]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/following/follow.rs
41d2e71ed7beffa4d29ce1eaa6792df30e4c5147
[lemmy.git] / crates / apub / src / activities / following / follow.rs
1 use crate::{
2   activities::{
3     generate_activity_id,
4     send_lemmy_activity,
5     verify_person,
6     verify_person_in_community,
7   },
8   fetcher::user_or_community::UserOrCommunity,
9   insert_activity,
10   objects::{community::ApubCommunity, person::ApubPerson},
11   protocol::activities::following::{
12     accept::AcceptFollow,
13     follow::Follow,
14     undo_follow::UndoFollow,
15   },
16   SendActivity,
17 };
18 use activitypub_federation::{
19   config::Data,
20   kinds::activity::FollowType,
21   traits::{ActivityHandler, Actor},
22 };
23 use lemmy_api_common::{
24   community::{BlockCommunity, BlockCommunityResponse},
25   context::LemmyContext,
26   utils::get_local_user_view_from_jwt,
27 };
28 use lemmy_db_schema::{
29   source::{
30     community::{Community, CommunityFollower, CommunityFollowerForm},
31     person::{PersonFollower, PersonFollowerForm},
32   },
33   traits::{Crud, Followable},
34 };
35 use lemmy_utils::error::LemmyError;
36 use url::Url;
37
38 impl Follow {
39   pub(in crate::activities::following) fn new(
40     actor: &ApubPerson,
41     community: &ApubCommunity,
42     context: &Data<LemmyContext>,
43   ) -> Result<Follow, LemmyError> {
44     Ok(Follow {
45       actor: actor.id().into(),
46       object: community.id().into(),
47       kind: FollowType::Follow,
48       id: generate_activity_id(
49         FollowType::Follow,
50         &context.settings().get_protocol_and_hostname(),
51       )?,
52     })
53   }
54
55   #[tracing::instrument(skip_all)]
56   pub async fn send(
57     actor: &ApubPerson,
58     community: &ApubCommunity,
59     context: &Data<LemmyContext>,
60   ) -> Result<(), LemmyError> {
61     let community_follower_form = CommunityFollowerForm {
62       community_id: community.id,
63       person_id: actor.id,
64       pending: true,
65     };
66     CommunityFollower::follow(context.pool(), &community_follower_form)
67       .await
68       .ok();
69
70     let follow = Follow::new(actor, community, context)?;
71     let inbox = vec![community.shared_inbox_or_inbox()];
72     send_lemmy_activity(context, follow, actor, inbox, true).await
73   }
74 }
75
76 #[async_trait::async_trait]
77 impl ActivityHandler for Follow {
78   type DataType = LemmyContext;
79   type Error = LemmyError;
80
81   fn id(&self) -> &Url {
82     &self.id
83   }
84
85   fn actor(&self) -> &Url {
86     self.actor.inner()
87   }
88
89   #[tracing::instrument(skip_all)]
90   async fn verify(&self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
91     verify_person(&self.actor, context).await?;
92     let object = self.object.dereference(context).await?;
93     if let UserOrCommunity::Community(c) = object {
94       verify_person_in_community(&self.actor, &c, context).await?;
95     }
96     Ok(())
97   }
98
99   #[tracing::instrument(skip_all)]
100   async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {
101     insert_activity(&self.id, &self, false, true, context).await?;
102     let actor = self.actor.dereference(context).await?;
103     let object = self.object.dereference(context).await?;
104     match object {
105       UserOrCommunity::User(u) => {
106         let form = PersonFollowerForm {
107           person_id: u.id,
108           follower_id: actor.id,
109           pending: false,
110         };
111         PersonFollower::follow(context.pool(), &form).await?;
112       }
113       UserOrCommunity::Community(c) => {
114         let form = CommunityFollowerForm {
115           community_id: c.id,
116           person_id: actor.id,
117           pending: false,
118         };
119         CommunityFollower::follow(context.pool(), &form).await?;
120       }
121     }
122
123     AcceptFollow::send(self, context).await
124   }
125 }
126
127 #[async_trait::async_trait]
128 impl SendActivity for BlockCommunity {
129   type Response = BlockCommunityResponse;
130
131   async fn send_activity(
132     request: &Self,
133     _response: &Self::Response,
134     context: &Data<LemmyContext>,
135   ) -> Result<(), LemmyError> {
136     let local_user_view =
137       get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
138     let community = Community::read(context.pool(), request.community_id).await?;
139     UndoFollow::send(&local_user_view.person.into(), &community.into(), context).await
140   }
141 }