]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/following/follow.rs
Add cargo feature for building lemmy_api_common with mininum deps (#2243)
[lemmy.git] / crates / apub / src / activities / following / follow.rs
1 use crate::{
2   activities::{
3     generate_activity_id,
4     send_lemmy_activity,
5     verify_activity,
6     verify_person,
7     verify_person_in_community,
8   },
9   objects::{community::ApubCommunity, person::ApubPerson},
10   protocol::activities::following::{accept::AcceptFollowCommunity, follow::FollowCommunity},
11 };
12 use activitystreams_kinds::activity::FollowType;
13 use lemmy_api_common::utils::blocking;
14 use lemmy_apub_lib::{
15   data::Data,
16   object_id::ObjectId,
17   traits::{ActivityHandler, ActorType},
18 };
19 use lemmy_db_schema::{
20   source::community::{CommunityFollower, CommunityFollowerForm},
21   traits::Followable,
22 };
23 use lemmy_utils::LemmyError;
24 use lemmy_websocket::LemmyContext;
25
26 impl FollowCommunity {
27   pub(in crate::activities::following) fn new(
28     actor: &ApubPerson,
29     community: &ApubCommunity,
30     context: &LemmyContext,
31   ) -> Result<FollowCommunity, LemmyError> {
32     Ok(FollowCommunity {
33       actor: ObjectId::new(actor.actor_id()),
34       object: ObjectId::new(community.actor_id()),
35       kind: FollowType::Follow,
36       id: generate_activity_id(
37         FollowType::Follow,
38         &context.settings().get_protocol_and_hostname(),
39       )?,
40       unparsed: Default::default(),
41     })
42   }
43
44   #[tracing::instrument(skip_all)]
45   pub async fn send(
46     actor: &ApubPerson,
47     community: &ApubCommunity,
48     context: &LemmyContext,
49   ) -> Result<(), LemmyError> {
50     let community_follower_form = CommunityFollowerForm {
51       community_id: community.id,
52       person_id: actor.id,
53       pending: true,
54     };
55     blocking(context.pool(), move |conn| {
56       CommunityFollower::follow(conn, &community_follower_form).ok()
57     })
58     .await?;
59
60     let follow = FollowCommunity::new(actor, community, context)?;
61     let inbox = vec![community.inbox_url.clone().into()];
62     send_lemmy_activity(context, &follow, &follow.id, actor, inbox, true).await
63   }
64 }
65
66 #[async_trait::async_trait(?Send)]
67 impl ActivityHandler for FollowCommunity {
68   type DataType = LemmyContext;
69
70   #[tracing::instrument(skip_all)]
71   async fn verify(
72     &self,
73     context: &Data<LemmyContext>,
74     request_counter: &mut i32,
75   ) -> Result<(), LemmyError> {
76     verify_activity(&self.id, self.actor.inner(), &context.settings())?;
77     verify_person(&self.actor, context, request_counter).await?;
78     let community = self
79       .object
80       .dereference(context, context.client(), request_counter)
81       .await?;
82     verify_person_in_community(&self.actor, &community, context, request_counter).await?;
83     Ok(())
84   }
85
86   #[tracing::instrument(skip_all)]
87   async fn receive(
88     self,
89     context: &Data<LemmyContext>,
90     request_counter: &mut i32,
91   ) -> Result<(), LemmyError> {
92     let person = self
93       .actor
94       .dereference(context, context.client(), request_counter)
95       .await?;
96     let community = self
97       .object
98       .dereference(context, context.client(), request_counter)
99       .await?;
100     let community_follower_form = CommunityFollowerForm {
101       community_id: community.id,
102       person_id: person.id,
103       pending: false,
104     };
105
106     // This will fail if they're already a follower, but ignore the error.
107     blocking(context.pool(), move |conn| {
108       CommunityFollower::follow(conn, &community_follower_form).ok()
109     })
110     .await?;
111
112     AcceptFollowCommunity::send(self, context, request_counter).await
113   }
114 }