]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/community/block_user.rs
Activity.to should always be a vec (and unspecified size for public activities)
[lemmy.git] / crates / apub / src / activities / community / block_user.rs
1 use crate::{
2   activities::{
3     community::{announce::AnnouncableActivities, send_to_community},
4     generate_activity_id,
5     verify_activity,
6     verify_is_public,
7     verify_mod_action,
8     verify_person_in_community,
9   },
10   context::lemmy_context,
11   fetcher::object_id::ObjectId,
12   objects::{community::ApubCommunity, person::ApubPerson},
13 };
14 use activitystreams::{
15   activity::kind::BlockType,
16   base::AnyBase,
17   primitives::OneOrMany,
18   public,
19   unparsed::Unparsed,
20 };
21 use lemmy_api_common::blocking;
22 use lemmy_apub_lib::{
23   data::Data,
24   traits::{ActivityFields, ActivityHandler, ActorType},
25 };
26 use lemmy_db_schema::{
27   source::community::{
28     CommunityFollower,
29     CommunityFollowerForm,
30     CommunityPersonBan,
31     CommunityPersonBanForm,
32   },
33   traits::{Bannable, Followable},
34 };
35 use lemmy_utils::LemmyError;
36 use lemmy_websocket::LemmyContext;
37 use serde::{Deserialize, Serialize};
38 use url::Url;
39
40 #[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
41 #[serde(rename_all = "camelCase")]
42 pub struct BlockUserFromCommunity {
43   actor: ObjectId<ApubPerson>,
44   to: Vec<Url>,
45   pub(in crate::activities::community) object: ObjectId<ApubPerson>,
46   cc: [ObjectId<ApubCommunity>; 1],
47   #[serde(rename = "type")]
48   kind: BlockType,
49   id: Url,
50   #[serde(rename = "@context")]
51   context: OneOrMany<AnyBase>,
52   #[serde(flatten)]
53   unparsed: Unparsed,
54 }
55
56 impl BlockUserFromCommunity {
57   pub(in crate::activities::community) fn new(
58     community: &ApubCommunity,
59     target: &ApubPerson,
60     actor: &ApubPerson,
61     context: &LemmyContext,
62   ) -> Result<BlockUserFromCommunity, LemmyError> {
63     Ok(BlockUserFromCommunity {
64       actor: ObjectId::new(actor.actor_id()),
65       to: vec![public()],
66       object: ObjectId::new(target.actor_id()),
67       cc: [ObjectId::new(community.actor_id())],
68       kind: BlockType::Block,
69       id: generate_activity_id(
70         BlockType::Block,
71         &context.settings().get_protocol_and_hostname(),
72       )?,
73       context: lemmy_context(),
74       unparsed: Default::default(),
75     })
76   }
77
78   pub async fn send(
79     community: &ApubCommunity,
80     target: &ApubPerson,
81     actor: &ApubPerson,
82     context: &LemmyContext,
83   ) -> Result<(), LemmyError> {
84     let block = BlockUserFromCommunity::new(community, target, actor, context)?;
85     let block_id = block.id.clone();
86
87     let activity = AnnouncableActivities::BlockUserFromCommunity(block);
88     let inboxes = vec![target.shared_inbox_or_inbox_url()];
89     send_to_community(activity, &block_id, actor, community, inboxes, context).await
90   }
91 }
92
93 #[async_trait::async_trait(?Send)]
94 impl ActivityHandler for BlockUserFromCommunity {
95   type DataType = LemmyContext;
96   async fn verify(
97     &self,
98     context: &Data<LemmyContext>,
99     request_counter: &mut i32,
100   ) -> Result<(), LemmyError> {
101     verify_is_public(&self.to)?;
102     verify_activity(self, &context.settings())?;
103     verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
104     verify_mod_action(&self.actor, &self.cc[0], context, request_counter).await?;
105     Ok(())
106   }
107
108   async fn receive(
109     self,
110     context: &Data<LemmyContext>,
111     request_counter: &mut i32,
112   ) -> Result<(), LemmyError> {
113     let community = self.cc[0].dereference(context, request_counter).await?;
114     let blocked_user = self.object.dereference(context, request_counter).await?;
115
116     let community_user_ban_form = CommunityPersonBanForm {
117       community_id: community.id,
118       person_id: blocked_user.id,
119     };
120
121     blocking(context.pool(), move |conn: &'_ _| {
122       CommunityPersonBan::ban(conn, &community_user_ban_form)
123     })
124     .await??;
125
126     // Also unsubscribe them from the community, if they are subscribed
127     let community_follower_form = CommunityFollowerForm {
128       community_id: community.id,
129       person_id: blocked_user.id,
130       pending: false,
131     };
132     blocking(context.pool(), move |conn: &'_ _| {
133       CommunityFollower::unfollow(conn, &community_follower_form)
134     })
135     .await?
136     .ok();
137
138     Ok(())
139   }
140 }