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_str(&self) -> String {
37 self.actor_id.to_owned()
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(self.actor_id.to_owned(), follow.into_any_base()?);
77 .set_many_contexts(lemmy_context()?)
78 .set_id(generate_activity_id(AcceptType::Accept)?)
79 .set_to(user.actor_id()?);
81 send_activity_single_dest(accept, self, user.get_inbox_url()?, context).await?;
85 /// If the creator of a community deletes the community, send this to all followers.
86 async fn send_delete(&self, context: &LemmyContext) -> Result<(), LemmyError> {
87 let mut delete = Delete::new(self.actor_id()?, self.actor_id()?);
89 .set_many_contexts(lemmy_context()?)
90 .set_id(generate_activity_id(DeleteType::Delete)?)
92 .set_many_ccs(vec![self.get_followers_url()?]);
94 send_to_community_followers(delete, self, context).await?;
98 /// If the creator of a community reverts the deletion of a community, send this to all followers.
99 async fn send_undo_delete(&self, context: &LemmyContext) -> Result<(), LemmyError> {
100 let mut delete = Delete::new(self.actor_id()?, self.actor_id()?);
102 .set_many_contexts(lemmy_context()?)
103 .set_id(generate_activity_id(DeleteType::Delete)?)
105 .set_many_ccs(vec![self.get_followers_url()?]);
107 let mut undo = Undo::new(self.actor_id()?, delete.into_any_base()?);
109 .set_many_contexts(lemmy_context()?)
110 .set_id(generate_activity_id(UndoType::Undo)?)
112 .set_many_ccs(vec![self.get_followers_url()?]);
114 send_to_community_followers(undo, self, context).await?;
118 /// If an admin removes a community, send this to all followers.
119 async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
120 let mut remove = Remove::new(self.actor_id()?, self.actor_id()?);
122 .set_many_contexts(lemmy_context()?)
123 .set_id(generate_activity_id(RemoveType::Remove)?)
125 .set_many_ccs(vec![self.get_followers_url()?]);
127 send_to_community_followers(remove, self, context).await?;
131 /// If an admin reverts the removal of a community, send this to all followers.
132 async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
133 let mut remove = Remove::new(self.actor_id()?, self.actor_id()?);
135 .set_many_contexts(lemmy_context()?)
136 .set_id(generate_activity_id(RemoveType::Remove)?)
138 .set_many_ccs(vec![self.get_followers_url()?]);
140 // Undo that fake activity
141 let mut undo = Undo::new(self.actor_id()?, remove.into_any_base()?);
143 .set_many_contexts(lemmy_context()?)
144 .set_id(generate_activity_id(LikeType::Like)?)
146 .set_many_ccs(vec![self.get_followers_url()?]);
148 send_to_community_followers(undo, self, context).await?;
152 /// Wraps an activity sent to the community in an announce, and then sends the announce to all
153 /// community followers.
154 async fn send_announce(
157 context: &LemmyContext,
158 ) -> Result<(), LemmyError> {
159 let mut announce = Announce::new(self.actor_id.to_owned(), activity);
161 .set_many_contexts(lemmy_context()?)
162 .set_id(generate_activity_id(AnnounceType::Announce)?)
164 .set_many_ccs(vec![self.get_followers_url()?]);
166 send_to_community_followers(announce, self, context).await?;
171 /// For a given community, returns the inboxes of all followers.
173 /// TODO: this function is very badly implemented, we should just store shared_inbox_url in
174 /// CommunityFollowerView
175 async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
178 let inboxes = blocking(pool, move |conn| {
179 CommunityFollowerView::for_community(conn, id)
182 let inboxes = inboxes
184 .filter(|i| !i.follower.local)
185 .map(|u| -> Result<Url, LemmyError> {
186 let url = Url::parse(&u.follower.actor_id)?;
187 let domain = url.domain().context(location_info!())?;
188 let port = if let Some(port) = url.port() {
193 Ok(Url::parse(&format!(
195 Settings::get().get_protocol_string(),
200 .filter_map(Result::ok)
201 // Don't send to blocked instances
202 .filter(|inbox| check_is_apub_id_valid(inbox).is_ok())