]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/community/remove_mod.rs
Breaking apub changes (#1859)
[lemmy.git] / crates / apub / src / activities / community / remove_mod.rs
1 use crate::{
2   activities::{
3     community::{announce::AnnouncableActivities, send_to_community},
4     generate_activity_id,
5     verify_activity,
6     verify_add_remove_moderator_target,
7     verify_mod_action,
8     verify_person_in_community,
9   },
10   context::lemmy_context,
11   fetcher::object_id::ObjectId,
12   generate_moderators_url,
13   objects::{community::ApubCommunity, person::ApubPerson},
14 };
15 use activitystreams::{
16   activity::kind::RemoveType,
17   base::AnyBase,
18   primitives::OneOrMany,
19   unparsed::Unparsed,
20 };
21 use lemmy_api_common::blocking;
22 use lemmy_apub_lib::{
23   data::Data,
24   traits::{ActivityFields, ActivityHandler, ActorType},
25   values::PublicUrl,
26 };
27 use lemmy_db_schema::{
28   source::community::{CommunityModerator, CommunityModeratorForm},
29   traits::Joinable,
30 };
31 use lemmy_utils::LemmyError;
32 use lemmy_websocket::LemmyContext;
33 use serde::{Deserialize, Serialize};
34 use url::Url;
35
36 #[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
37 #[serde(rename_all = "camelCase")]
38 pub struct RemoveMod {
39   actor: ObjectId<ApubPerson>,
40   to: [PublicUrl; 1],
41   pub(in crate::activities) object: ObjectId<ApubPerson>,
42   cc: [ObjectId<ApubCommunity>; 1],
43   #[serde(rename = "type")]
44   kind: RemoveType,
45   // if target is set, this is means remove mod from community
46   pub(in crate::activities) target: Url,
47   id: Url,
48   #[serde(rename = "@context")]
49   context: OneOrMany<AnyBase>,
50   #[serde(flatten)]
51   unparsed: Unparsed,
52 }
53
54 impl RemoveMod {
55   pub async fn send(
56     community: &ApubCommunity,
57     removed_mod: &ApubPerson,
58     actor: &ApubPerson,
59     context: &LemmyContext,
60   ) -> Result<(), LemmyError> {
61     let id = generate_activity_id(
62       RemoveType::Remove,
63       &context.settings().get_protocol_and_hostname(),
64     )?;
65     let remove = RemoveMod {
66       actor: ObjectId::new(actor.actor_id()),
67       to: [PublicUrl::Public],
68       object: ObjectId::new(removed_mod.actor_id()),
69       target: generate_moderators_url(&community.actor_id)?.into(),
70       id: id.clone(),
71       context: lemmy_context(),
72       cc: [ObjectId::new(community.actor_id())],
73       kind: RemoveType::Remove,
74       unparsed: Default::default(),
75     };
76
77     let activity = AnnouncableActivities::RemoveMod(remove);
78     let inboxes = vec![removed_mod.shared_inbox_or_inbox_url()];
79     send_to_community(activity, &id, actor, community, inboxes, context).await
80   }
81 }
82
83 #[async_trait::async_trait(?Send)]
84 impl ActivityHandler for RemoveMod {
85   type DataType = LemmyContext;
86   async fn verify(
87     &self,
88     context: &Data<LemmyContext>,
89     request_counter: &mut i32,
90   ) -> Result<(), LemmyError> {
91     verify_activity(self, &context.settings())?;
92     verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
93     verify_mod_action(&self.actor, &self.cc[0], context, request_counter).await?;
94     verify_add_remove_moderator_target(&self.target, &self.cc[0])?;
95     Ok(())
96   }
97
98   async fn receive(
99     self,
100     context: &Data<LemmyContext>,
101     request_counter: &mut i32,
102   ) -> Result<(), LemmyError> {
103     let community = self.cc[0].dereference(context, request_counter).await?;
104     let remove_mod = self.object.dereference(context, request_counter).await?;
105
106     let form = CommunityModeratorForm {
107       community_id: community.id,
108       person_id: remove_mod.id,
109     };
110     blocking(context.pool(), move |conn| {
111       CommunityModerator::leave(conn, &form)
112     })
113     .await??;
114     // TODO: send websocket notification about removed mod
115     Ok(())
116   }
117 }