]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/send/community.rs
Merge pull request #1328 from LemmyNet/move_views_to_diesel
[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_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;
32 use url::Url;
33
34 #[async_trait::async_trait(?Send)]
35 impl ActorType for Community {
36   fn actor_id_str(&self) -> String {
37     self.actor_id.to_owned()
38   }
39
40   fn public_key(&self) -> Option<String> {
41     self.public_key.to_owned()
42   }
43   fn private_key(&self) -> Option<String> {
44     self.private_key.to_owned()
45   }
46
47   async fn send_follow(
48     &self,
49     _follow_actor_id: &Url,
50     _context: &LemmyContext,
51   ) -> Result<(), LemmyError> {
52     unimplemented!()
53   }
54
55   async fn send_unfollow(
56     &self,
57     _follow_actor_id: &Url,
58     _context: &LemmyContext,
59   ) -> Result<(), LemmyError> {
60     unimplemented!()
61   }
62
63   /// As a local community, accept the follow request from a remote user.
64   async fn send_accept_follow(
65     &self,
66     follow: Follow,
67     context: &LemmyContext,
68   ) -> Result<(), LemmyError> {
69     let actor_uri = follow
70       .actor()?
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?;
74
75     let mut accept = Accept::new(self.actor_id.to_owned(), follow.into_any_base()?);
76     accept
77       .set_many_contexts(lemmy_context()?)
78       .set_id(generate_activity_id(AcceptType::Accept)?)
79       .set_to(user.actor_id()?);
80
81     send_activity_single_dest(accept, self, user.get_inbox_url()?, context).await?;
82     Ok(())
83   }
84
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()?);
88     delete
89       .set_many_contexts(lemmy_context()?)
90       .set_id(generate_activity_id(DeleteType::Delete)?)
91       .set_to(public())
92       .set_many_ccs(vec![self.get_followers_url()?]);
93
94     send_to_community_followers(delete, self, context).await?;
95     Ok(())
96   }
97
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()?);
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.get_followers_url()?]);
106
107     let mut undo = Undo::new(self.actor_id()?, delete.into_any_base()?);
108     undo
109       .set_many_contexts(lemmy_context()?)
110       .set_id(generate_activity_id(UndoType::Undo)?)
111       .set_to(public())
112       .set_many_ccs(vec![self.get_followers_url()?]);
113
114     send_to_community_followers(undo, self, context).await?;
115     Ok(())
116   }
117
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()?);
121     remove
122       .set_many_contexts(lemmy_context()?)
123       .set_id(generate_activity_id(RemoveType::Remove)?)
124       .set_to(public())
125       .set_many_ccs(vec![self.get_followers_url()?]);
126
127     send_to_community_followers(remove, self, context).await?;
128     Ok(())
129   }
130
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()?);
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.get_followers_url()?]);
139
140     // Undo that fake activity
141     let mut undo = Undo::new(self.actor_id()?, remove.into_any_base()?);
142     undo
143       .set_many_contexts(lemmy_context()?)
144       .set_id(generate_activity_id(LikeType::Like)?)
145       .set_to(public())
146       .set_many_ccs(vec![self.get_followers_url()?]);
147
148     send_to_community_followers(undo, self, context).await?;
149     Ok(())
150   }
151
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(
155     &self,
156     activity: AnyBase,
157     context: &LemmyContext,
158   ) -> Result<(), LemmyError> {
159     let mut announce = Announce::new(self.actor_id.to_owned(), activity);
160     announce
161       .set_many_contexts(lemmy_context()?)
162       .set_id(generate_activity_id(AnnounceType::Announce)?)
163       .set_to(public())
164       .set_many_ccs(vec![self.get_followers_url()?]);
165
166     send_to_community_followers(announce, self, context).await?;
167
168     Ok(())
169   }
170
171   /// For a given community, returns the inboxes of all followers.
172   ///
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> {
176     let id = self.id;
177
178     let inboxes = blocking(pool, move |conn| {
179       CommunityFollowerView::for_community(conn, id)
180     })
181     .await??;
182     let inboxes = inboxes
183       .into_iter()
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() {
189           format!(":{}", port)
190         } else {
191           "".to_string()
192         };
193         Ok(Url::parse(&format!(
194           "{}://{}{}/inbox",
195           Settings::get().get_protocol_string(),
196           domain,
197           port,
198         ))?)
199       })
200       .filter_map(Result::ok)
201       // Don't send to blocked instances
202       .filter(|inbox| check_is_apub_id_valid(inbox).is_ok())
203       .unique()
204       .collect();
205
206     Ok(inboxes)
207   }
208 }