3 community::{announce::AnnouncableActivities, send_to_community},
7 verify_person_in_community,
9 context::lemmy_context,
10 fetcher::object_id::ObjectId,
11 objects::{community::Group, ToApub},
13 use activitystreams::{
14 activity::kind::UpdateType,
16 primitives::OneOrMany,
19 use lemmy_api_common::blocking;
22 traits::{ActivityFields, ActivityHandler, ActorType},
25 use lemmy_db_queries::Crud;
26 use lemmy_db_schema::source::{
27 community::{Community, CommunityForm},
30 use lemmy_utils::LemmyError;
31 use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
32 use serde::{Deserialize, Serialize};
35 /// This activity is received from a remote community mod, and updates the description or other
36 /// fields of a local community.
37 #[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
38 #[serde(rename_all = "camelCase")]
39 pub struct UpdateCommunity {
40 actor: ObjectId<Person>,
42 // TODO: would be nice to use a separate struct here, which only contains the fields updated here
44 cc: [ObjectId<Community>; 1],
45 #[serde(rename = "type")]
48 #[serde(rename = "@context")]
49 context: OneOrMany<AnyBase>,
54 impl UpdateCommunity {
56 community: &Community,
58 context: &LemmyContext,
59 ) -> Result<(), LemmyError> {
60 let id = generate_activity_id(
62 &context.settings().get_protocol_and_hostname(),
64 let update = UpdateCommunity {
65 actor: ObjectId::new(actor.actor_id()),
66 to: [PublicUrl::Public],
67 object: community.to_apub(context.pool()).await?,
68 cc: [ObjectId::new(community.actor_id())],
69 kind: UpdateType::Update,
71 context: lemmy_context(),
72 unparsed: Default::default(),
75 let activity = AnnouncableActivities::UpdateCommunity(Box::new(update));
76 send_to_community(activity, &id, actor, community, vec![], context).await
80 #[async_trait::async_trait(?Send)]
81 impl ActivityHandler for UpdateCommunity {
82 type DataType = LemmyContext;
85 context: &Data<LemmyContext>,
86 request_counter: &mut i32,
87 ) -> Result<(), LemmyError> {
88 verify_activity(self, &context.settings())?;
89 verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
90 verify_mod_action(&self.actor, self.cc[0].clone(), context, request_counter).await?;
96 context: &Data<LemmyContext>,
97 request_counter: &mut i32,
98 ) -> Result<(), LemmyError> {
99 let cc = self.cc[0].clone();
100 let community = cc.dereference(context, request_counter).await?;
102 let updated_community = Group::from_apub_to_form(
104 &community.actor_id.clone().into(),
108 let cf = CommunityForm {
109 name: updated_community.name,
110 title: updated_community.title,
111 description: updated_community.description,
112 nsfw: updated_community.nsfw,
113 // TODO: icon and banner would be hosted on the other instance, ideally we would copy it to ours
114 icon: updated_community.icon,
115 banner: updated_community.banner,
116 ..CommunityForm::default()
118 let updated_community = blocking(context.pool(), move |conn| {
119 Community::update(conn, community.id, &cf)
123 send_community_ws_message(
124 updated_community.id,
125 UserOperationCrud::EditCommunity,