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