2 activities::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,
13 use activitystreams::{
38 base::{AnyBase, BaseExt, ExtendsExt},
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;
52 impl ActorType for Community {
53 fn is_local(&self) -> bool {
56 fn actor_id(&self) -> Url {
57 self.actor_id.to_owned().into_inner()
59 fn name(&self) -> String {
62 fn public_key(&self) -> Option<String> {
63 self.public_key.to_owned()
65 fn private_key(&self) -> Option<String> {
66 self.private_key.to_owned()
69 fn get_shared_inbox_or_inbox_url(&self) -> Url {
73 .unwrap_or_else(|| self.inbox_url.to_owned())
78 #[async_trait::async_trait(?Send)]
79 impl CommunityType for Community {
80 fn followers_url(&self) -> Url {
81 self.followers_url.clone().into_inner()
84 /// As a local community, accept the follow request from a remote person.
85 async fn send_accept_follow(
88 context: &LemmyContext,
89 ) -> Result<(), LemmyError> {
90 let actor_uri = follow
92 .as_single_xsd_any_uri()
93 .context(location_info!())?;
94 let person = get_or_fetch_and_upsert_person(actor_uri, context, &mut 0).await?;
96 let mut accept = Accept::new(
97 self.actor_id.to_owned().into_inner(),
98 follow.into_any_base()?,
101 .set_many_contexts(lemmy_context())
102 .set_id(generate_activity_id(AcceptType::Accept)?)
103 .set_to(person.actor_id());
105 send_activity_single_dest(accept, self, person.inbox_url.into(), context).await?;
109 /// If a remote community is updated by a local mod, send the updated info to the community's
111 async fn send_update(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> {
113 // Do nothing, other instances will automatically refetch the community
115 let mut update = Update::new(
117 self.to_apub(context.pool()).await?.into_any_base()?,
120 .set_many_contexts(lemmy_context())
121 .set_id(generate_activity_id(UpdateType::Update)?)
123 .set_many_ccs(vec![self.actor_id()]);
124 send_to_community(update, &mod_, self, None, context).await?;
129 /// If the creator of a community deletes the community, send this to all followers.
131 /// We need to handle deletion by a remote mod separately.
132 async fn send_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> {
133 // Local mod, send directly from community to followers
135 let mut delete = Delete::new(self.actor_id(), self.actor_id());
137 .set_many_contexts(lemmy_context())
138 .set_id(generate_activity_id(DeleteType::Delete)?)
140 .set_many_ccs(vec![self.followers_url()]);
142 send_to_community_followers(delete, self, None, context).await?;
144 // Remote mod, send from mod to community
146 let mut delete = Delete::new(mod_.actor_id(), self.actor_id());
148 .set_many_contexts(lemmy_context())
149 .set_id(generate_activity_id(DeleteType::Delete)?)
151 .set_many_ccs(vec![self.actor_id()]);
153 send_to_community(delete, &mod_, self, None, context).await?;
158 /// If the creator of a community reverts the deletion of a community, send this to all followers.
160 /// We need to handle undelete by a remote mod separately.
161 async fn send_undo_delete(&self, mod_: Person, context: &LemmyContext) -> Result<(), LemmyError> {
162 // Local mod, send directly from community to followers
164 let mut delete = Delete::new(self.actor_id(), self.actor_id());
166 .set_many_contexts(lemmy_context())
167 .set_id(generate_activity_id(DeleteType::Delete)?)
169 .set_many_ccs(vec![self.followers_url()]);
171 let mut undo = Undo::new(self.actor_id(), delete.into_any_base()?);
173 .set_many_contexts(lemmy_context())
174 .set_id(generate_activity_id(UndoType::Undo)?)
176 .set_many_ccs(vec![self.followers_url()]);
178 send_to_community_followers(undo, self, None, context).await?;
180 // Remote mod, send from mod to community
182 let mut delete = Delete::new(mod_.actor_id(), self.actor_id());
184 .set_many_contexts(lemmy_context())
185 .set_id(generate_activity_id(DeleteType::Delete)?)
187 .set_many_ccs(vec![self.actor_id()]);
189 let mut undo = Undo::new(mod_.actor_id(), delete.into_any_base()?);
191 .set_many_contexts(lemmy_context())
192 .set_id(generate_activity_id(UndoType::Undo)?)
194 .set_many_ccs(vec![self.actor_id()]);
196 send_to_community(undo, &mod_, self, None, context).await?;
201 /// If an admin removes a community, send this to all followers.
202 async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
203 let mut remove = Remove::new(self.actor_id(), self.actor_id());
205 .set_many_contexts(lemmy_context())
206 .set_id(generate_activity_id(RemoveType::Remove)?)
208 .set_many_ccs(vec![self.followers_url()]);
210 send_to_community_followers(remove, self, None, context).await?;
214 /// If an admin reverts the removal of a community, send this to all followers.
215 async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
216 let mut remove = Remove::new(self.actor_id(), self.actor_id());
218 .set_many_contexts(lemmy_context())
219 .set_id(generate_activity_id(RemoveType::Remove)?)
221 .set_many_ccs(vec![self.followers_url()]);
223 // Undo that fake activity
224 let mut undo = Undo::new(self.actor_id(), remove.into_any_base()?);
226 .set_many_contexts(lemmy_context())
227 .set_id(generate_activity_id(LikeType::Like)?)
229 .set_many_ccs(vec![self.followers_url()]);
231 send_to_community_followers(undo, self, None, context).await?;
235 /// Wraps an activity sent to the community in an announce, and then sends the announce to all
236 /// community followers.
238 /// If we are announcing a local activity, it hasn't been stored in the database yet, and we need
239 /// to do it here, so that it can be fetched by ID. Remote activities are inserted into DB in the
242 /// If the `object` of the announced activity is an actor, the actor ID needs to be passed as
243 /// `object_actor`, so that the announce can be delivered to that user.
244 async fn send_announce(
247 object_actor: Option<Url>,
248 context: &LemmyContext,
249 ) -> Result<(), LemmyError> {
250 let inner_id = activity.id().context(location_info!())?;
251 if inner_id.domain() == Some(&Settings::get().get_hostname_without_port()?) {
252 insert_activity(inner_id, activity.clone(), true, false, context.pool()).await?;
255 let mut ccs = vec![self.followers_url()];
256 let mut object_actor_inbox: Option<Url> = None;
257 if let Some(actor_id) = object_actor {
258 // Ignore errors, maybe its not actually an actor
259 // TODO: should pass the actual request counter in, but that seems complicated
260 let actor = get_or_fetch_and_upsert_actor(&actor_id, context, &mut 0)
263 if let Some(actor) = actor {
265 object_actor_inbox = Some(actor.get_shared_inbox_or_inbox_url());
268 let mut announce = Announce::new(self.actor_id(), activity);
270 .set_many_contexts(lemmy_context())
271 .set_id(generate_activity_id(AnnounceType::Announce)?)
275 send_to_community_followers(announce, self, object_actor_inbox, context).await?;
280 /// For a given community, returns the inboxes of all followers.
281 async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
284 let follows = blocking(pool, move |conn| {
285 CommunityFollowerView::for_community(conn, id)
288 let inboxes = follows
290 .filter(|f| !f.follower.local)
291 .map(|f| f.follower.shared_inbox_url.unwrap_or(f.follower.inbox_url))
292 .map(|i| i.into_inner())
294 // Don't send to blocked instances
295 .filter(|inbox| check_is_apub_id_valid(inbox, false).is_ok())
301 async fn send_add_mod(
305 context: &LemmyContext,
306 ) -> Result<(), LemmyError> {
307 let mut add = Add::new(actor.actor_id(), added_mod.actor_id());
309 .set_many_contexts(lemmy_context())
310 .set_id(generate_activity_id(AddType::Add)?)
312 .set_many_ccs(vec![self.actor_id()])
313 .set_target(generate_moderators_url(&self.actor_id)?.into_inner());
315 send_to_community(add, actor, self, Some(added_mod.actor_id()), context).await?;
319 async fn send_remove_mod(
323 context: &LemmyContext,
324 ) -> Result<(), LemmyError> {
325 let mut remove = Remove::new(actor.actor_id(), removed_mod.actor_id());
327 .set_many_contexts(lemmy_context())
328 .set_id(generate_activity_id(RemoveType::Remove)?)
330 .set_many_ccs(vec![self.actor_id()])
331 .set_target(generate_moderators_url(&self.actor_id)?.into_inner());
333 send_to_community(remove, actor, self, Some(removed_mod.actor_id()), context).await?;
337 async fn send_block_user(
340 blocked_user: Person,
341 context: &LemmyContext,
342 ) -> Result<(), LemmyError> {
343 let mut block = Block::new(actor.actor_id(), blocked_user.actor_id());
345 .set_many_contexts(lemmy_context())
346 .set_id(generate_activity_id(BlockType::Block)?)
348 .set_many_ccs(vec![self.actor_id()]);
350 send_to_community(block, actor, self, Some(blocked_user.actor_id()), context).await?;
354 async fn send_undo_block_user(
357 unblocked_user: Person,
358 context: &LemmyContext,
359 ) -> Result<(), LemmyError> {
360 let mut block = Block::new(actor.actor_id(), unblocked_user.actor_id());
362 .set_many_contexts(lemmy_context())
363 .set_id(generate_activity_id(BlockType::Block)?)
365 .set_many_ccs(vec![self.actor_id()]);
367 // Undo that fake activity
368 let mut undo = Undo::new(actor.actor_id(), block.into_any_base()?);
370 .set_many_contexts(lemmy_context())
371 .set_id(generate_activity_id(UndoType::Undo)?)
373 .set_many_ccs(vec![self.actor_id()]);
375 send_to_community(undo, actor, self, Some(unblocked_user.actor_id()), context).await?;