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