3 community::{announce::AnnouncableActivities, send_to_community},
8 verify_person_in_community,
10 context::lemmy_context,
11 fetcher::object_id::ObjectId,
13 community::{ApubCommunity, Group},
17 use activitystreams::{
18 activity::kind::UpdateType,
20 primitives::OneOrMany,
24 use lemmy_api_common::blocking;
27 traits::{ActivityFields, ActivityHandler, ActorType, ApubObject},
29 use lemmy_db_schema::{
30 source::community::{Community, CommunityForm},
33 use lemmy_utils::LemmyError;
34 use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
35 use serde::{Deserialize, Serialize};
38 /// This activity is received from a remote community mod, and updates the description or other
39 /// fields of a local community.
40 #[derive(Clone, Debug, Deserialize, Serialize, ActivityFields)]
41 #[serde(rename_all = "camelCase")]
42 pub struct UpdateCommunity {
43 actor: ObjectId<ApubPerson>,
45 // TODO: would be nice to use a separate struct here, which only contains the fields updated here
47 cc: [ObjectId<ApubCommunity>; 1],
48 #[serde(rename = "type")]
51 #[serde(rename = "@context")]
52 context: OneOrMany<AnyBase>,
57 impl UpdateCommunity {
59 community: &ApubCommunity,
61 context: &LemmyContext,
62 ) -> Result<(), LemmyError> {
63 let id = generate_activity_id(
65 &context.settings().get_protocol_and_hostname(),
67 let update = UpdateCommunity {
68 actor: ObjectId::new(actor.actor_id()),
70 object: community.to_apub(context).await?,
71 cc: [ObjectId::new(community.actor_id())],
72 kind: UpdateType::Update,
74 context: lemmy_context(),
75 unparsed: Default::default(),
78 let activity = AnnouncableActivities::UpdateCommunity(Box::new(update));
79 send_to_community(activity, &id, actor, community, vec![], context).await
83 #[async_trait::async_trait(?Send)]
84 impl ActivityHandler for UpdateCommunity {
85 type DataType = LemmyContext;
88 context: &Data<LemmyContext>,
89 request_counter: &mut i32,
90 ) -> Result<(), LemmyError> {
91 verify_is_public(&self.to)?;
92 verify_activity(self, &context.settings())?;
93 verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
94 verify_mod_action(&self.actor, &self.cc[0], context, request_counter).await?;
100 context: &Data<LemmyContext>,
101 request_counter: &mut i32,
102 ) -> Result<(), LemmyError> {
103 let cc = self.cc[0].clone();
104 let community = cc.dereference(context, request_counter).await?;
106 let updated_community = Group::from_apub_to_form(
108 &community.actor_id.clone().into(),
112 let cf = CommunityForm {
113 name: updated_community.name,
114 title: updated_community.title,
115 description: updated_community.description,
116 nsfw: updated_community.nsfw,
117 // TODO: icon and banner would be hosted on the other instance, ideally we would copy it to ours
118 icon: updated_community.icon,
119 banner: updated_community.banner,
120 ..CommunityForm::default()
122 let updated_community = blocking(context.pool(), move |conn| {
123 Community::update(conn, community.id, &cf)
127 send_community_ws_message(
128 updated_community.id,
129 UserOperationCrud::EditCommunity,