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