]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/following/accept.rs
Extract Activitypub logic into separate library (#2288)
[lemmy.git] / crates / apub / src / activities / following / accept.rs
1 use crate::{
2   activities::{generate_activity_id, send_lemmy_activity},
3   local_instance,
4   protocol::activities::following::{accept::AcceptFollowCommunity, follow::FollowCommunity},
5   ActorType,
6 };
7 use activitypub_federation::{
8   core::object_id::ObjectId,
9   data::Data,
10   traits::ActivityHandler,
11   utils::verify_urls_match,
12 };
13 use activitystreams_kinds::activity::AcceptType;
14 use lemmy_api_common::utils::blocking;
15 use lemmy_db_schema::{source::community::CommunityFollower, traits::Followable};
16 use lemmy_utils::error::LemmyError;
17 use lemmy_websocket::LemmyContext;
18 use url::Url;
19
20 impl AcceptFollowCommunity {
21   #[tracing::instrument(skip_all)]
22   pub async fn send(
23     follow: FollowCommunity,
24     context: &LemmyContext,
25     request_counter: &mut i32,
26   ) -> Result<(), LemmyError> {
27     let community = follow
28       .object
29       .dereference_local::<LemmyError>(context)
30       .await?;
31     let person = follow
32       .actor
33       .clone()
34       .dereference::<LemmyError>(context, local_instance(context), request_counter)
35       .await?;
36     let accept = AcceptFollowCommunity {
37       actor: ObjectId::new(community.actor_id()),
38       object: follow,
39       kind: AcceptType::Accept,
40       id: generate_activity_id(
41         AcceptType::Accept,
42         &context.settings().get_protocol_and_hostname(),
43       )?,
44       unparsed: Default::default(),
45     };
46     let inbox = vec![person.inbox_url()];
47     send_lemmy_activity(context, &accept, &accept.id, &community, inbox, true).await
48   }
49 }
50
51 /// Handle accepted follows
52 #[async_trait::async_trait(?Send)]
53 impl ActivityHandler for AcceptFollowCommunity {
54   type DataType = LemmyContext;
55   type Error = LemmyError;
56
57   fn id(&self) -> &Url {
58     &self.id
59   }
60
61   fn actor(&self) -> &Url {
62     self.actor.inner()
63   }
64
65   #[tracing::instrument(skip_all)]
66   async fn verify(
67     &self,
68     context: &Data<LemmyContext>,
69     request_counter: &mut i32,
70   ) -> Result<(), LemmyError> {
71     verify_urls_match(self.actor.inner(), self.object.object.inner())?;
72     self.object.verify(context, request_counter).await?;
73     Ok(())
74   }
75
76   #[tracing::instrument(skip_all)]
77   async fn receive(
78     self,
79     context: &Data<LemmyContext>,
80     request_counter: &mut i32,
81   ) -> Result<(), LemmyError> {
82     let person = self
83       .actor
84       .dereference::<LemmyError>(context, local_instance(context), request_counter)
85       .await?;
86     let community = self
87       .object
88       .actor
89       .dereference::<LemmyError>(context, local_instance(context), request_counter)
90       .await?;
91     // This will throw an error if no follow was requested
92     blocking(context.pool(), move |conn| {
93       CommunityFollower::follow_accepted(conn, person.id, community.id)
94     })
95     .await??;
96
97     Ok(())
98   }
99 }