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