]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/send/community.rs
Refactor activitypub code
[lemmy.git] / crates / apub / src / activities / send / community.rs
1 use crate::{
2   activities::send::generate_activity_id,
3   activity_queue::{send_activity_single_dest, send_to_community, send_to_community_followers},
4   check_is_apub_id_valid,
5   extensions::context::lemmy_context,
6   fetcher::user::get_or_fetch_and_upsert_user,
7   generate_moderators_url,
8   ActorType,
9   CommunityType,
10 };
11 use activitystreams::{
12   activity::{
13     kind::{AcceptType, AddType, AnnounceType, DeleteType, LikeType, RemoveType, UndoType},
14     Accept,
15     ActorAndObjectRefExt,
16     Add,
17     Announce,
18     Delete,
19     Follow,
20     OptTargetRefExt,
21     Remove,
22     Undo,
23   },
24   base::{AnyBase, BaseExt, ExtendsExt},
25   object::ObjectExt,
26   public,
27 };
28 use anyhow::Context;
29 use itertools::Itertools;
30 use lemmy_api_structs::blocking;
31 use lemmy_db_queries::DbPool;
32 use lemmy_db_schema::source::{community::Community, user::User_};
33 use lemmy_db_views_actor::community_follower_view::CommunityFollowerView;
34 use lemmy_utils::{location_info, LemmyError};
35 use lemmy_websocket::LemmyContext;
36 use url::Url;
37
38 #[async_trait::async_trait(?Send)]
39 impl ActorType for Community {
40   fn is_local(&self) -> bool {
41     self.local
42   }
43   fn actor_id(&self) -> Url {
44     self.actor_id.to_owned().into_inner()
45   }
46   fn public_key(&self) -> Option<String> {
47     self.public_key.to_owned()
48   }
49   fn private_key(&self) -> Option<String> {
50     self.private_key.to_owned()
51   }
52
53   fn get_shared_inbox_or_inbox_url(&self) -> Url {
54     self
55       .shared_inbox_url
56       .clone()
57       .unwrap_or_else(|| self.inbox_url.to_owned())
58       .into()
59   }
60 }
61
62 #[async_trait::async_trait(?Send)]
63 impl CommunityType for Community {
64   /// As a local community, accept the follow request from a remote user.
65   async fn send_accept_follow(
66     &self,
67     follow: Follow,
68     context: &LemmyContext,
69   ) -> Result<(), LemmyError> {
70     let actor_uri = follow
71       .actor()?
72       .as_single_xsd_any_uri()
73       .context(location_info!())?;
74     let user = get_or_fetch_and_upsert_user(actor_uri, context, &mut 0).await?;
75
76     let mut accept = Accept::new(
77       self.actor_id.to_owned().into_inner(),
78       follow.into_any_base()?,
79     );
80     accept
81       .set_many_contexts(lemmy_context()?)
82       .set_id(generate_activity_id(AcceptType::Accept)?)
83       .set_to(user.actor_id());
84
85     send_activity_single_dest(accept, self, user.inbox_url.into(), context).await?;
86     Ok(())
87   }
88
89   /// If the creator of a community deletes the community, send this to all followers.
90   async fn send_delete(&self, context: &LemmyContext) -> Result<(), LemmyError> {
91     let mut delete = Delete::new(self.actor_id(), self.actor_id());
92     delete
93       .set_many_contexts(lemmy_context()?)
94       .set_id(generate_activity_id(DeleteType::Delete)?)
95       .set_to(public())
96       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
97
98     send_to_community_followers(delete, self, context).await?;
99     Ok(())
100   }
101
102   /// If the creator of a community reverts the deletion of a community, send this to all followers.
103   async fn send_undo_delete(&self, context: &LemmyContext) -> Result<(), LemmyError> {
104     let mut delete = Delete::new(self.actor_id(), self.actor_id());
105     delete
106       .set_many_contexts(lemmy_context()?)
107       .set_id(generate_activity_id(DeleteType::Delete)?)
108       .set_to(public())
109       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
110
111     let mut undo = Undo::new(self.actor_id(), delete.into_any_base()?);
112     undo
113       .set_many_contexts(lemmy_context()?)
114       .set_id(generate_activity_id(UndoType::Undo)?)
115       .set_to(public())
116       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
117
118     send_to_community_followers(undo, self, context).await?;
119     Ok(())
120   }
121
122   /// If an admin removes a community, send this to all followers.
123   async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
124     let mut remove = Remove::new(self.actor_id(), self.actor_id());
125     remove
126       .set_many_contexts(lemmy_context()?)
127       .set_id(generate_activity_id(RemoveType::Remove)?)
128       .set_to(public())
129       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
130
131     send_to_community_followers(remove, self, context).await?;
132     Ok(())
133   }
134
135   /// If an admin reverts the removal of a community, send this to all followers.
136   async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
137     let mut remove = Remove::new(self.actor_id(), self.actor_id());
138     remove
139       .set_many_contexts(lemmy_context()?)
140       .set_id(generate_activity_id(RemoveType::Remove)?)
141       .set_to(public())
142       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
143
144     // Undo that fake activity
145     let mut undo = Undo::new(self.actor_id(), remove.into_any_base()?);
146     undo
147       .set_many_contexts(lemmy_context()?)
148       .set_id(generate_activity_id(LikeType::Like)?)
149       .set_to(public())
150       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
151
152     send_to_community_followers(undo, self, context).await?;
153     Ok(())
154   }
155
156   /// Wraps an activity sent to the community in an announce, and then sends the announce to all
157   /// community followers.
158   async fn send_announce(
159     &self,
160     activity: AnyBase,
161     context: &LemmyContext,
162   ) -> Result<(), LemmyError> {
163     let mut announce = Announce::new(self.actor_id.to_owned().into_inner(), activity);
164     announce
165       .set_many_contexts(lemmy_context()?)
166       .set_id(generate_activity_id(AnnounceType::Announce)?)
167       .set_to(public())
168       .set_many_ccs(vec![self.actor_id()]);
169
170     send_to_community_followers(announce, self, context).await?;
171
172     Ok(())
173   }
174
175   /// For a given community, returns the inboxes of all followers.
176   async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
177     let id = self.id;
178
179     let follows = blocking(pool, move |conn| {
180       CommunityFollowerView::for_community(conn, id)
181     })
182     .await??;
183     let inboxes = follows
184       .into_iter()
185       .filter(|f| !f.follower.local)
186       .map(|f| f.follower.shared_inbox_url.unwrap_or(f.follower.inbox_url))
187       .map(|i| i.into_inner())
188       .unique()
189       // Don't send to blocked instances
190       .filter(|inbox| check_is_apub_id_valid(inbox).is_ok())
191       .collect();
192
193     Ok(inboxes)
194   }
195
196   async fn send_add_mod(
197     &self,
198     actor: &User_,
199     added_mod: User_,
200     context: &LemmyContext,
201   ) -> Result<(), LemmyError> {
202     let mut add = Add::new(
203       actor.actor_id.clone().into_inner(),
204       added_mod.actor_id.into_inner(),
205     );
206     add
207       .set_many_contexts(lemmy_context()?)
208       .set_id(generate_activity_id(AddType::Add)?)
209       .set_to(public())
210       .set_many_ccs(vec![self.actor_id()])
211       .set_target(generate_moderators_url(&self.actor_id)?.into_inner());
212
213     send_to_community(add, actor, self, context).await?;
214     Ok(())
215   }
216
217   async fn send_remove_mod(
218     &self,
219     actor: &User_,
220     removed_mod: User_,
221     context: &LemmyContext,
222   ) -> Result<(), LemmyError> {
223     let mut remove = Remove::new(
224       actor.actor_id.clone().into_inner(),
225       removed_mod.actor_id.into_inner(),
226     );
227     remove
228       .set_many_contexts(lemmy_context()?)
229       .set_id(generate_activity_id(RemoveType::Remove)?)
230       .set_to(public())
231       .set_many_ccs(vec![self.actor_id()])
232       .set_target(generate_moderators_url(&self.actor_id)?.into_inner());
233
234     send_to_community(remove, &actor, self, context).await?;
235     Ok(())
236   }
237 }