]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/following/follow.rs
Moving settings and secrets to context.
[lemmy.git] / crates / apub / src / activities / following / follow.rs
1 use crate::{
2   activities::{
3     following::accept::AcceptFollowCommunity,
4     generate_activity_id,
5     verify_activity,
6     verify_person,
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::FollowType,
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::Followable;
22 use lemmy_db_schema::source::{
23   community::{Community, CommunityFollower, CommunityFollowerForm},
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 FollowCommunity {
34   actor: ObjectId<Person>,
35   // TODO: is there any reason to put the same community id twice, in to and object?
36   pub(in crate::activities::following) to: ObjectId<Community>,
37   pub(in crate::activities::following) object: ObjectId<Community>,
38   #[serde(rename = "type")]
39   kind: FollowType,
40   id: Url,
41   #[serde(rename = "@context")]
42   context: OneOrMany<AnyBase>,
43   #[serde(flatten)]
44   unparsed: Unparsed,
45 }
46
47 impl FollowCommunity {
48   pub(in crate::activities::following) fn new(
49     actor: &Person,
50     community: &Community,
51     context: &LemmyContext,
52   ) -> Result<FollowCommunity, LemmyError> {
53     Ok(FollowCommunity {
54       actor: ObjectId::new(actor.actor_id()),
55       to: ObjectId::new(community.actor_id()),
56       object: ObjectId::new(community.actor_id()),
57       kind: FollowType::Follow,
58       id: generate_activity_id(
59         FollowType::Follow,
60         &context.settings().get_protocol_and_hostname(),
61       )?,
62       context: lemmy_context(),
63       unparsed: Default::default(),
64     })
65   }
66   pub async fn send(
67     actor: &Person,
68     community: &Community,
69     context: &LemmyContext,
70   ) -> Result<(), LemmyError> {
71     let community_follower_form = CommunityFollowerForm {
72       community_id: community.id,
73       person_id: actor.id,
74       pending: true,
75     };
76     blocking(context.pool(), move |conn| {
77       CommunityFollower::follow(conn, &community_follower_form).ok()
78     })
79     .await?;
80
81     let follow = FollowCommunity::new(actor, community, context)?;
82     let inbox = vec![community.inbox_url.clone().into()];
83     send_activity_new(context, &follow, &follow.id, actor, inbox, true).await
84   }
85 }
86
87 #[async_trait::async_trait(?Send)]
88 impl ActivityHandler for FollowCommunity {
89   async fn verify(
90     &self,
91     context: &LemmyContext,
92     request_counter: &mut i32,
93   ) -> Result<(), LemmyError> {
94     verify_activity(self, &context.settings())?;
95     verify_urls_match(self.to.inner(), self.object.inner())?;
96     verify_person(&self.actor, context, request_counter).await?;
97     Ok(())
98   }
99
100   async fn receive(
101     self,
102     context: &LemmyContext,
103     request_counter: &mut i32,
104   ) -> Result<(), LemmyError> {
105     let actor = self.actor.dereference(context, request_counter).await?;
106     let community = self.object.dereference(context, request_counter).await?;
107     let community_follower_form = CommunityFollowerForm {
108       community_id: community.id,
109       person_id: actor.id,
110       pending: false,
111     };
112
113     // This will fail if they're already a follower, but ignore the error.
114     blocking(context.pool(), move |conn| {
115       CommunityFollower::follow(conn, &community_follower_form).ok()
116     })
117     .await?;
118
119     AcceptFollowCommunity::send(self, context).await
120   }
121 }