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