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,
10 kind::{AcceptType, AnnounceType, DeleteType, LikeType, RemoveType, UndoType},
19 base::{AnyBase, BaseExt, ExtendsExt},
24 use itertools::Itertools;
25 use lemmy_db::{community::Community, community_view::CommunityFollowerView, DbPool};
26 use lemmy_structs::blocking;
27 use lemmy_utils::{location_info, settings::Settings, LemmyError};
28 use lemmy_websocket::LemmyContext;
31 #[async_trait::async_trait(?Send)]
32 impl ActorType for Community {
33 fn actor_id_str(&self) -> String {
34 self.actor_id.to_owned()
37 fn public_key(&self) -> Option<String> {
38 self.public_key.to_owned()
40 fn private_key(&self) -> Option<String> {
41 self.private_key.to_owned()
46 _follow_actor_id: &Url,
47 _context: &LemmyContext,
48 ) -> Result<(), LemmyError> {
52 async fn send_unfollow(
54 _follow_actor_id: &Url,
55 _context: &LemmyContext,
56 ) -> Result<(), LemmyError> {
60 /// As a local community, accept the follow request from a remote user.
61 async fn send_accept_follow(
64 context: &LemmyContext,
65 ) -> Result<(), LemmyError> {
66 let actor_uri = follow
68 .as_single_xsd_any_uri()
69 .context(location_info!())?;
70 let user = get_or_fetch_and_upsert_user(actor_uri, context, &mut 0).await?;
72 let mut accept = Accept::new(self.actor_id.to_owned(), follow.into_any_base()?);
74 .set_context(activitystreams::context())
75 .set_id(generate_activity_id(AcceptType::Accept)?)
76 .set_to(user.actor_id()?);
78 send_activity_single_dest(accept, self, user.get_inbox_url()?, context).await?;
82 /// If the creator of a community deletes the community, send this to all followers.
83 async fn send_delete(&self, context: &LemmyContext) -> Result<(), LemmyError> {
84 let mut delete = Delete::new(self.actor_id()?, self.actor_id()?);
86 .set_context(activitystreams::context())
87 .set_id(generate_activity_id(DeleteType::Delete)?)
89 .set_many_ccs(vec![self.get_followers_url()?]);
91 send_to_community_followers(delete, self, context).await?;
95 /// If the creator of a community reverts the deletion of a community, send this to all followers.
96 async fn send_undo_delete(&self, context: &LemmyContext) -> Result<(), LemmyError> {
97 let mut delete = Delete::new(self.actor_id()?, self.actor_id()?);
99 .set_context(activitystreams::context())
100 .set_id(generate_activity_id(DeleteType::Delete)?)
102 .set_many_ccs(vec![self.get_followers_url()?]);
104 let mut undo = Undo::new(self.actor_id()?, delete.into_any_base()?);
106 .set_context(activitystreams::context())
107 .set_id(generate_activity_id(UndoType::Undo)?)
109 .set_many_ccs(vec![self.get_followers_url()?]);
111 send_to_community_followers(undo, self, context).await?;
115 /// If an admin removes a community, send this to all followers.
116 async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
117 let mut remove = Remove::new(self.actor_id()?, self.actor_id()?);
119 .set_context(activitystreams::context())
120 .set_id(generate_activity_id(RemoveType::Remove)?)
122 .set_many_ccs(vec![self.get_followers_url()?]);
124 send_to_community_followers(remove, self, context).await?;
128 /// If an admin reverts the removal of a community, send this to all followers.
129 async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
130 let mut remove = Remove::new(self.actor_id()?, 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 // Undo that fake activity
138 let mut undo = Undo::new(self.actor_id()?, remove.into_any_base()?);
140 .set_context(activitystreams::context())
141 .set_id(generate_activity_id(LikeType::Like)?)
143 .set_many_ccs(vec![self.get_followers_url()?]);
145 send_to_community_followers(undo, self, context).await?;
149 /// Wraps an activity sent to the community in an announce, and then sends the announce to all
150 /// community followers.
151 async fn send_announce(
154 context: &LemmyContext,
155 ) -> Result<(), LemmyError> {
156 let mut announce = Announce::new(self.actor_id.to_owned(), activity);
158 .set_context(activitystreams::context())
159 .set_id(generate_activity_id(AnnounceType::Announce)?)
161 .set_many_ccs(vec![self.get_followers_url()?]);
163 send_to_community_followers(announce, self, context).await?;
168 /// For a given community, returns the inboxes of all followers.
170 /// TODO: this function is very badly implemented, we should just store shared_inbox_url in
171 /// CommunityFollowerView
172 async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
175 let inboxes = blocking(pool, move |conn| {
176 CommunityFollowerView::for_community(conn, id)
179 let inboxes = inboxes
181 .filter(|i| !i.user_local)
182 .map(|u| -> Result<Url, LemmyError> {
183 let url = Url::parse(&u.user_actor_id)?;
184 let domain = url.domain().context(location_info!())?;
185 let port = if let Some(port) = url.port() {
190 Ok(Url::parse(&format!(
192 Settings::get().get_protocol_string(),
197 .filter_map(Result::ok)
198 // Don't send to blocked instances
199 .filter(|inbox| check_is_apub_id_valid(inbox).is_ok())