]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/block/undo_block_user.rs
cd9784f3213b6962726f7399b5626a9268c1263b
[lemmy.git] / crates / apub / src / activities / block / undo_block_user.rs
1 use crate::{
2   activities::{
3     block::{generate_cc, SiteOrCommunity},
4     community::{announce::GetCommunity, send_activity_in_community},
5     generate_activity_id,
6     send_lemmy_activity,
7     verify_is_public,
8   },
9   activity_lists::AnnouncableActivities,
10   local_instance,
11   objects::{community::ApubCommunity, instance::remote_instance_inboxes, person::ApubPerson},
12   protocol::activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
13   ActorType,
14 };
15 use activitypub_federation::{
16   core::object_id::ObjectId,
17   data::Data,
18   traits::{ActivityHandler, Actor},
19   utils::verify_domains_match,
20 };
21 use activitystreams_kinds::{activity::UndoType, public};
22 use lemmy_api_common::utils::blocking;
23 use lemmy_db_schema::{
24   source::{
25     community::{CommunityPersonBan, CommunityPersonBanForm},
26     moderator::{ModBan, ModBanForm, ModBanFromCommunity, ModBanFromCommunityForm},
27     person::{Person, PersonUpdateForm},
28   },
29   traits::{Bannable, Crud},
30 };
31 use lemmy_utils::error::LemmyError;
32 use lemmy_websocket::LemmyContext;
33 use url::Url;
34
35 impl UndoBlockUser {
36   #[tracing::instrument(skip_all)]
37   pub async fn send(
38     target: &SiteOrCommunity,
39     user: &ApubPerson,
40     mod_: &ApubPerson,
41     reason: Option<String>,
42     context: &LemmyContext,
43   ) -> Result<(), LemmyError> {
44     let block = BlockUser::new(target, user, mod_, None, reason, None, context).await?;
45
46     let id = generate_activity_id(
47       UndoType::Undo,
48       &context.settings().get_protocol_and_hostname(),
49     )?;
50     let undo = UndoBlockUser {
51       actor: ObjectId::new(mod_.actor_id()),
52       to: vec![public()],
53       object: block,
54       cc: generate_cc(target, context.pool()).await?,
55       kind: UndoType::Undo,
56       id: id.clone(),
57       unparsed: Default::default(),
58     };
59
60     let mut inboxes = vec![user.shared_inbox_or_inbox()];
61     match target {
62       SiteOrCommunity::Site(_) => {
63         inboxes.append(&mut remote_instance_inboxes(context.pool()).await?);
64         send_lemmy_activity(context, undo, mod_, inboxes, false).await
65       }
66       SiteOrCommunity::Community(c) => {
67         let activity = AnnouncableActivities::UndoBlockUser(undo);
68         send_activity_in_community(activity, mod_, c, inboxes, context).await
69       }
70     }
71   }
72 }
73
74 #[async_trait::async_trait(?Send)]
75 impl ActivityHandler for UndoBlockUser {
76   type DataType = LemmyContext;
77   type Error = LemmyError;
78
79   fn id(&self) -> &Url {
80     &self.id
81   }
82
83   fn actor(&self) -> &Url {
84     self.actor.inner()
85   }
86
87   #[tracing::instrument(skip_all)]
88   async fn verify(
89     &self,
90     context: &Data<LemmyContext>,
91     request_counter: &mut i32,
92   ) -> Result<(), LemmyError> {
93     verify_is_public(&self.to, &self.cc)?;
94     verify_domains_match(self.actor.inner(), self.object.actor.inner())?;
95     self.object.verify(context, request_counter).await?;
96     Ok(())
97   }
98
99   #[tracing::instrument(skip_all)]
100   async fn receive(
101     self,
102     context: &Data<LemmyContext>,
103     request_counter: &mut i32,
104   ) -> Result<(), LemmyError> {
105     let instance = local_instance(context);
106     let expires = self.object.expires.map(|u| u.naive_local());
107     let mod_person = self
108       .actor
109       .dereference(context, instance, request_counter)
110       .await?;
111     let blocked_person = self
112       .object
113       .object
114       .dereference(context, instance, request_counter)
115       .await?;
116     match self
117       .object
118       .target
119       .dereference(context, instance, request_counter)
120       .await?
121     {
122       SiteOrCommunity::Site(_site) => {
123         let blocked_person = blocking(context.pool(), move |conn| {
124           Person::update(
125             conn,
126             blocked_person.id,
127             &PersonUpdateForm::builder()
128               .banned(Some(false))
129               .ban_expires(Some(expires))
130               .build(),
131           )
132         })
133         .await??;
134
135         // write mod log
136         let form = ModBanForm {
137           mod_person_id: mod_person.id,
138           other_person_id: blocked_person.id,
139           reason: self.object.summary,
140           banned: Some(false),
141           expires,
142         };
143         blocking(context.pool(), move |conn| ModBan::create(conn, &form)).await??;
144       }
145       SiteOrCommunity::Community(community) => {
146         let community_user_ban_form = CommunityPersonBanForm {
147           community_id: community.id,
148           person_id: blocked_person.id,
149           expires: None,
150         };
151         blocking(context.pool(), move |conn: &mut _| {
152           CommunityPersonBan::unban(conn, &community_user_ban_form)
153         })
154         .await??;
155
156         // write to mod log
157         let form = ModBanFromCommunityForm {
158           mod_person_id: mod_person.id,
159           other_person_id: blocked_person.id,
160           community_id: community.id,
161           reason: self.object.summary,
162           banned: Some(false),
163           expires,
164         };
165         blocking(context.pool(), move |conn| {
166           ModBanFromCommunity::create(conn, &form)
167         })
168         .await??;
169       }
170     }
171
172     Ok(())
173   }
174 }
175
176 #[async_trait::async_trait(?Send)]
177 impl GetCommunity for UndoBlockUser {
178   #[tracing::instrument(skip_all)]
179   async fn get_community(
180     &self,
181     context: &LemmyContext,
182     request_counter: &mut i32,
183   ) -> Result<ApubCommunity, LemmyError> {
184     self.object.get_community(context, request_counter).await
185   }
186 }