]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/send/community.rs
3e77248f800d1163903aa930021996db47dfe4f9
[lemmy.git] / crates / 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   extensions::context::lemmy_context,
6   fetcher::user::get_or_fetch_and_upsert_user,
7   ActorType,
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_api_structs::blocking;
27 use lemmy_db_queries::DbPool;
28 use lemmy_db_schema::source::community::Community;
29 use lemmy_db_views_actor::community_follower_view::CommunityFollowerView;
30 use lemmy_utils::{location_info, LemmyError};
31 use lemmy_websocket::LemmyContext;
32 use url::Url;
33
34 #[async_trait::async_trait(?Send)]
35 impl ActorType for Community {
36   fn is_local(&self) -> bool {
37     self.local
38   }
39   fn actor_id(&self) -> Url {
40     self.actor_id.to_owned().into_inner()
41   }
42   fn public_key(&self) -> Option<String> {
43     self.public_key.to_owned()
44   }
45   fn private_key(&self) -> Option<String> {
46     self.private_key.to_owned()
47   }
48
49   fn get_shared_inbox_or_inbox_url(&self) -> Url {
50     self
51       .shared_inbox_url
52       .clone()
53       .unwrap_or_else(|| self.inbox_url.to_owned())
54       .into()
55   }
56
57   async fn send_follow(
58     &self,
59     _follow_actor_id: &Url,
60     _context: &LemmyContext,
61   ) -> Result<(), LemmyError> {
62     unimplemented!()
63   }
64
65   async fn send_unfollow(
66     &self,
67     _follow_actor_id: &Url,
68     _context: &LemmyContext,
69   ) -> Result<(), LemmyError> {
70     unimplemented!()
71   }
72
73   /// As a local community, accept the follow request from a remote user.
74   async fn send_accept_follow(
75     &self,
76     follow: Follow,
77     context: &LemmyContext,
78   ) -> Result<(), LemmyError> {
79     let actor_uri = follow
80       .actor()?
81       .as_single_xsd_any_uri()
82       .context(location_info!())?;
83     let user = get_or_fetch_and_upsert_user(actor_uri, context, &mut 0).await?;
84
85     let mut accept = Accept::new(
86       self.actor_id.to_owned().into_inner(),
87       follow.into_any_base()?,
88     );
89     accept
90       .set_many_contexts(lemmy_context()?)
91       .set_id(generate_activity_id(AcceptType::Accept)?)
92       .set_to(user.actor_id());
93
94     send_activity_single_dest(accept, self, user.inbox_url.into(), context).await?;
95     Ok(())
96   }
97
98   /// If the creator of a community deletes the community, send this to all followers.
99   async fn send_delete(&self, context: &LemmyContext) -> Result<(), LemmyError> {
100     let mut delete = Delete::new(self.actor_id(), self.actor_id());
101     delete
102       .set_many_contexts(lemmy_context()?)
103       .set_id(generate_activity_id(DeleteType::Delete)?)
104       .set_to(public())
105       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
106
107     send_to_community_followers(delete, self, context).await?;
108     Ok(())
109   }
110
111   /// If the creator of a community reverts the deletion of a community, send this to all followers.
112   async fn send_undo_delete(&self, context: &LemmyContext) -> Result<(), LemmyError> {
113     let mut delete = Delete::new(self.actor_id(), self.actor_id());
114     delete
115       .set_many_contexts(lemmy_context()?)
116       .set_id(generate_activity_id(DeleteType::Delete)?)
117       .set_to(public())
118       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
119
120     let mut undo = Undo::new(self.actor_id(), delete.into_any_base()?);
121     undo
122       .set_many_contexts(lemmy_context()?)
123       .set_id(generate_activity_id(UndoType::Undo)?)
124       .set_to(public())
125       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
126
127     send_to_community_followers(undo, self, context).await?;
128     Ok(())
129   }
130
131   /// If an admin removes a community, send this to all followers.
132   async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
133     let mut remove = Remove::new(self.actor_id(), self.actor_id());
134     remove
135       .set_many_contexts(lemmy_context()?)
136       .set_id(generate_activity_id(RemoveType::Remove)?)
137       .set_to(public())
138       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
139
140     send_to_community_followers(remove, self, context).await?;
141     Ok(())
142   }
143
144   /// If an admin reverts the removal of a community, send this to all followers.
145   async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> {
146     let mut remove = Remove::new(self.actor_id(), self.actor_id());
147     remove
148       .set_many_contexts(lemmy_context()?)
149       .set_id(generate_activity_id(RemoveType::Remove)?)
150       .set_to(public())
151       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
152
153     // Undo that fake activity
154     let mut undo = Undo::new(self.actor_id(), remove.into_any_base()?);
155     undo
156       .set_many_contexts(lemmy_context()?)
157       .set_id(generate_activity_id(LikeType::Like)?)
158       .set_to(public())
159       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
160
161     send_to_community_followers(undo, self, context).await?;
162     Ok(())
163   }
164
165   /// Wraps an activity sent to the community in an announce, and then sends the announce to all
166   /// community followers.
167   async fn send_announce(
168     &self,
169     activity: AnyBase,
170     context: &LemmyContext,
171   ) -> Result<(), LemmyError> {
172     let mut announce = Announce::new(self.actor_id.to_owned().into_inner(), activity);
173     announce
174       .set_many_contexts(lemmy_context()?)
175       .set_id(generate_activity_id(AnnounceType::Announce)?)
176       .set_to(public())
177       .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
178
179     send_to_community_followers(announce, self, context).await?;
180
181     Ok(())
182   }
183
184   /// For a given community, returns the inboxes of all followers.
185   async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
186     let id = self.id;
187
188     let follows = blocking(pool, move |conn| {
189       CommunityFollowerView::for_community(conn, id)
190     })
191     .await??;
192     let inboxes = follows
193       .into_iter()
194       .filter(|f| !f.follower.local)
195       .map(|f| f.follower.shared_inbox_url.unwrap_or(f.follower.inbox_url))
196       .map(|i| i.into_inner())
197       .unique()
198       // Don't send to blocked instances
199       .filter(|inbox| check_is_apub_id_valid(inbox).is_ok())
200       .collect();
201
202     Ok(inboxes)
203   }
204 }