Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 5 additions & 47 deletions crates/api/api/src/community/follow.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
use crate::community::do_follow_community;
use activitypub_federation::config::Data;
use actix_web::web::Json;
use lemmy_api_utils::{
context::LemmyContext,
send_activity::{ActivityChannel, SendActivityData},
utils::{check_community_deleted_removed, check_local_user_valid},
};
use lemmy_api_utils::{context::LemmyContext, utils::check_local_user_valid};
use lemmy_db_schema::{
source::{
actor_language::CommunityLanguage,
community::{Community, CommunityActions, CommunityFollowerForm},
},
traits::{Crud, Followable},
source::{actor_language::CommunityLanguage, community::Community},
traits::Crud,
};
use lemmy_db_schema_file::enums::{CommunityFollowerState, CommunityVisibility};
use lemmy_db_views_community::{
api::{CommunityResponse, FollowCommunity},
CommunityView,
};
use lemmy_db_views_community_person_ban::CommunityPersonBanView;
use lemmy_db_views_local_user::LocalUserView;
use lemmy_utils::error::LemmyResult;

Expand All @@ -29,42 +21,8 @@ pub async fn follow_community(
check_local_user_valid(&local_user_view)?;
let community_id = data.community_id;
let community = Community::read(&mut context.pool(), community_id).await?;
let person_id = local_user_view.person.id;

if data.follow {
// Only run these checks for local community, in case of remote community the local
// state may be outdated. Can't use check_community_user_action() here as it only allows
// actions from existing followers for private community (so following would be impossible).
if community.local {
check_community_deleted_removed(&community)?;
CommunityPersonBanView::check(&mut context.pool(), person_id, community_id).await?;
}

let follow_state = if community.visibility == CommunityVisibility::Private {
// Private communities require manual approval
CommunityFollowerState::ApprovalRequired
} else if community.local {
// Local follow is accepted immediately
CommunityFollowerState::Accepted
} else {
// remote follow needs to be federated first
CommunityFollowerState::Pending
};
let form = CommunityFollowerForm::new(community_id, person_id, follow_state);

// Write to db
CommunityActions::follow(&mut context.pool(), &form).await?;
} else {
CommunityActions::unfollow(&mut context.pool(), person_id, community_id).await?;
}

// Send the federated follow
if !community.local {
ActivityChannel::submit_activity(
SendActivityData::FollowCommunity(community, local_user_view.person.clone(), data.follow),
&context,
)?;
}
do_follow_community(community, &local_user_view.person, data.follow, &context).await?;

let community_view = CommunityView::read(
&mut context.pool(),
Expand Down
60 changes: 60 additions & 0 deletions crates/api/api/src/community/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
use activitypub_federation::config::Data;
use lemmy_api_utils::{
context::LemmyContext,
send_activity::{ActivityChannel, SendActivityData},
utils::check_community_deleted_removed,
};
use lemmy_db_schema::{
source::{
community::{Community, CommunityActions, CommunityFollowerForm},
person::Person,
},
traits::Followable,
};
use lemmy_db_schema_file::enums::{CommunityFollowerState, CommunityVisibility};
use lemmy_db_views_community_person_ban::CommunityPersonBanView;
use lemmy_utils::error::LemmyResult;

pub mod add_mod;
pub mod ban;
pub mod block;
Expand All @@ -8,3 +25,46 @@ pub mod random;
pub mod tag;
pub mod transfer;
pub mod update_notifications;

pub(super) async fn do_follow_community(
community: Community,
person: &Person,
follow: bool,
context: &Data<LemmyContext>,
Comment on lines +29 to +33
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would probably be a good idea to pass in &Community, even if you do have to do a clone later. Up to you tho.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its not necessary as the callers dont use community anymore.

) -> LemmyResult<()> {
if follow {
// Only run these checks for local community, in case of remote community the local
// state may be outdated. Can't use check_community_user_action() here as it only allows
// actions from existing followers for private community (so following would be impossible).
if community.local {
check_community_deleted_removed(&community)?;
CommunityPersonBanView::check(&mut context.pool(), person.id, community.id).await?;
}

let follow_state = if community.visibility == CommunityVisibility::Private {
// Private communities require manual approval
CommunityFollowerState::ApprovalRequired
} else if community.local {
// Local follow is accepted immediately
CommunityFollowerState::Accepted
} else {
// remote follow needs to be federated first
CommunityFollowerState::Pending
};
let form = CommunityFollowerForm::new(community.id, person.id, follow_state);

// Write to db
CommunityActions::follow(&mut context.pool(), &form).await?;
} else {
CommunityActions::unfollow(&mut context.pool(), person.id, community.id).await?;
}

// Send the federated follow
if !community.local {
ActivityChannel::submit_activity(
SendActivityData::FollowCommunity(community, person.clone(), follow),
context,
)?;
}
Ok(())
}
19 changes: 18 additions & 1 deletion crates/api/api/src/community/update_notifications.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
use crate::community::do_follow_community;
use activitypub_federation::config::Data;
use actix_web::web::Json;
use lemmy_api_utils::context::LemmyContext;
use lemmy_db_schema::source::community::CommunityActions;
use lemmy_db_schema::{
source::community::{Community, CommunityActions},
traits::Crud,
};
use lemmy_db_schema_file::enums::CommunityNotificationsMode;
use lemmy_db_views_community::api::UpdateCommunityNotifications;
use lemmy_db_views_local_user::LocalUserView;
use lemmy_db_views_site::api::SuccessResponse;
Expand All @@ -19,5 +24,17 @@ pub async fn update_community_notifications(
&mut context.pool(),
)
.await?;

// To get notifications for a remote community, the user needs to follow it over federation.
// Do this automatically here to avoid confusion.
if data.mode == CommunityNotificationsMode::AllPostsAndComments
|| data.mode == CommunityNotificationsMode::AllPosts
{
let community = Community::read(&mut context.pool(), data.community_id).await?;
if !community.local {
do_follow_community(community, &local_user_view.person, true, &context).await?;
}
}

Ok(Json(SuccessResponse::default()))
}
20 changes: 19 additions & 1 deletion crates/api/api/src/post/update_notifications.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
use crate::community::do_follow_community;
use activitypub_federation::config::Data;
use actix_web::web::Json;
use lemmy_api_utils::context::LemmyContext;
use lemmy_db_schema::source::post::PostActions;
use lemmy_db_schema::{
source::{
community::Community,
post::{Post, PostActions},
},
traits::Crud,
};
use lemmy_db_schema_file::enums::PostNotificationsMode;
use lemmy_db_views_local_user::LocalUserView;
use lemmy_db_views_post::api::UpdatePostNotifications;
use lemmy_db_views_site::api::SuccessResponse;
Expand All @@ -19,5 +27,15 @@ pub async fn update_post_notifications(
&mut context.pool(),
)
.await?;
let post = Post::read(&mut context.pool(), data.post_id).await?;

// To get notifications for a remote community, the user needs to follow it over federation.
// Do this automatically here to avoid confusion.
if data.mode == PostNotificationsMode::AllComments {
let community = Community::read(&mut context.pool(), post.community_id).await?;
if !community.local {
do_follow_community(community, &local_user_view.person, true, &context).await?;
}
}
Ok(Json(SuccessResponse::default()))
}