]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/block/undo_block_user.rs
Merge pull request #2593 from LemmyNet/refactor-notifications
[lemmy.git] / crates / apub / src / activities / block / undo_block_user.rs
1 use crate::{
2   activities::{
3     block::{generate_cc, SiteOrCommunity},
4     community::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::{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::context::LemmyContext;
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 url::Url;
33
34 impl UndoBlockUser {
35   #[tracing::instrument(skip_all)]
36   pub async fn send(
37     target: &SiteOrCommunity,
38     user: &ApubPerson,
39     mod_: &ApubPerson,
40     reason: Option<String>,
41     context: &LemmyContext,
42   ) -> Result<(), LemmyError> {
43     let block = BlockUser::new(target, user, mod_, None, reason, None, context).await?;
44     let audience = if let SiteOrCommunity::Community(c) = target {
45       Some(ObjectId::new(c.actor_id()))
46     } else {
47       None
48     };
49
50     let id = generate_activity_id(
51       UndoType::Undo,
52       &context.settings().get_protocol_and_hostname(),
53     )?;
54     let undo = UndoBlockUser {
55       actor: ObjectId::new(mod_.actor_id()),
56       to: vec![public()],
57       object: block,
58       cc: generate_cc(target, context.pool()).await?,
59       kind: UndoType::Undo,
60       id: id.clone(),
61       audience,
62     };
63
64     let mut inboxes = vec![user.shared_inbox_or_inbox()];
65     match target {
66       SiteOrCommunity::Site(_) => {
67         inboxes.append(&mut remote_instance_inboxes(context.pool()).await?);
68         send_lemmy_activity(context, undo, mod_, inboxes, false).await
69       }
70       SiteOrCommunity::Community(c) => {
71         let activity = AnnouncableActivities::UndoBlockUser(undo);
72         send_activity_in_community(activity, mod_, c, inboxes, true, context).await
73       }
74     }
75   }
76 }
77
78 #[async_trait::async_trait(?Send)]
79 impl ActivityHandler for UndoBlockUser {
80   type DataType = LemmyContext;
81   type Error = LemmyError;
82
83   fn id(&self) -> &Url {
84     &self.id
85   }
86
87   fn actor(&self) -> &Url {
88     self.actor.inner()
89   }
90
91   #[tracing::instrument(skip_all)]
92   async fn verify(
93     &self,
94     context: &Data<LemmyContext>,
95     request_counter: &mut i32,
96   ) -> Result<(), LemmyError> {
97     verify_is_public(&self.to, &self.cc)?;
98     verify_domains_match(self.actor.inner(), self.object.actor.inner())?;
99     self.object.verify(context, request_counter).await?;
100     Ok(())
101   }
102
103   #[tracing::instrument(skip_all)]
104   async fn receive(
105     self,
106     context: &Data<LemmyContext>,
107     request_counter: &mut i32,
108   ) -> Result<(), LemmyError> {
109     let instance = local_instance(context).await;
110     let expires = self.object.expires.map(|u| u.naive_local());
111     let mod_person = self
112       .actor
113       .dereference(context, instance, request_counter)
114       .await?;
115     let blocked_person = self
116       .object
117       .object
118       .dereference(context, instance, request_counter)
119       .await?;
120     match self
121       .object
122       .target
123       .dereference(context, instance, request_counter)
124       .await?
125     {
126       SiteOrCommunity::Site(_site) => {
127         let blocked_person = Person::update(
128           context.pool(),
129           blocked_person.id,
130           &PersonUpdateForm::builder()
131             .banned(Some(false))
132             .ban_expires(Some(expires))
133             .build(),
134         )
135         .await?;
136
137         // write mod log
138         let form = ModBanForm {
139           mod_person_id: mod_person.id,
140           other_person_id: blocked_person.id,
141           reason: self.object.summary,
142           banned: Some(false),
143           expires,
144         };
145         ModBan::create(context.pool(), &form).await?;
146       }
147       SiteOrCommunity::Community(community) => {
148         let community_user_ban_form = CommunityPersonBanForm {
149           community_id: community.id,
150           person_id: blocked_person.id,
151           expires: None,
152         };
153         CommunityPersonBan::unban(context.pool(), &community_user_ban_form).await?;
154
155         // write to mod log
156         let form = ModBanFromCommunityForm {
157           mod_person_id: mod_person.id,
158           other_person_id: blocked_person.id,
159           community_id: community.id,
160           reason: self.object.summary,
161           banned: Some(false),
162           expires,
163         };
164         ModBanFromCommunity::create(context.pool(), &form).await?;
165       }
166     }
167
168     Ok(())
169   }
170 }