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