]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/block/mod.rs
a791ea40e74d53a1bb1967c444969a9b253ac380
[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(target: &SiteOrCommunity, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
122   Ok(match target {
123     SiteOrCommunity::Site(_) => Site::read_remote_sites(pool)
124       .await?
125       .into_iter()
126       .map(|s| s.actor_id.into())
127       .collect(),
128     SiteOrCommunity::Community(c) => vec![c.id()],
129   })
130 }
131
132 #[async_trait::async_trait]
133 impl SendActivity for BanPerson {
134   type Response = BanPersonResponse;
135
136   async fn send_activity(
137     request: &Self,
138     _response: &Self::Response,
139     context: &Data<LemmyContext>,
140   ) -> Result<(), LemmyError> {
141     let local_user_view = local_user_view_from_jwt(&request.auth, context).await?;
142     let person = Person::read(context.pool(), request.person_id).await?;
143     let site = SiteOrCommunity::Site(SiteView::read_local(context.pool()).await?.site.into());
144     let expires = request.expires.map(naive_from_unix);
145
146     // if the action affects a local user, federate to other instances
147     if person.local {
148       if request.ban {
149         BlockUser::send(
150           &site,
151           &person.into(),
152           &local_user_view.person.into(),
153           request.remove_data.unwrap_or(false),
154           request.reason.clone(),
155           expires,
156           context,
157         )
158         .await
159       } else {
160         UndoBlockUser::send(
161           &site,
162           &person.into(),
163           &local_user_view.person.into(),
164           request.reason.clone(),
165           context,
166         )
167         .await
168       }
169     } else {
170       Ok(())
171     }
172   }
173 }
174
175 #[async_trait::async_trait]
176 impl SendActivity for BanFromCommunity {
177   type Response = BanFromCommunityResponse;
178
179   async fn send_activity(
180     request: &Self,
181     _response: &Self::Response,
182     context: &Data<LemmyContext>,
183   ) -> Result<(), LemmyError> {
184     let local_user_view = local_user_view_from_jwt(&request.auth, context).await?;
185     let community: ApubCommunity = Community::read(context.pool(), request.community_id)
186       .await?
187       .into();
188     let banned_person: ApubPerson = Person::read(context.pool(), request.person_id)
189       .await?
190       .into();
191     let expires = request.expires.map(naive_from_unix);
192
193     if request.ban {
194       BlockUser::send(
195         &SiteOrCommunity::Community(community),
196         &banned_person,
197         &local_user_view.person.clone().into(),
198         request.remove_data.unwrap_or(false),
199         request.reason.clone(),
200         expires,
201         context,
202       )
203       .await
204     } else {
205       UndoBlockUser::send(
206         &SiteOrCommunity::Community(community),
207         &banned_person,
208         &local_user_view.person.clone().into(),
209         request.reason.clone(),
210         context,
211       )
212       .await
213     }
214   }
215 }