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