]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/following/accept.rs
Merge branch 'remove_settings_and_secret_singletons_squashed'
[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::object_id::ObjectId,
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: ObjectId<Community>,
35   to: ObjectId<Person>,
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: ObjectId::new(community.actor_id()),
61       to: ObjectId::new(person.actor_id()),
62       object: follow,
63       kind: AcceptType::Accept,
64       id: generate_activity_id(
65         AcceptType::Accept,
66         &context.settings().get_protocol_and_hostname(),
67       )?,
68       context: lemmy_context(),
69       unparsed: Default::default(),
70     };
71     let inbox = vec![person.inbox_url.into()];
72     send_activity_new(context, &accept, &accept.id, &community, inbox, true).await
73   }
74 }
75 /// Handle accepted follows
76 #[async_trait::async_trait(?Send)]
77 impl ActivityHandler for AcceptFollowCommunity {
78   async fn verify(
79     &self,
80     context: &LemmyContext,
81     request_counter: &mut i32,
82   ) -> Result<(), LemmyError> {
83     verify_activity(self, &context.settings())?;
84     verify_urls_match(self.to.inner(), self.object.actor())?;
85     verify_urls_match(self.actor(), self.object.to.inner())?;
86     verify_community(&self.actor, context, request_counter).await?;
87     self.object.verify(context, request_counter).await?;
88     Ok(())
89   }
90
91   async fn receive(
92     self,
93     context: &LemmyContext,
94     request_counter: &mut i32,
95   ) -> Result<(), LemmyError> {
96     let actor = self.actor.dereference(context, request_counter).await?;
97     let to = self.to.dereference(context, request_counter).await?;
98     // This will throw an error if no follow was requested
99     blocking(context.pool(), move |conn| {
100       CommunityFollower::follow_accepted(conn, actor.id, to.id)
101     })
102     .await??;
103
104     Ok(())
105   }
106 }