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,
11 use activitystreams::{
13 kind::{AcceptType, AddType, AnnounceType, DeleteType, LikeType, RemoveType, UndoType},
24 base::{AnyBase, BaseExt, ExtendsExt},
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;
38 #[async_trait::async_trait(?Send)]
39 impl ActorType for Community {
40 fn is_local(&self) -> bool {
43 fn actor_id(&self) -> Url {
44 self.actor_id.to_owned().into_inner()
46 fn public_key(&self) -> Option<String> {
47 self.public_key.to_owned()
49 fn private_key(&self) -> Option<String> {
50 self.private_key.to_owned()
53 fn get_shared_inbox_or_inbox_url(&self) -> Url {
57 .unwrap_or_else(|| self.inbox_url.to_owned())
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(
68 context: &LemmyContext,
69 ) -> Result<(), LemmyError> {
70 let actor_uri = follow
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?;
76 let mut accept = Accept::new(
77 self.actor_id.to_owned().into_inner(),
78 follow.into_any_base()?,
81 .set_many_contexts(lemmy_context()?)
82 .set_id(generate_activity_id(AcceptType::Accept)?)
83 .set_to(user.actor_id());
85 send_activity_single_dest(accept, self, user.inbox_url.into(), context).await?;
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());
93 .set_many_contexts(lemmy_context()?)
94 .set_id(generate_activity_id(DeleteType::Delete)?)
96 .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
98 send_to_community_followers(delete, self, context).await?;
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());
106 .set_many_contexts(lemmy_context()?)
107 .set_id(generate_activity_id(DeleteType::Delete)?)
109 .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
111 let mut undo = Undo::new(self.actor_id(), delete.into_any_base()?);
113 .set_many_contexts(lemmy_context()?)
114 .set_id(generate_activity_id(UndoType::Undo)?)
116 .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
118 send_to_community_followers(undo, self, context).await?;
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());
126 .set_many_contexts(lemmy_context()?)
127 .set_id(generate_activity_id(RemoveType::Remove)?)
129 .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
131 send_to_community_followers(remove, self, context).await?;
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());
139 .set_many_contexts(lemmy_context()?)
140 .set_id(generate_activity_id(RemoveType::Remove)?)
142 .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
144 // Undo that fake activity
145 let mut undo = Undo::new(self.actor_id(), remove.into_any_base()?);
147 .set_many_contexts(lemmy_context()?)
148 .set_id(generate_activity_id(LikeType::Like)?)
150 .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
152 send_to_community_followers(undo, self, context).await?;
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(
161 context: &LemmyContext,
162 ) -> Result<(), LemmyError> {
163 let mut announce = Announce::new(self.actor_id.to_owned().into_inner(), activity);
165 .set_many_contexts(lemmy_context()?)
166 .set_id(generate_activity_id(AnnounceType::Announce)?)
168 .set_many_ccs(vec![self.actor_id()]);
170 send_to_community_followers(announce, self, context).await?;
175 /// For a given community, returns the inboxes of all followers.
176 async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
179 let follows = blocking(pool, move |conn| {
180 CommunityFollowerView::for_community(conn, id)
183 let inboxes = follows
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())
189 // Don't send to blocked instances
190 .filter(|inbox| check_is_apub_id_valid(inbox).is_ok())
196 async fn send_add_mod(
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(),
207 .set_many_contexts(lemmy_context()?)
208 .set_id(generate_activity_id(AddType::Add)?)
210 .set_many_ccs(vec![self.actor_id()])
211 .set_target(generate_moderators_url(&self.actor_id)?.into_inner());
213 send_to_community(add, actor, self, context).await?;
217 async fn send_remove_mod(
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(),
228 .set_many_contexts(lemmy_context()?)
229 .set_id(generate_activity_id(RemoveType::Remove)?)
231 .set_many_ccs(vec![self.actor_id()])
232 .set_target(generate_moderators_url(&self.actor_id)?.into_inner());
234 send_to_community(remove, &actor, self, context).await?;