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