2 activities::send::generate_activity_id,
3 activity_queue::{send_activity_single_dest, send_to_community_followers},
4 check_is_apub_id_valid,
5 extensions::context::lemmy_context,
6 fetcher::user::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_queries::DbPool;
27 use lemmy_db_schema::source::community::Community;
28 use lemmy_db_views_actor::community_follower_view::CommunityFollowerView;
29 use lemmy_structs::blocking;
30 use lemmy_utils::{location_info, settings::Settings, LemmyError};
31 use lemmy_websocket::LemmyContext;
34 #[async_trait::async_trait(?Send)]
35 impl ActorType for Community {
36 fn actor_id(&self) -> Url {
37 self.actor_id.to_owned().into_inner()
40 fn public_key(&self) -> Option<String> {
41 self.public_key.to_owned()
43 fn private_key(&self) -> Option<String> {
44 self.private_key.to_owned()
49 _follow_actor_id: &Url,
50 _context: &LemmyContext,
51 ) -> Result<(), LemmyError> {
55 async fn send_unfollow(
57 _follow_actor_id: &Url,
58 _context: &LemmyContext,
59 ) -> Result<(), LemmyError> {
63 /// As a local community, accept the follow request from a remote user.
64 async fn send_accept_follow(
67 context: &LemmyContext,
68 ) -> Result<(), LemmyError> {
69 let actor_uri = follow
71 .as_single_xsd_any_uri()
72 .context(location_info!())?;
73 let user = get_or_fetch_and_upsert_user(actor_uri, context, &mut 0).await?;
75 let mut accept = Accept::new(
76 self.actor_id.to_owned().into_inner(),
77 follow.into_any_base()?,
80 .set_many_contexts(lemmy_context()?)
81 .set_id(generate_activity_id(AcceptType::Accept)?)
82 .set_to(user.actor_id());
84 send_activity_single_dest(accept, self, user.get_inbox_url()?, context).await?;
88 /// If the creator of a community deletes the community, send this to all followers.
89 async fn send_delete(&self, context: &LemmyContext) -> Result<(), LemmyError> {
90 let mut delete = Delete::new(self.actor_id(), self.actor_id());
92 .set_many_contexts(lemmy_context()?)
93 .set_id(generate_activity_id(DeleteType::Delete)?)
95 .set_many_ccs(vec![self.get_followers_url()?]);
97 send_to_community_followers(delete, self, context).await?;
101 /// If the creator of a community reverts the deletion of a community, send this to all followers.
102 async fn send_undo_delete(&self, context: &LemmyContext) -> Result<(), LemmyError> {
103 let mut delete = Delete::new(self.actor_id(), self.actor_id());
105 .set_many_contexts(lemmy_context()?)
106 .set_id(generate_activity_id(DeleteType::Delete)?)
108 .set_many_ccs(vec![self.get_followers_url()?]);
110 let mut undo = Undo::new(self.actor_id(), delete.into_any_base()?);
112 .set_many_contexts(lemmy_context()?)
113 .set_id(generate_activity_id(UndoType::Undo)?)
115 .set_many_ccs(vec![self.get_followers_url()?]);
117 send_to_community_followers(undo, self, context).await?;
121 /// If an admin removes a community, send this to all followers.
122 async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
123 let mut remove = Remove::new(self.actor_id(), self.actor_id());
125 .set_many_contexts(lemmy_context()?)
126 .set_id(generate_activity_id(RemoveType::Remove)?)
128 .set_many_ccs(vec![self.get_followers_url()?]);
130 send_to_community_followers(remove, self, context).await?;
134 /// If an admin reverts the removal of a community, send this to all followers.
135 async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
136 let mut remove = Remove::new(self.actor_id(), self.actor_id());
138 .set_many_contexts(lemmy_context()?)
139 .set_id(generate_activity_id(RemoveType::Remove)?)
141 .set_many_ccs(vec![self.get_followers_url()?]);
143 // Undo that fake activity
144 let mut undo = Undo::new(self.actor_id(), remove.into_any_base()?);
146 .set_many_contexts(lemmy_context()?)
147 .set_id(generate_activity_id(LikeType::Like)?)
149 .set_many_ccs(vec![self.get_followers_url()?]);
151 send_to_community_followers(undo, self, context).await?;
155 /// Wraps an activity sent to the community in an announce, and then sends the announce to all
156 /// community followers.
157 async fn send_announce(
160 context: &LemmyContext,
161 ) -> Result<(), LemmyError> {
162 let mut announce = Announce::new(self.actor_id.to_owned().into_inner(), activity);
164 .set_many_contexts(lemmy_context()?)
165 .set_id(generate_activity_id(AnnounceType::Announce)?)
167 .set_many_ccs(vec![self.get_followers_url()?]);
169 send_to_community_followers(announce, self, context).await?;
174 /// For a given community, returns the inboxes of all followers.
176 /// TODO: this function is very badly implemented, we should just store shared_inbox_url in
177 /// CommunityFollowerView
178 async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
181 let inboxes = blocking(pool, move |conn| {
182 CommunityFollowerView::for_community(conn, id)
185 let inboxes = inboxes
187 .filter(|i| !i.follower.local)
188 .map(|u| -> Result<Url, LemmyError> {
189 let url = u.follower.actor_id.into_inner();
190 let domain = url.domain().context(location_info!())?;
191 let port = if let Some(port) = url.port() {
196 Ok(Url::parse(&format!(
198 Settings::get().get_protocol_string(),
203 .filter_map(Result::ok)
204 // Don't send to blocked instances
205 .filter(|inbox| check_is_apub_id_valid(inbox).is_ok())