]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/community/add_mod.rs
Rewrite remaining activities (#1712)
[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::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person},
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: Url,
38   to: PublicUrl,
39   object: Url,
40   target: Url,
41   cc: [Url; 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: actor.actor_id(),
61       to: PublicUrl::Public,
62       object: added_mod.actor_id(),
63       target: generate_moderators_url(&community.actor_id)?.into(),
64       cc: [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].clone())?;
88     Ok(())
89   }
90
91   async fn receive(
92     self,
93     context: &LemmyContext,
94     request_counter: &mut i32,
95   ) -> Result<(), LemmyError> {
96     let community =
97       get_or_fetch_and_upsert_community(&self.cc[0], context, request_counter).await?;
98     let new_mod = get_or_fetch_and_upsert_person(&self.object, context, request_counter).await?;
99
100     // If we had to refetch the community while parsing the activity, then the new mod has already
101     // been added. Skip it here as it would result in a duplicate key error.
102     let new_mod_id = new_mod.id;
103     let moderated_communities = blocking(context.pool(), move |conn| {
104       CommunityModerator::get_person_moderated_communities(conn, new_mod_id)
105     })
106     .await??;
107     if !moderated_communities.contains(&community.id) {
108       let form = CommunityModeratorForm {
109         community_id: community.id,
110         person_id: new_mod.id,
111       };
112       blocking(context.pool(), move |conn| {
113         CommunityModerator::join(conn, &form)
114       })
115       .await??;
116     }
117     // TODO: send websocket notification about added mod
118     Ok(())
119   }
120 }