2 activities::send::generate_activity_id,
3 activity_queue::{send_activity_single_dest, send_to_community_followers},
4 check_is_apub_id_valid,
5 fetcher::get_or_fetch_and_upsert_user,
11 kind::{AcceptType, AnnounceType, DeleteType, LikeType, RemoveType, UndoType},
20 base::{AnyBase, BaseExt, ExtendsExt},
25 use itertools::Itertools;
26 use lemmy_db::{community::Community, community_view::CommunityFollowerView, user::User_, DbPool};
27 use lemmy_structs::blocking;
28 use lemmy_utils::{location_info, settings::Settings, LemmyError};
29 use lemmy_websocket::LemmyContext;
32 #[async_trait::async_trait(?Send)]
33 impl ActorType for Community {
34 fn actor_id_str(&self) -> String {
35 self.actor_id.to_owned()
38 fn public_key(&self) -> Option<String> {
39 self.public_key.to_owned()
41 fn private_key(&self) -> Option<String> {
42 self.private_key.to_owned()
45 fn user_id(&self) -> i32 {
51 _follow_actor_id: &Url,
52 _context: &LemmyContext,
53 ) -> Result<(), LemmyError> {
57 async fn send_unfollow(
59 _follow_actor_id: &Url,
60 _context: &LemmyContext,
61 ) -> Result<(), LemmyError> {
65 /// As a local community, accept the follow request from a remote user.
66 async fn send_accept_follow(
69 context: &LemmyContext,
70 ) -> Result<(), LemmyError> {
71 let actor_uri = follow
73 .as_single_xsd_any_uri()
74 .context(location_info!())?;
75 let user = get_or_fetch_and_upsert_user(actor_uri, context, &mut 0).await?;
77 let mut accept = Accept::new(self.actor_id.to_owned(), follow.into_any_base()?);
79 .set_context(activitystreams::context())
80 .set_id(generate_activity_id(AcceptType::Accept)?)
81 .set_to(user.actor_id()?);
83 send_activity_single_dest(accept, self, user.get_inbox_url()?, context).await?;
87 /// If the creator of a community deletes the community, send this to all followers.
88 async fn send_delete(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
89 let group = self.to_apub(context.pool()).await?;
91 let mut delete = Delete::new(creator.actor_id.to_owned(), group.into_any_base()?);
93 .set_context(activitystreams::context())
94 .set_id(generate_activity_id(DeleteType::Delete)?)
96 .set_many_ccs(vec![self.get_followers_url()?]);
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(
106 context: &LemmyContext,
107 ) -> Result<(), LemmyError> {
108 let group = self.to_apub(context.pool()).await?;
110 let mut delete = Delete::new(creator.actor_id.to_owned(), group.into_any_base()?);
112 .set_context(activitystreams::context())
113 .set_id(generate_activity_id(DeleteType::Delete)?)
115 .set_many_ccs(vec![self.get_followers_url()?]);
117 let mut undo = Undo::new(creator.actor_id.to_owned(), delete.into_any_base()?);
119 .set_context(activitystreams::context())
120 .set_id(generate_activity_id(UndoType::Undo)?)
122 .set_many_ccs(vec![self.get_followers_url()?]);
124 send_to_community_followers(undo, self, context).await?;
128 /// If an admin removes a community, send this to all followers.
129 async fn send_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
130 let mut remove = Remove::new(mod_.actor_id.to_owned(), self.actor_id()?);
132 .set_context(activitystreams::context())
133 .set_id(generate_activity_id(RemoveType::Remove)?)
135 .set_many_ccs(vec![self.get_followers_url()?]);
137 send_to_community_followers(remove, self, context).await?;
141 /// If an admin reverts the removal of a community, send this to all followers.
142 async fn send_undo_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError> {
143 let mut remove = Remove::new(mod_.actor_id.to_owned(), self.actor_id()?);
145 .set_context(activitystreams::context())
146 .set_id(generate_activity_id(RemoveType::Remove)?)
148 .set_many_ccs(vec![self.get_followers_url()?]);
150 // Undo that fake activity
151 let mut undo = Undo::new(mod_.actor_id.to_owned(), remove.into_any_base()?);
153 .set_context(activitystreams::context())
154 .set_id(generate_activity_id(LikeType::Like)?)
156 .set_many_ccs(vec![self.get_followers_url()?]);
158 send_to_community_followers(undo, self, context).await?;
162 /// Wraps an activity sent to the community in an announce, and then sends the announce to all
163 /// community followers.
164 async fn send_announce(
167 context: &LemmyContext,
168 ) -> Result<(), LemmyError> {
169 let mut announce = Announce::new(self.actor_id.to_owned(), activity);
171 .set_context(activitystreams::context())
172 .set_id(generate_activity_id(AnnounceType::Announce)?)
174 .set_many_ccs(vec![self.get_followers_url()?]);
176 send_to_community_followers(announce, self, context).await?;
181 /// For a given community, returns the inboxes of all followers.
183 /// TODO: this function is very badly implemented, we should just store shared_inbox_url in
184 /// CommunityFollowerView
185 async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
188 let inboxes = blocking(pool, move |conn| {
189 CommunityFollowerView::for_community(conn, id)
192 let inboxes = inboxes
194 .filter(|i| !i.user_local)
195 .map(|u| -> Result<Url, LemmyError> {
196 let url = Url::parse(&u.user_actor_id)?;
197 let domain = url.domain().context(location_info!())?;
198 let port = if let Some(port) = url.port() {
203 Ok(Url::parse(&format!(
205 Settings::get().get_protocol_string(),
210 .filter_map(Result::ok)
211 // Don't send to blocked instances
212 .filter(|inbox| check_is_apub_id_valid(inbox).is_ok())