]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/block/mod.rs
Make functions work with both connection and pool (#3420)
[lemmy.git] / crates / apub / src / activities / block / mod.rs
1 use crate::{
2   objects::{community::ApubCommunity, instance::ApubSite, person::ApubPerson},
3   protocol::{
4     activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
5     objects::{group::Group, instance::Instance},
6   },
7   SendActivity,
8 };
9 use activitypub_federation::{
10   config::Data,
11   fetch::object_id::ObjectId,
12   traits::{Actor, Object},
13 };
14 use chrono::NaiveDateTime;
15 use lemmy_api_common::{
16   community::{BanFromCommunity, BanFromCommunityResponse},
17   context::LemmyContext,
18   person::{BanPerson, BanPersonResponse},
19   utils::local_user_view_from_jwt,
20 };
21 use lemmy_db_schema::{
22   source::{community::Community, person::Person, site::Site},
23   traits::Crud,
24   utils::DbPool,
25 };
26 use lemmy_db_views::structs::SiteView;
27 use lemmy_utils::{error::LemmyError, utils::time::naive_from_unix};
28 use serde::Deserialize;
29 use url::Url;
30
31 pub mod block_user;
32 pub mod undo_block_user;
33
34 #[derive(Clone, Debug)]
35 pub enum SiteOrCommunity {
36   Site(ApubSite),
37   Community(ApubCommunity),
38 }
39
40 #[derive(Deserialize)]
41 #[serde(untagged)]
42 pub enum InstanceOrGroup {
43   Instance(Instance),
44   Group(Group),
45 }
46
47 #[async_trait::async_trait]
48 impl Object for SiteOrCommunity {
49   type DataType = LemmyContext;
50   type Kind = InstanceOrGroup;
51   type Error = LemmyError;
52
53   #[tracing::instrument(skip_all)]
54   fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
55     Some(match self {
56       SiteOrCommunity::Site(i) => i.last_refreshed_at,
57       SiteOrCommunity::Community(c) => c.last_refreshed_at,
58     })
59   }
60
61   #[tracing::instrument(skip_all)]
62   async fn read_from_id(
63     object_id: Url,
64     data: &Data<Self::DataType>,
65   ) -> Result<Option<Self>, LemmyError>
66   where
67     Self: Sized,
68   {
69     let site = ApubSite::read_from_id(object_id.clone(), data).await?;
70     Ok(match site {
71       Some(o) => Some(SiteOrCommunity::Site(o)),
72       None => ApubCommunity::read_from_id(object_id, data)
73         .await?
74         .map(SiteOrCommunity::Community),
75     })
76   }
77
78   async fn delete(self, _data: &Data<Self::DataType>) -> Result<(), LemmyError> {
79     unimplemented!()
80   }
81
82   async fn into_json(self, _data: &Data<Self::DataType>) -> Result<Self::Kind, LemmyError> {
83     unimplemented!()
84   }
85
86   #[tracing::instrument(skip_all)]
87   async fn verify(
88     apub: &Self::Kind,
89     expected_domain: &Url,
90     data: &Data<Self::DataType>,
91   ) -> Result<(), LemmyError> {
92     match apub {
93       InstanceOrGroup::Instance(i) => ApubSite::verify(i, expected_domain, data).await,
94       InstanceOrGroup::Group(g) => ApubCommunity::verify(g, expected_domain, data).await,
95     }
96   }
97
98   #[tracing::instrument(skip_all)]
99   async fn from_json(apub: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, LemmyError>
100   where
101     Self: Sized,
102   {
103     Ok(match apub {
104       InstanceOrGroup::Instance(p) => SiteOrCommunity::Site(ApubSite::from_json(p, data).await?),
105       InstanceOrGroup::Group(n) => {
106         SiteOrCommunity::Community(ApubCommunity::from_json(n, data).await?)
107       }
108     })
109   }
110 }
111
112 impl SiteOrCommunity {
113   fn id(&self) -> ObjectId<SiteOrCommunity> {
114     match self {
115       SiteOrCommunity::Site(s) => ObjectId::from(s.actor_id.clone()),
116       SiteOrCommunity::Community(c) => ObjectId::from(c.actor_id.clone()),
117     }
118   }
119 }
120
121 async fn generate_cc(
122   target: &SiteOrCommunity,
123   pool: &mut DbPool<'_>,
124 ) -> Result<Vec<Url>, LemmyError> {
125   Ok(match target {
126     SiteOrCommunity::Site(_) => Site::read_remote_sites(pool)
127       .await?
128       .into_iter()
129       .map(|s| s.actor_id.into())
130       .collect(),
131     SiteOrCommunity::Community(c) => vec![c.id()],
132   })
133 }
134
135 #[async_trait::async_trait]
136 impl SendActivity for BanPerson {
137   type Response = BanPersonResponse;
138
139   async fn send_activity(
140     request: &Self,
141     _response: &Self::Response,
142     context: &Data<LemmyContext>,
143   ) -> Result<(), LemmyError> {
144     let local_user_view = local_user_view_from_jwt(&request.auth, context).await?;
145     let person = Person::read(&mut context.pool(), request.person_id).await?;
146     let site = SiteOrCommunity::Site(SiteView::read_local(&mut context.pool()).await?.site.into());
147     let expires = request.expires.map(naive_from_unix);
148
149     // if the action affects a local user, federate to other instances
150     if person.local {
151       if request.ban {
152         BlockUser::send(
153           &site,
154           &person.into(),
155           &local_user_view.person.into(),
156           request.remove_data.unwrap_or(false),
157           request.reason.clone(),
158           expires,
159           context,
160         )
161         .await
162       } else {
163         UndoBlockUser::send(
164           &site,
165           &person.into(),
166           &local_user_view.person.into(),
167           request.reason.clone(),
168           context,
169         )
170         .await
171       }
172     } else {
173       Ok(())
174     }
175   }
176 }
177
178 #[async_trait::async_trait]
179 impl SendActivity for BanFromCommunity {
180   type Response = BanFromCommunityResponse;
181
182   async fn send_activity(
183     request: &Self,
184     _response: &Self::Response,
185     context: &Data<LemmyContext>,
186   ) -> Result<(), LemmyError> {
187     let local_user_view = local_user_view_from_jwt(&request.auth, context).await?;
188     let community: ApubCommunity = Community::read(&mut context.pool(), request.community_id)
189       .await?
190       .into();
191     let banned_person: ApubPerson = Person::read(&mut context.pool(), request.person_id)
192       .await?
193       .into();
194     let expires = request.expires.map(naive_from_unix);
195
196     if request.ban {
197       BlockUser::send(
198         &SiteOrCommunity::Community(community),
199         &banned_person,
200         &local_user_view.person.clone().into(),
201         request.remove_data.unwrap_or(false),
202         request.reason.clone(),
203         expires,
204         context,
205       )
206       .await
207     } else {
208       UndoBlockUser::send(
209         &SiteOrCommunity::Community(community),
210         &banned_person,
211         &local_user_view.person.clone().into(),
212         request.reason.clone(),
213         context,
214       )
215       .await
216     }
217   }
218 }