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