X-Git-Url: http://these/git/?a=blobdiff_plain;f=crates%2Fapub%2Fsrc%2Factivities%2Ffollowing%2Ffollow.rs;h=2f0f5037aed69d6d3abed8572bb0a5afe2b68f1c;hb=e9e76549a88cfbdab36f00d302cceabcaaa24f4c;hp=21446eb1276e3c23342b680dea02e779fb036799;hpb=8708ad1b44e58dfbd8c555f9bc270daadbfa01af;p=lemmy.git diff --git a/crates/apub/src/activities/following/follow.rs b/crates/apub/src/activities/following/follow.rs index 21446eb1..2f0f5037 100644 --- a/crates/apub/src/activities/following/follow.rs +++ b/crates/apub/src/activities/following/follow.rs @@ -1,121 +1,145 @@ use crate::{ activities::{ - following::accept::AcceptFollowCommunity, generate_activity_id, - verify_activity, + send_lemmy_activity, verify_person, + verify_person_in_community, }, - activity_queue::send_activity_new, - extensions::context::lemmy_context, - fetcher::object_id::ObjectId, - ActorType, + fetcher::user_or_community::UserOrCommunity, + insert_received_activity, + objects::{community::ApubCommunity, person::ApubPerson}, + protocol::activities::following::{ + accept::AcceptFollow, + follow::Follow, + undo_follow::UndoFollow, + }, + SendActivity, +}; +use activitypub_federation::{ + config::Data, + kinds::activity::FollowType, + protocol::verification::verify_urls_match, + traits::{ActivityHandler, Actor}, }; -use activitystreams::{ - activity::kind::FollowType, - base::AnyBase, - primitives::OneOrMany, - unparsed::Unparsed, +use lemmy_api_common::{ + community::{BlockCommunity, BlockCommunityResponse}, + context::LemmyContext, + utils::local_user_view_from_jwt, }; -use lemmy_api_common::blocking; -use lemmy_apub_lib::{verify_urls_match, ActivityFields, ActivityHandler}; -use lemmy_db_queries::Followable; -use lemmy_db_schema::source::{ - community::{Community, CommunityFollower, CommunityFollowerForm}, - person::Person, +use lemmy_db_schema::{ + source::{ + community::{Community, CommunityFollower, CommunityFollowerForm}, + person::{PersonFollower, PersonFollowerForm}, + }, + traits::{Crud, Followable}, }; -use lemmy_utils::LemmyError; -use lemmy_websocket::LemmyContext; -use serde::{Deserialize, Serialize}; +use lemmy_utils::error::LemmyError; use url::Url; -#[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)] -#[serde(rename_all = "camelCase")] -pub struct FollowCommunity { - actor: ObjectId, - // TODO: is there any reason to put the same community id twice, in to and object? - pub(in crate::activities::following) to: ObjectId, - pub(in crate::activities::following) object: ObjectId, - #[serde(rename = "type")] - kind: FollowType, - id: Url, - #[serde(rename = "@context")] - context: OneOrMany, - #[serde(flatten)] - unparsed: Unparsed, -} - -impl FollowCommunity { +impl Follow { pub(in crate::activities::following) fn new( - actor: &Person, - community: &Community, - context: &LemmyContext, - ) -> Result { - Ok(FollowCommunity { - actor: ObjectId::new(actor.actor_id()), - to: ObjectId::new(community.actor_id()), - object: ObjectId::new(community.actor_id()), + actor: &ApubPerson, + community: &ApubCommunity, + context: &Data, + ) -> Result { + Ok(Follow { + actor: actor.id().into(), + object: community.id().into(), + to: Some([community.id().into()]), kind: FollowType::Follow, id: generate_activity_id( FollowType::Follow, &context.settings().get_protocol_and_hostname(), )?, - context: lemmy_context(), - unparsed: Default::default(), }) } + + #[tracing::instrument(skip_all)] pub async fn send( - actor: &Person, - community: &Community, - context: &LemmyContext, + actor: &ApubPerson, + community: &ApubCommunity, + context: &Data, ) -> Result<(), LemmyError> { let community_follower_form = CommunityFollowerForm { community_id: community.id, person_id: actor.id, pending: true, }; - blocking(context.pool(), move |conn| { - CommunityFollower::follow(conn, &community_follower_form).ok() - }) - .await?; + CommunityFollower::follow(&mut context.pool(), &community_follower_form) + .await + .ok(); - let follow = FollowCommunity::new(actor, community, context)?; - let inbox = vec![community.inbox_url.clone().into()]; - send_activity_new(context, &follow, &follow.id, actor, inbox, true).await + let follow = Follow::new(actor, community, context)?; + let inbox = vec![community.shared_inbox_or_inbox()]; + send_lemmy_activity(context, follow, actor, inbox, true).await } } -#[async_trait::async_trait(?Send)] -impl ActivityHandler for FollowCommunity { - async fn verify( - &self, - context: &LemmyContext, - request_counter: &mut i32, - ) -> Result<(), LemmyError> { - verify_activity(self, &context.settings())?; - verify_urls_match(self.to.inner(), self.object.inner())?; - verify_person(&self.actor, context, request_counter).await?; +#[async_trait::async_trait] +impl ActivityHandler for Follow { + type DataType = LemmyContext; + type Error = LemmyError; + + fn id(&self) -> &Url { + &self.id + } + + fn actor(&self) -> &Url { + self.actor.inner() + } + + #[tracing::instrument(skip_all)] + async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + insert_received_activity(&self.id, context).await?; + verify_person(&self.actor, context).await?; + let object = self.object.dereference(context).await?; + if let UserOrCommunity::Community(c) = object { + verify_person_in_community(&self.actor, &c, context).await?; + } + if let Some(to) = &self.to { + verify_urls_match(to[0].inner(), self.object.inner())?; + } Ok(()) } - async fn receive( - self, - context: &LemmyContext, - request_counter: &mut i32, - ) -> Result<(), LemmyError> { - let actor = self.actor.dereference(context, request_counter).await?; - let community = self.object.dereference(context, request_counter).await?; - let community_follower_form = CommunityFollowerForm { - community_id: community.id, - person_id: actor.id, - pending: false, - }; + #[tracing::instrument(skip_all)] + async fn receive(self, context: &Data) -> Result<(), LemmyError> { + let actor = self.actor.dereference(context).await?; + let object = self.object.dereference(context).await?; + match object { + UserOrCommunity::User(u) => { + let form = PersonFollowerForm { + person_id: u.id, + follower_id: actor.id, + pending: false, + }; + PersonFollower::follow(&mut context.pool(), &form).await?; + } + UserOrCommunity::Community(c) => { + let form = CommunityFollowerForm { + community_id: c.id, + person_id: actor.id, + pending: false, + }; + CommunityFollower::follow(&mut context.pool(), &form).await?; + } + } - // This will fail if they're already a follower, but ignore the error. - blocking(context.pool(), move |conn| { - CommunityFollower::follow(conn, &community_follower_form).ok() - }) - .await?; + AcceptFollow::send(self, context).await + } +} - AcceptFollowCommunity::send(self, context).await +#[async_trait::async_trait] +impl SendActivity for BlockCommunity { + type Response = BlockCommunityResponse; + + 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 community = Community::read(&mut context.pool(), request.community_id).await?; + UndoFollow::send(&local_user_view.person.into(), &community.into(), context).await } }