diff --git a/crates/api/src/community/follow.rs b/crates/api/src/community/follow.rs index a2f46eb75..8fea2625d 100644 --- a/crates/api/src/community/follow.rs +++ b/crates/api/src/community/follow.rs @@ -1,8 +1,9 @@ -use crate::Perform; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ community::{CommunityResponse, FollowCommunity}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{check_community_ban, check_community_deleted_or_removed, local_user_view_from_jwt}, }; use lemmy_db_schema::{ @@ -15,54 +16,56 @@ use lemmy_db_schema::{ use lemmy_db_views_actor::structs::CommunityView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for FollowCommunity { - type Response = CommunityResponse; +#[tracing::instrument(skip(context))] +pub async fn follow_community( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &FollowCommunity = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let community = Community::read(&mut context.pool(), data.community_id).await?; + let mut community_follower_form = CommunityFollowerForm { + community_id: community.id, + person_id: local_user_view.person.id, + pending: false, + }; - let community_id = data.community_id; - let community = Community::read(&mut context.pool(), community_id).await?; - let mut community_follower_form = CommunityFollowerForm { - community_id: data.community_id, - person_id: local_user_view.person.id, - pending: false, - }; + if data.follow { + if community.local { + check_community_ban(local_user_view.person.id, community.id, &mut context.pool()).await?; + check_community_deleted_or_removed(community.id, &mut context.pool()).await?; - if data.follow { - if community.local { - check_community_ban(local_user_view.person.id, community_id, &mut context.pool()).await?; - check_community_deleted_or_removed(community_id, &mut context.pool()).await?; - - CommunityFollower::follow(&mut context.pool(), &community_follower_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?; - } else { - // Mark as pending, the actual federation activity is sent via `SendActivity` handler - community_follower_form.pending = true; - CommunityFollower::follow(&mut context.pool(), &community_follower_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?; - } - } - if !data.follow { - CommunityFollower::unfollow(&mut context.pool(), &community_follower_form) + CommunityFollower::follow(&mut context.pool(), &community_follower_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?; + } else { + // Mark as pending, the actual federation activity is sent via `SendActivity` handler + community_follower_form.pending = true; + CommunityFollower::follow(&mut context.pool(), &community_follower_form) .await .with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?; } - - let community_id = data.community_id; - let person_id = local_user_view.person.id; - let community_view = - CommunityView::read(&mut context.pool(), community_id, Some(person_id), None).await?; - let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?; - - Ok(Self::Response { - community_view, - discussion_languages, - }) } + if !data.follow { + CommunityFollower::unfollow(&mut context.pool(), &community_follower_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?; + } + + ActivityChannel::submit_activity( + SendActivityData::FollowCommunity(community, local_user_view.person.clone(), data.follow), + &context, + ) + .await?; + + let community_id = data.community_id; + let person_id = local_user_view.person.id; + let community_view = + CommunityView::read(&mut context.pool(), community_id, Some(person_id), None).await?; + let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?; + + Ok(Json(CommunityResponse { + community_view, + discussion_languages, + })) } diff --git a/crates/api/src/community/mod.rs b/crates/api/src/community/mod.rs index fda082657..fc3ef67c5 100644 --- a/crates/api/src/community/mod.rs +++ b/crates/api/src/community/mod.rs @@ -1,6 +1,6 @@ mod add_mod; mod ban; mod block; -mod follow; +pub mod follow; mod hide; mod transfer; diff --git a/crates/api_common/src/send_activity.rs b/crates/api_common/src/send_activity.rs index 7954db284..8580c2175 100644 --- a/crates/api_common/src/send_activity.rs +++ b/crates/api_common/src/send_activity.rs @@ -31,6 +31,7 @@ pub enum SendActivityData { RemoveComment(Comment, Person, Community, Option), UpdateComment(Comment), LikePostOrComment(DbUrl, Person, Community, i16), + FollowCommunity(Community, Person, bool), } // TODO: instead of static, move this into LemmyContext. make sure that stopping the process with diff --git a/crates/apub/src/activities/following/mod.rs b/crates/apub/src/activities/following/mod.rs index 06f95e3f4..c4f0bd0b7 100644 --- a/crates/apub/src/activities/following/mod.rs +++ b/crates/apub/src/activities/following/mod.rs @@ -1,41 +1,27 @@ use crate::{ - objects::community::ApubCommunity, + objects::{community::ApubCommunity, person::ApubPerson}, protocol::activities::following::{follow::Follow, undo_follow::UndoFollow}, - SendActivity, }; use activitypub_federation::config::Data; -use lemmy_api_common::{ - community::{CommunityResponse, FollowCommunity}, - context::LemmyContext, - utils::local_user_view_from_jwt, -}; -use lemmy_db_schema::{source::community::Community, traits::Crud}; +use lemmy_api_common::context::LemmyContext; +use lemmy_db_schema::source::{community::Community, person::Person}; use lemmy_utils::error::LemmyError; pub mod accept; pub mod follow; pub mod undo_follow; -#[async_trait::async_trait] -impl SendActivity for FollowCommunity { - type Response = CommunityResponse; - - async fn send_activity( - request: &Self, - _response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - let local_user_view = local_user_view_from_jwt(&request.auth, context).await?; - let person = local_user_view.person.clone().into(); - let community: ApubCommunity = Community::read(&mut context.pool(), request.community_id) - .await? - .into(); - if community.local { - Ok(()) - } else if request.follow { - Follow::send(&person, &community, context).await - } else { - UndoFollow::send(&person, &community, context).await - } +pub async fn send_follow_community( + community: Community, + person: Person, + follow: bool, + context: &Data, +) -> Result<(), LemmyError> { + let community: ApubCommunity = community.into(); + let actor: ApubPerson = person.into(); + if follow { + Follow::send(&actor, &community, context).await + } else { + UndoFollow::send(&actor, &community, context).await } } diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index c577f8bc9..780755766 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -1,3 +1,4 @@ +use self::following::send_follow_community; use crate::{ activities::{ deletion::{send_apub_delete_in_community, DeletableObjects}, @@ -250,6 +251,9 @@ pub async fn match_outgoing_activities( LikePostOrComment(object_id, person, community, score) => { send_like_activity(object_id, person, community, score, context).await } + SendActivityData::FollowCommunity(community, person, follow) => { + send_follow_community(community, person, follow, &context).await + } } }; if *SYNCHRONOUS_FEDERATION { diff --git a/src/api_routes_http.rs b/src/api_routes_http.rs index 6d538e63e..dccf18dd4 100644 --- a/src/api_routes_http.rs +++ b/src/api_routes_http.rs @@ -2,6 +2,7 @@ use actix_web::{guard, web, Error, HttpResponse, Result}; use lemmy_api::{ comment::{distinguish::distinguish_comment, like::like_comment, save::save_comment}, comment_report::{list::list_comment_reports, resolve::resolve_comment_report}, + community::follow::follow_community, local_user::notifications::mark_reply_read::mark_reply_as_read, post::like::like_post, Perform, @@ -15,7 +16,6 @@ use lemmy_api_common::{ CreateCommunity, DeleteCommunity, EditCommunity, - FollowCommunity, HideCommunity, RemoveCommunity, TransferCommunity, @@ -146,7 +146,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .route("", web::put().to(route_post_crud::)) .route("/hide", web::put().to(route_post::)) .route("/list", web::get().to(list_communities)) - .route("/follow", web::post().to(route_post::)) + .route("/follow", web::post().to(follow_community)) .route("/block", web::post().to(route_post::)) .route( "/delete",