]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/community/add_mod.rs
Rewrite fetcher (#1792)
[lemmy.git] / crates / apub / src / activities / community / add_mod.rs
1 use crate::{
2   activities::{
3     community::announce::AnnouncableActivities,
4     generate_activity_id,
5     verify_activity,
6     verify_add_remove_moderator_target,
7     verify_mod_action,
8     verify_person_in_community,
9   },
10   activity_queue::send_to_community_new,
11   extensions::context::lemmy_context,
12   fetcher::object_id::ObjectId,
13   generate_moderators_url,
14   ActorType,
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::{values::PublicUrl, ActivityFields, ActivityHandler};
24 use lemmy_db_queries::{source::community::CommunityModerator_, Joinable};
25 use lemmy_db_schema::source::{
26   community::{Community, CommunityModerator, CommunityModeratorForm},
27   person::Person,
28 };
29 use lemmy_utils::LemmyError;
30 use lemmy_websocket::LemmyContext;
31 use serde::{Deserialize, Serialize};
32 use url::Url;
33
34 #[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
35 #[serde(rename_all = "camelCase")]
36 pub struct AddMod {
37   actor: ObjectId<Person>,
38   to: [PublicUrl; 1],
39   object: ObjectId<Person>,
40   target: Url,
41   cc: [ObjectId<Community>; 1],
42   #[serde(rename = "type")]
43   kind: AddType,
44   id: Url,
45   #[serde(rename = "@context")]
46   context: OneOrMany<AnyBase>,
47   #[serde(flatten)]
48   unparsed: Unparsed,
49 }
50
51 impl AddMod {
52   pub async fn send(
53     community: &Community,
54     added_mod: &Person,
55     actor: &Person,
56     context: &LemmyContext,
57   ) -> Result<(), LemmyError> {
58     let id = generate_activity_id(AddType::Add)?;
59     let add = AddMod {
60       actor: ObjectId::new(actor.actor_id()),
61       to: [PublicUrl::Public],
62       object: ObjectId::new(added_mod.actor_id()),
63       target: generate_moderators_url(&community.actor_id)?.into(),
64       cc: [ObjectId::new(community.actor_id())],
65       kind: AddType::Add,
66       id: id.clone(),
67       context: lemmy_context(),
68       unparsed: Default::default(),
69     };
70
71     let activity = AnnouncableActivities::AddMod(add);
72     let inboxes = vec![added_mod.get_shared_inbox_or_inbox_url()];
73     send_to_community_new(activity, &id, actor, community, inboxes, context).await
74   }
75 }
76
77 #[async_trait::async_trait(?Send)]
78 impl ActivityHandler for AddMod {
79   async fn verify(
80     &self,
81     context: &LemmyContext,
82     request_counter: &mut i32,
83   ) -> Result<(), LemmyError> {
84     verify_activity(self)?;
85     verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
86     verify_mod_action(&self.actor, self.cc[0].clone(), context).await?;
87     verify_add_remove_moderator_target(&self.target, &self.cc[0])?;
88     Ok(())
89   }
90
91   async fn receive(
92     self,
93     context: &LemmyContext,
94     request_counter: &mut i32,
95   ) -> Result<(), LemmyError> {
96     let community = self.cc[0].dereference(context, request_counter).await?;
97     let new_mod = self.object.dereference(context, request_counter).await?;
98
99     // If we had to refetch the community while parsing the activity, then the new mod has already
100     // been added. Skip it here as it would result in a duplicate key error.
101     let new_mod_id = new_mod.id;
102     let moderated_communities = blocking(context.pool(), move |conn| {
103       CommunityModerator::get_person_moderated_communities(conn, new_mod_id)
104     })
105     .await??;
106     if !moderated_communities.contains(&community.id) {
107       let form = CommunityModeratorForm {
108         community_id: community.id,
109         person_id: new_mod.id,
110       };
111       blocking(context.pool(), move |conn| {
112         CommunityModerator::join(conn, &form)
113       })
114       .await??;
115     }
116     // TODO: send websocket notification about added mod
117     Ok(())
118   }
119 }