]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/community/add_mod.rs
Pleroma federation2 (#1855)
[lemmy.git] / crates / apub / src / activities / community / add_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   migrations::PublicUrlMigration,
14   objects::{community::ApubCommunity, person::ApubPerson},
15 };
16 use activitystreams::{
17   activity::kind::AddType,
18   base::AnyBase,
19   primitives::OneOrMany,
20   unparsed::Unparsed,
21 };
22 use lemmy_api_common::blocking;
23 use lemmy_apub_lib::{
24   data::Data,
25   traits::{ActivityFields, ActivityHandler, ActorType},
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 AddMod {
39   actor: ObjectId<ApubPerson>,
40   to: PublicUrlMigration,
41   object: ObjectId<ApubPerson>,
42   target: Url,
43   cc: [ObjectId<ApubCommunity>; 1],
44   #[serde(rename = "type")]
45   kind: AddType,
46   id: Url,
47   #[serde(rename = "@context")]
48   context: OneOrMany<AnyBase>,
49   #[serde(flatten)]
50   unparsed: Unparsed,
51 }
52
53 impl AddMod {
54   pub async fn send(
55     community: &ApubCommunity,
56     added_mod: &ApubPerson,
57     actor: &ApubPerson,
58     context: &LemmyContext,
59   ) -> Result<(), LemmyError> {
60     let id = generate_activity_id(
61       AddType::Add,
62       &context.settings().get_protocol_and_hostname(),
63     )?;
64     let add = AddMod {
65       actor: ObjectId::new(actor.actor_id()),
66       to: PublicUrlMigration::create(),
67       object: ObjectId::new(added_mod.actor_id()),
68       target: generate_moderators_url(&community.actor_id)?.into(),
69       cc: [ObjectId::new(community.actor_id())],
70       kind: AddType::Add,
71       id: id.clone(),
72       context: lemmy_context(),
73       unparsed: Default::default(),
74     };
75
76     let activity = AnnouncableActivities::AddMod(add);
77     let inboxes = vec![added_mod.shared_inbox_or_inbox_url()];
78     send_to_community(activity, &id, actor, community, inboxes, context).await
79   }
80 }
81
82 #[async_trait::async_trait(?Send)]
83 impl ActivityHandler for AddMod {
84   type DataType = LemmyContext;
85
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 new_mod = self.object.dereference(context, request_counter).await?;
105
106     // If we had to refetch the community while parsing the activity, then the new mod has already
107     // been added. Skip it here as it would result in a duplicate key error.
108     let new_mod_id = new_mod.id;
109     let moderated_communities = blocking(context.pool(), move |conn| {
110       CommunityModerator::get_person_moderated_communities(conn, new_mod_id)
111     })
112     .await??;
113     if !moderated_communities.contains(&community.id) {
114       let form = CommunityModeratorForm {
115         community_id: community.id,
116         person_id: new_mod.id,
117       };
118       blocking(context.pool(), move |conn| {
119         CommunityModerator::join(conn, &form)
120       })
121       .await??;
122     }
123     // TODO: send websocket notification about added mod
124     Ok(())
125   }
126 }