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