3 community::{announce::AnnouncableActivities, send_to_community},
7 verify_person_in_community,
9 context::lemmy_context,
10 fetcher::object_id::ObjectId,
11 migrations::PublicUrlMigration,
13 community::{ApubCommunity, Group},
17 use activitystreams::{
18 activity::kind::UpdateType,
20 primitives::OneOrMany,
23 use lemmy_api_common::blocking;
26 traits::{ActivityFields, ActivityHandler, ActorType, ToApub},
28 use lemmy_db_schema::{
29 source::community::{Community, CommunityForm},
32 use lemmy_utils::LemmyError;
33 use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
34 use serde::{Deserialize, Serialize};
37 /// This activity is received from a remote community mod, and updates the description or other
38 /// fields of a local community.
39 #[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
40 #[serde(rename_all = "camelCase")]
41 pub struct UpdateCommunity {
42 actor: ObjectId<ApubPerson>,
43 to: PublicUrlMigration,
44 // TODO: would be nice to use a separate struct here, which only contains the fields updated here
46 cc: [ObjectId<ApubCommunity>; 1],
47 #[serde(rename = "type")]
50 #[serde(rename = "@context")]
51 context: OneOrMany<AnyBase>,
56 impl UpdateCommunity {
58 community: &ApubCommunity,
60 context: &LemmyContext,
61 ) -> Result<(), LemmyError> {
62 let id = generate_activity_id(
64 &context.settings().get_protocol_and_hostname(),
66 let update = UpdateCommunity {
67 actor: ObjectId::new(actor.actor_id()),
68 to: PublicUrlMigration::create(),
69 object: community.to_apub(context.pool()).await?,
70 cc: [ObjectId::new(community.actor_id())],
71 kind: UpdateType::Update,
73 context: lemmy_context(),
74 unparsed: Default::default(),
77 let activity = AnnouncableActivities::UpdateCommunity(Box::new(update));
78 send_to_community(activity, &id, actor, community, vec![], context).await
82 #[async_trait::async_trait(?Send)]
83 impl ActivityHandler for UpdateCommunity {
84 type DataType = LemmyContext;
87 context: &Data<LemmyContext>,
88 request_counter: &mut i32,
89 ) -> Result<(), LemmyError> {
90 verify_activity(self, &context.settings())?;
91 verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
92 verify_mod_action(&self.actor, &self.cc[0], context, request_counter).await?;
98 context: &Data<LemmyContext>,
99 request_counter: &mut i32,
100 ) -> Result<(), LemmyError> {
101 let cc = self.cc[0].clone();
102 let community = cc.dereference(context, request_counter).await?;
104 let updated_community = Group::from_apub_to_form(
106 &community.actor_id.clone().into(),
110 let cf = CommunityForm {
111 name: updated_community.name,
112 title: updated_community.title,
113 description: updated_community.description,
114 nsfw: updated_community.nsfw,
115 // TODO: icon and banner would be hosted on the other instance, ideally we would copy it to ours
116 icon: updated_community.icon,
117 banner: updated_community.banner,
118 ..CommunityForm::default()
120 let updated_community = blocking(context.pool(), move |conn| {
121 Community::update(conn, community.id, &cf)
125 send_community_ws_message(
126 updated_community.id,
127 UserOperationCrud::EditCommunity,