]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/block/undo_block_user.rs
ee6f631aee0a137747898850bce7d8b01a0fae21
[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,
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::ban_person(conn, blocked_person.id, false, expires)
125         })
126         .await??;
127
128         // write mod log
129         let form = ModBanForm {
130           mod_person_id: mod_person.id,
131           other_person_id: blocked_person.id,
132           reason: self.object.summary,
133           banned: Some(false),
134           expires,
135         };
136         blocking(context.pool(), move |conn| ModBan::create(conn, &form)).await??;
137       }
138       SiteOrCommunity::Community(community) => {
139         let community_user_ban_form = CommunityPersonBanForm {
140           community_id: community.id,
141           person_id: blocked_person.id,
142           expires: None,
143         };
144         blocking(context.pool(), move |conn: &mut _| {
145           CommunityPersonBan::unban(conn, &community_user_ban_form)
146         })
147         .await??;
148
149         // write to mod log
150         let form = ModBanFromCommunityForm {
151           mod_person_id: mod_person.id,
152           other_person_id: blocked_person.id,
153           community_id: community.id,
154           reason: self.object.summary,
155           banned: Some(false),
156           expires,
157         };
158         blocking(context.pool(), move |conn| {
159           ModBanFromCommunity::create(conn, &form)
160         })
161         .await??;
162       }
163     }
164
165     Ok(())
166   }
167 }
168
169 #[async_trait::async_trait(?Send)]
170 impl GetCommunity for UndoBlockUser {
171   #[tracing::instrument(skip_all)]
172   async fn get_community(
173     &self,
174     context: &LemmyContext,
175     request_counter: &mut i32,
176   ) -> Result<ApubCommunity, LemmyError> {
177     self.object.get_community(context, request_counter).await
178   }
179 }