]> Untitled Git - lemmy.git/blob - lemmy_apub/src/activities/send/community.rs
446ce6f349a1e33ed47b6ae3a5eccca43005f4c9
[lemmy.git] / lemmy_apub / src / activities / send / community.rs
1 use crate::{
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,
6   ActorType,
7   ToApub,
8 };
9 use activitystreams::{
10   activity::{
11     kind::{AcceptType, AnnounceType, DeleteType, LikeType, RemoveType, UndoType},
12     Accept,
13     ActorAndObjectRefExt,
14     Announce,
15     Delete,
16     Follow,
17     Remove,
18     Undo,
19   },
20   base::{AnyBase, BaseExt, ExtendsExt},
21   object::ObjectExt,
22   public,
23 };
24 use anyhow::Context;
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;
30 use url::Url;
31
32 #[async_trait::async_trait(?Send)]
33 impl ActorType for Community {
34   fn actor_id_str(&self) -> String {
35     self.actor_id.to_owned()
36   }
37
38   fn public_key(&self) -> Option<String> {
39     self.public_key.to_owned()
40   }
41   fn private_key(&self) -> Option<String> {
42     self.private_key.to_owned()
43   }
44
45   fn user_id(&self) -> i32 {
46     self.creator_id
47   }
48
49   async fn send_follow(
50     &self,
51     _follow_actor_id: &Url,
52     _context: &LemmyContext,
53   ) -> Result<(), LemmyError> {
54     unimplemented!()
55   }
56
57   async fn send_unfollow(
58     &self,
59     _follow_actor_id: &Url,
60     _context: &LemmyContext,
61   ) -> Result<(), LemmyError> {
62     unimplemented!()
63   }
64
65   /// As a local community, accept the follow request from a remote user.
66   async fn send_accept_follow(
67     &self,
68     follow: Follow,
69     context: &LemmyContext,
70   ) -> Result<(), LemmyError> {
71     let actor_uri = follow
72       .actor()?
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?;
76
77     let mut accept = Accept::new(self.actor_id.to_owned(), follow.into_any_base()?);
78     accept
79       .set_context(activitystreams::context())
80       .set_id(generate_activity_id(AcceptType::Accept)?)
81       .set_to(user.actor_id()?);
82
83     send_activity_single_dest(accept, self, user.get_inbox_url()?, context).await?;
84     Ok(())
85   }
86
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?;
90
91     let mut delete = Delete::new(creator.actor_id.to_owned(), group.into_any_base()?);
92     delete
93       .set_context(activitystreams::context())
94       .set_id(generate_activity_id(DeleteType::Delete)?)
95       .set_to(public())
96       .set_many_ccs(vec![self.get_followers_url()?]);
97
98     send_to_community_followers(delete, self, context).await?;
99     Ok(())
100   }
101
102   /// If the creator of a community reverts the deletion of a community, send this to all followers.
103   async fn send_undo_delete(
104     &self,
105     creator: &User_,
106     context: &LemmyContext,
107   ) -> Result<(), LemmyError> {
108     let group = self.to_apub(context.pool()).await?;
109
110     let mut delete = Delete::new(creator.actor_id.to_owned(), group.into_any_base()?);
111     delete
112       .set_context(activitystreams::context())
113       .set_id(generate_activity_id(DeleteType::Delete)?)
114       .set_to(public())
115       .set_many_ccs(vec![self.get_followers_url()?]);
116
117     let mut undo = Undo::new(creator.actor_id.to_owned(), delete.into_any_base()?);
118     undo
119       .set_context(activitystreams::context())
120       .set_id(generate_activity_id(UndoType::Undo)?)
121       .set_to(public())
122       .set_many_ccs(vec![self.get_followers_url()?]);
123
124     send_to_community_followers(undo, self, context).await?;
125     Ok(())
126   }
127
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()?);
131     remove
132       .set_context(activitystreams::context())
133       .set_id(generate_activity_id(RemoveType::Remove)?)
134       .set_to(public())
135       .set_many_ccs(vec![self.get_followers_url()?]);
136
137     send_to_community_followers(remove, self, context).await?;
138     Ok(())
139   }
140
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()?);
144     remove
145       .set_context(activitystreams::context())
146       .set_id(generate_activity_id(RemoveType::Remove)?)
147       .set_to(public())
148       .set_many_ccs(vec![self.get_followers_url()?]);
149
150     // Undo that fake activity
151     let mut undo = Undo::new(mod_.actor_id.to_owned(), remove.into_any_base()?);
152     undo
153       .set_context(activitystreams::context())
154       .set_id(generate_activity_id(LikeType::Like)?)
155       .set_to(public())
156       .set_many_ccs(vec![self.get_followers_url()?]);
157
158     send_to_community_followers(undo, self, context).await?;
159     Ok(())
160   }
161
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(
165     &self,
166     activity: AnyBase,
167     context: &LemmyContext,
168   ) -> Result<(), LemmyError> {
169     let mut announce = Announce::new(self.actor_id.to_owned(), activity);
170     announce
171       .set_context(activitystreams::context())
172       .set_id(generate_activity_id(AnnounceType::Announce)?)
173       .set_to(public())
174       .set_many_ccs(vec![self.get_followers_url()?]);
175
176     send_to_community_followers(announce, self, context).await?;
177
178     Ok(())
179   }
180
181   /// For a given community, returns the inboxes of all followers.
182   ///
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> {
186     let id = self.id;
187
188     let inboxes = blocking(pool, move |conn| {
189       CommunityFollowerView::for_community(conn, id)
190     })
191     .await??;
192     let inboxes = inboxes
193       .into_iter()
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() {
199           format!(":{}", port)
200         } else {
201           "".to_string()
202         };
203         Ok(Url::parse(&format!(
204           "{}://{}{}/inbox",
205           Settings::get().get_protocol_string(),
206           domain,
207           port,
208         ))?)
209       })
210       .filter_map(Result::ok)
211       // Don't send to blocked instances
212       .filter(|inbox| check_is_apub_id_valid(inbox).is_ok())
213       .unique()
214       .collect();
215
216     Ok(inboxes)
217   }
218 }