3 community::send_activity_in_community,
7 verify_person_in_community,
9 activity_lists::AnnouncableActivities,
11 objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
14 community::{collection_add::CollectionAdd, collection_remove::CollectionRemove},
15 create_or_update::page::CreateOrUpdatePage,
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::{
30 community::{AddModToCommunity, AddModToCommunityResponse},
31 context::LemmyContext,
32 post::{FeaturePost, PostResponse},
33 utils::{generate_featured_url, generate_moderators_url, get_local_user_view_from_jwt},
35 use lemmy_db_schema::{
36 impls::community::CollectionType,
38 community::{Community, CommunityModerator, CommunityModeratorForm},
39 moderator::{ModAddCommunity, ModAddCommunityForm},
41 post::{Post, PostUpdateForm},
43 traits::{Crud, Joinable},
45 use lemmy_utils::error::LemmyError;
49 #[tracing::instrument(skip_all)]
50 pub async fn send_add_mod(
51 community: &ApubCommunity,
52 added_mod: &ApubPerson,
54 context: &LemmyContext,
55 ) -> Result<(), LemmyError> {
56 let id = generate_activity_id(
58 &context.settings().get_protocol_and_hostname(),
60 let add = CollectionAdd {
61 actor: ObjectId::new(actor.actor_id()),
63 object: added_mod.actor_id(),
64 target: generate_moderators_url(&community.actor_id)?.into(),
65 cc: vec![community.actor_id()],
68 audience: Some(ObjectId::new(community.actor_id())),
71 let activity = AnnouncableActivities::CollectionAdd(add);
72 let inboxes = vec![added_mod.shared_inbox_or_inbox()];
73 send_activity_in_community(activity, actor, community, inboxes, true, context).await
76 pub async fn send_add_featured_post(
77 community: &ApubCommunity,
78 featured_post: &ApubPost,
80 context: &LemmyContext,
81 ) -> Result<(), LemmyError> {
82 let id = generate_activity_id(
84 &context.settings().get_protocol_and_hostname(),
86 let add = CollectionAdd {
87 actor: ObjectId::new(actor.actor_id()),
89 object: featured_post.ap_id.clone().into(),
90 target: generate_featured_url(&community.actor_id)?.into(),
91 cc: vec![community.actor_id()],
94 audience: Some(ObjectId::new(community.actor_id())),
96 let activity = AnnouncableActivities::CollectionAdd(add);
97 send_activity_in_community(activity, actor, community, vec![], true, context).await
101 #[async_trait::async_trait(?Send)]
102 impl ActivityHandler for CollectionAdd {
103 type DataType = LemmyContext;
104 type Error = LemmyError;
106 fn id(&self) -> &Url {
110 fn actor(&self) -> &Url {
114 #[tracing::instrument(skip_all)]
117 context: &Data<LemmyContext>,
118 request_counter: &mut i32,
119 ) -> Result<(), LemmyError> {
120 verify_is_public(&self.to, &self.cc)?;
121 let community = self.community(context, request_counter).await?;
122 verify_person_in_community(&self.actor, &community, context, request_counter).await?;
134 #[tracing::instrument(skip_all)]
137 context: &Data<LemmyContext>,
138 request_counter: &mut i32,
139 ) -> Result<(), LemmyError> {
140 let (community, collection_type) =
141 Community::get_by_collection_url(context.pool(), &self.target.into()).await?;
142 match collection_type {
143 CollectionType::Moderators => {
144 let new_mod = ObjectId::<ApubPerson>::new(self.object)
145 .dereference(context, local_instance(context).await, request_counter)
148 // If we had to refetch the community while parsing the activity, then the new mod has already
149 // been added. Skip it here as it would result in a duplicate key error.
150 let new_mod_id = new_mod.id;
151 let moderated_communities =
152 CommunityModerator::get_person_moderated_communities(context.pool(), new_mod_id).await?;
153 if !moderated_communities.contains(&community.id) {
154 let form = CommunityModeratorForm {
155 community_id: community.id,
156 person_id: new_mod.id,
158 CommunityModerator::join(context.pool(), &form).await?;
163 .dereference(context, local_instance(context).await, request_counter)
165 let form = ModAddCommunityForm {
166 mod_person_id: actor.id,
167 other_person_id: new_mod.id,
168 community_id: community.id,
169 removed: Some(false),
171 ModAddCommunity::create(context.pool(), &form).await?;
173 // TODO: send websocket notification about added mod
175 CollectionType::Featured => {
176 let post = ObjectId::<ApubPost>::new(self.object)
177 .dereference(context, local_instance(context).await, request_counter)
179 let form = PostUpdateForm::builder()
180 .featured_community(Some(true))
182 Post::update(context.pool(), post.id, &form).await?;
189 #[async_trait::async_trait(?Send)]
190 impl SendActivity for AddModToCommunity {
191 type Response = AddModToCommunityResponse;
193 async fn send_activity(
195 _response: &Self::Response,
196 context: &LemmyContext,
197 ) -> Result<(), LemmyError> {
198 let local_user_view =
199 get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
200 let community: ApubCommunity = Community::read(context.pool(), request.community_id)
203 let updated_mod: ApubPerson = Person::read(context.pool(), request.person_id)
207 CollectionAdd::send_add_mod(
210 &local_user_view.person.into(),
215 CollectionRemove::send_remove_mod(
218 &local_user_view.person.into(),
226 #[async_trait::async_trait(?Send)]
227 impl SendActivity for FeaturePost {
228 type Response = PostResponse;
230 async fn send_activity(
232 response: &Self::Response,
233 context: &LemmyContext,
234 ) -> Result<(), LemmyError> {
235 let local_user_view =
236 get_local_user_view_from_jwt(&request.auth, context.pool(), context.secret()).await?;
237 // Deprecated, for backwards compatibility with 0.17
238 CreateOrUpdatePage::send(
239 &response.post_view.post,
240 local_user_view.person.id,
241 CreateOrUpdateType::Update,
245 let community = Community::read(context.pool(), response.post_view.community.id)
248 let post = response.post_view.post.clone().into();
249 let person = local_user_view.person.into();
250 if request.featured {
251 CollectionAdd::send_add_featured_post(&community, &post, &person, context).await
253 CollectionRemove::send_remove_featured_post(&community, &post, &person, context).await