4 announce::GetCommunity,
5 get_community_from_moderators_url,
6 send_activity_in_community,
9 verify_add_remove_moderator_target,
12 verify_person_in_community,
14 activity_lists::AnnouncableActivities,
16 fetch_local_site_data,
17 generate_moderators_url,
19 objects::{community::ApubCommunity, person::ApubPerson},
20 protocol::activities::community::add_mod::AddMod,
23 use activitypub_federation::{
24 core::object_id::ObjectId,
26 traits::{ActivityHandler, Actor},
28 use activitystreams_kinds::{activity::AddType, public};
29 use lemmy_api_common::utils::blocking;
30 use lemmy_db_schema::{
32 community::{CommunityModerator, CommunityModeratorForm},
33 moderator::{ModAddCommunity, ModAddCommunityForm},
35 traits::{Crud, Joinable},
37 use lemmy_utils::error::LemmyError;
38 use lemmy_websocket::LemmyContext;
42 #[tracing::instrument(skip_all)]
44 community: &ApubCommunity,
45 added_mod: &ApubPerson,
47 context: &LemmyContext,
48 ) -> Result<(), LemmyError> {
49 let id = generate_activity_id(
51 &context.settings().get_protocol_and_hostname(),
54 actor: ObjectId::new(actor.actor_id()),
56 object: ObjectId::new(added_mod.actor_id()),
57 target: generate_moderators_url(&community.actor_id)?.into(),
58 cc: vec![community.actor_id()],
61 unparsed: Default::default(),
64 let activity = AnnouncableActivities::AddMod(add);
65 let inboxes = vec![added_mod.shared_inbox_or_inbox()];
66 send_activity_in_community(activity, actor, community, inboxes, context).await
70 #[async_trait::async_trait(?Send)]
71 impl ActivityHandler for AddMod {
72 type DataType = LemmyContext;
73 type Error = LemmyError;
75 fn id(&self) -> &Url {
79 fn actor(&self) -> &Url {
83 #[tracing::instrument(skip_all)]
86 context: &Data<LemmyContext>,
87 request_counter: &mut i32,
88 ) -> Result<(), LemmyError> {
89 let local_site_data = blocking(context.pool(), fetch_local_site_data).await??;
90 check_apub_id_valid(self.id(), &local_site_data, context.settings())
91 .map_err(LemmyError::from_message)?;
93 verify_is_public(&self.to, &self.cc)?;
94 let community = self.get_community(context, request_counter).await?;
95 verify_person_in_community(&self.actor, &community, context, request_counter).await?;
104 verify_add_remove_moderator_target(&self.target, &community)?;
108 #[tracing::instrument(skip_all)]
111 context: &Data<LemmyContext>,
112 request_counter: &mut i32,
113 ) -> Result<(), LemmyError> {
114 let community = self.get_community(context, request_counter).await?;
117 .dereference(context, local_instance(context), request_counter)
120 // If we had to refetch the community while parsing the activity, then the new mod has already
121 // been added. Skip it here as it would result in a duplicate key error.
122 let new_mod_id = new_mod.id;
123 let moderated_communities = blocking(context.pool(), move |conn| {
124 CommunityModerator::get_person_moderated_communities(conn, new_mod_id)
127 if !moderated_communities.contains(&community.id) {
128 let form = CommunityModeratorForm {
129 community_id: community.id,
130 person_id: new_mod.id,
132 blocking(context.pool(), move |conn| {
133 CommunityModerator::join(conn, &form)
140 .dereference(context, local_instance(context), request_counter)
142 let form = ModAddCommunityForm {
143 mod_person_id: actor.id,
144 other_person_id: new_mod.id,
145 community_id: community.id,
146 removed: Some(false),
148 blocking(context.pool(), move |conn| {
149 ModAddCommunity::create(conn, &form)
153 // TODO: send websocket notification about added mod
158 #[async_trait::async_trait(?Send)]
159 impl GetCommunity for AddMod {
160 #[tracing::instrument(skip_all)]
161 async fn get_community(
163 context: &LemmyContext,
164 request_counter: &mut i32,
165 ) -> Result<ApubCommunity, LemmyError> {
166 get_community_from_moderators_url(&self.target, context, request_counter).await