]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/send/community.rs
Running clippy --fix (#1647)
[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::{get_or_fetch_and_upsert_actor, person::get_or_fetch_and_upsert_person},
7   generate_moderators_url,
8   insert_activity,
9   objects::ToApub,
10   ActorType,
11   CommunityType,
12 };
13 use activitystreams::{
14   activity::{
15     kind::{
16       AcceptType,
17       AddType,
18       AnnounceType,
19       BlockType,
20       DeleteType,
21       LikeType,
22       RemoveType,
23       UndoType,
24       UpdateType,
25     },
26     Accept,
27     ActorAndObjectRefExt,
28     Add,
29     Announce,
30     Block,
31     Delete,
32     Follow,
33     OptTargetRefExt,
34     Remove,
35     Undo,
36     Update,
37   },
38   base::{AnyBase, BaseExt, ExtendsExt},
39   object::ObjectExt,
40   public,
41 };
42 use anyhow::Context;
43 use itertools::Itertools;
44 use lemmy_api_common::blocking;
45 use lemmy_db_queries::DbPool;
46 use lemmy_db_schema::source::{community::Community, person::Person};
47 use lemmy_db_views_actor::community_follower_view::CommunityFollowerView;
48 use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
49 use lemmy_websocket::LemmyContext;
50 use url::Url;
51
52 #[async_trait::async_trait(?Send)]
53 impl ActorType for Community {
54   fn is_local(&self) -> bool {
55     self.local
56   }
57   fn actor_id(&self) -> Url {
58     self.actor_id.to_owned().into_inner()
59   }
60   fn public_key(&self) -> Option<String> {
61     self.public_key.to_owned()
62   }
63   fn private_key(&self) -> Option<String> {
64     self.private_key.to_owned()
65   }
66
67   fn get_shared_inbox_or_inbox_url(&self) -> Url {
68     self
69       .shared_inbox_url
70       .clone()
71       .unwrap_or_else(|| self.inbox_url.to_owned())
72       .into()
73   }
74 }
75
76 #[async_trait::async_trait(?Send)]
77 impl CommunityType for Community {
78   fn followers_url(&self) -> Url {
79     self.followers_url.clone().into_inner()
80   }
81
82   /// As a local community, accept the follow request from a remote person.
83   async fn send_accept_follow(
84     &self,
85     follow: Follow,
86     context: &LemmyContext,
87   ) -> Result<(), LemmyError> {
88     let actor_uri = follow
89       .actor()?
90       .as_single_xsd_any_uri()
91       .context(location_info!())?;
92     let person = get_or_fetch_and_upsert_person(actor_uri, context, &mut 0).await?;
93
94     let mut accept = Accept::new(
95       self.actor_id.to_owned().into_inner(),
96       follow.into_any_base()?,
97     );
98     accept
99       .set_many_contexts(lemmy_context()?)
100       .set_id(generate_activity_id(AcceptType::Accept)?)
101       .set_to(person.actor_id());
102
103     send_activity_single_dest(accept, self, person.inbox_url.into(), context).await?;
104     Ok(())
105   }
106
107   /// If a remote community is updated by a local mod, send the updated info to the community's
108   /// instance.
109   async fn send_update(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> {
110     if self.local {
111       // Do nothing, other instances will automatically refetch the community
112     } else {
113       let mut update = Update::new(
114         mod_.actor_id(),
115         self.to_apub(context.pool()).await?.into_any_base()?,
116       );
117       update
118         .set_many_contexts(lemmy_context()?)
119         .set_id(generate_activity_id(UpdateType::Update)?)
120         .set_to(public())
121         .set_many_ccs(vec![self.actor_id()]);
122       send_to_community(update, &mod_, self, None, context).await?;
123     }
124     Ok(())
125   }
126
127   /// If the creator of a community deletes the community, send this to all followers.
128   ///
129   /// We need to handle deletion by a remote mod separately.
130   async fn send_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> {
131     // Local mod, send directly from community to followers
132     if self.local {
133       let mut delete = Delete::new(self.actor_id(), self.actor_id());
134       delete
135         .set_many_contexts(lemmy_context()?)
136         .set_id(generate_activity_id(DeleteType::Delete)?)
137         .set_to(public())
138         .set_many_ccs(vec![self.followers_url()]);
139
140       send_to_community_followers(delete, self, None, context).await?;
141     }
142     // Remote mod, send from mod to community
143     else {
144       let mut delete = Delete::new(mod_.actor_id(), self.actor_id());
145       delete
146         .set_many_contexts(lemmy_context()?)
147         .set_id(generate_activity_id(DeleteType::Delete)?)
148         .set_to(public())
149         .set_many_ccs(vec![self.actor_id()]);
150
151       send_to_community(delete, &mod_, self, None, context).await?;
152     }
153     Ok(())
154   }
155
156   /// If the creator of a community reverts the deletion of a community, send this to all followers.
157   ///
158   /// We need to handle undelete by a remote mod separately.
159   async fn send_undo_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> {
160     // Local mod, send directly from community to followers
161     if self.local {
162       let mut delete = Delete::new(self.actor_id(), self.actor_id());
163       delete
164         .set_many_contexts(lemmy_context()?)
165         .set_id(generate_activity_id(DeleteType::Delete)?)
166         .set_to(public())
167         .set_many_ccs(vec![self.followers_url()]);
168
169       let mut undo = Undo::new(self.actor_id(), delete.into_any_base()?);
170       undo
171         .set_many_contexts(lemmy_context()?)
172         .set_id(generate_activity_id(UndoType::Undo)?)
173         .set_to(public())
174         .set_many_ccs(vec![self.followers_url()]);
175
176       send_to_community_followers(undo, self, None, context).await?;
177     }
178     // Remote mod, send from mod to community
179     else {
180       let mut delete = Delete::new(mod_.actor_id(), self.actor_id());
181       delete
182         .set_many_contexts(lemmy_context()?)
183         .set_id(generate_activity_id(DeleteType::Delete)?)
184         .set_to(public())
185         .set_many_ccs(vec![self.actor_id()]);
186
187       let mut undo = Undo::new(mod_.actor_id(), delete.into_any_base()?);
188       undo
189         .set_many_contexts(lemmy_context()?)
190         .set_id(generate_activity_id(UndoType::Undo)?)
191         .set_to(public())
192         .set_many_ccs(vec![self.actor_id()]);
193
194       send_to_community(undo, &mod_, self, None, context).await?;
195     }
196     Ok(())
197   }
198
199   /// If an admin removes a community, send this to all followers.
200   async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
201     let mut remove = Remove::new(self.actor_id(), self.actor_id());
202     remove
203       .set_many_contexts(lemmy_context()?)
204       .set_id(generate_activity_id(RemoveType::Remove)?)
205       .set_to(public())
206       .set_many_ccs(vec![self.followers_url()]);
207
208     send_to_community_followers(remove, self, None, context).await?;
209     Ok(())
210   }
211
212   /// If an admin reverts the removal of a community, send this to all followers.
213   async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
214     let mut remove = Remove::new(self.actor_id(), self.actor_id());
215     remove
216       .set_many_contexts(lemmy_context()?)
217       .set_id(generate_activity_id(RemoveType::Remove)?)
218       .set_to(public())
219       .set_many_ccs(vec![self.followers_url()]);
220
221     // Undo that fake activity
222     let mut undo = Undo::new(self.actor_id(), remove.into_any_base()?);
223     undo
224       .set_many_contexts(lemmy_context()?)
225       .set_id(generate_activity_id(LikeType::Like)?)
226       .set_to(public())
227       .set_many_ccs(vec![self.followers_url()]);
228
229     send_to_community_followers(undo, self, None, context).await?;
230     Ok(())
231   }
232
233   /// Wraps an activity sent to the community in an announce, and then sends the announce to all
234   /// community followers.
235   ///
236   /// If we are announcing a local activity, it hasn't been stored in the database yet, and we need
237   /// to do it here, so that it can be fetched by ID. Remote activities are inserted into DB in the
238   /// inbox.
239   ///
240   /// If the `object` of the announced activity is an actor, the actor ID needs to be passed as
241   /// `object_actor`, so that the announce can be delivered to that user.
242   async fn send_announce(
243     &self,
244     activity: AnyBase,
245     object_actor: Option<Url>,
246     context: &LemmyContext,
247   ) -> Result<(), LemmyError> {
248     let inner_id = activity.id().context(location_info!())?;
249     if inner_id.domain() == Some(&Settings::get().get_hostname_without_port()?) {
250       insert_activity(inner_id, activity.clone(), true, false, context.pool()).await?;
251     }
252
253     let mut ccs = vec![self.followers_url()];
254     let mut object_actor_inbox: Option<Url> = None;
255     if let Some(actor_id) = object_actor {
256       // Ignore errors, maybe its not actually an actor
257       // TODO: should pass the actual request counter in, but that seems complicated
258       let actor = get_or_fetch_and_upsert_actor(&actor_id, context, &mut 0)
259         .await
260         .ok();
261       if let Some(actor) = actor {
262         ccs.push(actor_id);
263         object_actor_inbox = Some(actor.get_shared_inbox_or_inbox_url());
264       }
265     }
266     let mut announce = Announce::new(self.actor_id(), activity);
267     announce
268       .set_many_contexts(lemmy_context()?)
269       .set_id(generate_activity_id(AnnounceType::Announce)?)
270       .set_to(public())
271       .set_many_ccs(ccs);
272
273     send_to_community_followers(announce, self, object_actor_inbox, context).await?;
274
275     Ok(())
276   }
277
278   /// For a given community, returns the inboxes of all followers.
279   async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
280     let id = self.id;
281
282     let follows = blocking(pool, move |conn| {
283       CommunityFollowerView::for_community(conn, id)
284     })
285     .await??;
286     let inboxes = follows
287       .into_iter()
288       .filter(|f| !f.follower.local)
289       .map(|f| f.follower.shared_inbox_url.unwrap_or(f.follower.inbox_url))
290       .map(|i| i.into_inner())
291       .unique()
292       // Don't send to blocked instances
293       .filter(|inbox| check_is_apub_id_valid(inbox, false).is_ok())
294       .collect();
295
296     Ok(inboxes)
297   }
298
299   async fn send_add_mod(
300     &self,
301     actor: &Person,
302     added_mod: Person,
303     context: &LemmyContext,
304   ) -> Result<(), LemmyError> {
305     let mut add = Add::new(actor.actor_id(), added_mod.actor_id());
306     add
307       .set_many_contexts(lemmy_context()?)
308       .set_id(generate_activity_id(AddType::Add)?)
309       .set_to(public())
310       .set_many_ccs(vec![self.actor_id()])
311       .set_target(generate_moderators_url(&self.actor_id)?.into_inner());
312
313     send_to_community(add, actor, self, Some(added_mod.actor_id()), context).await?;
314     Ok(())
315   }
316
317   async fn send_remove_mod(
318     &self,
319     actor: &Person,
320     removed_mod: Person,
321     context: &LemmyContext,
322   ) -> Result<(), LemmyError> {
323     let mut remove = Remove::new(actor.actor_id(), removed_mod.actor_id());
324     remove
325       .set_many_contexts(lemmy_context()?)
326       .set_id(generate_activity_id(RemoveType::Remove)?)
327       .set_to(public())
328       .set_many_ccs(vec![self.actor_id()])
329       .set_target(generate_moderators_url(&self.actor_id)?.into_inner());
330
331     send_to_community(remove, actor, self, Some(removed_mod.actor_id()), context).await?;
332     Ok(())
333   }
334
335   async fn send_block_user(
336     &self,
337     actor: &Person,
338     blocked_user: Person,
339     context: &LemmyContext,
340   ) -> Result<(), LemmyError> {
341     let mut block = Block::new(actor.actor_id(), blocked_user.actor_id());
342     block
343       .set_many_contexts(lemmy_context()?)
344       .set_id(generate_activity_id(BlockType::Block)?)
345       .set_to(public())
346       .set_many_ccs(vec![self.actor_id()]);
347
348     send_to_community(block, actor, self, Some(blocked_user.actor_id()), context).await?;
349     Ok(())
350   }
351
352   async fn send_undo_block_user(
353     &self,
354     actor: &Person,
355     unblocked_user: Person,
356     context: &LemmyContext,
357   ) -> Result<(), LemmyError> {
358     let mut block = Block::new(actor.actor_id(), unblocked_user.actor_id());
359     block
360       .set_many_contexts(lemmy_context()?)
361       .set_id(generate_activity_id(BlockType::Block)?)
362       .set_to(public())
363       .set_many_ccs(vec![self.actor_id()]);
364
365     // Undo that fake activity
366     let mut undo = Undo::new(actor.actor_id(), block.into_any_base()?);
367     undo
368       .set_many_contexts(lemmy_context()?)
369       .set_id(generate_activity_id(UndoType::Undo)?)
370       .set_to(public())
371       .set_many_ccs(vec![self.actor_id()]);
372
373     send_to_community(undo, actor, self, Some(unblocked_user.actor_id()), context).await?;
374     Ok(())
375   }
376 }