]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/community/update.rs
57a31221e45ad2da169f3710c21842b13fdb48be
[lemmy.git] / crates / apub / src / activities / community / update.rs
1 use crate::{
2   activities::{
3     community::{announce::GetCommunity, send_activity_in_community},
4     generate_activity_id,
5     verify_is_public,
6     verify_mod_action,
7     verify_person_in_community,
8   },
9   activity_lists::AnnouncableActivities,
10   local_instance,
11   objects::{community::ApubCommunity, person::ApubPerson},
12   protocol::activities::community::update::UpdateCommunity,
13   ActorType,
14 };
15 use activitypub_federation::{
16   core::object_id::ObjectId,
17   data::Data,
18   traits::{ActivityHandler, ApubObject},
19 };
20 use activitystreams_kinds::{activity::UpdateType, public};
21 use lemmy_api_common::utils::blocking;
22 use lemmy_db_schema::{
23   source::community::{Community, CommunityForm},
24   traits::Crud,
25 };
26 use lemmy_utils::error::LemmyError;
27 use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
28 use url::Url;
29
30 impl UpdateCommunity {
31   #[tracing::instrument(skip_all)]
32   pub async fn send(
33     community: ApubCommunity,
34     actor: &ApubPerson,
35     context: &LemmyContext,
36   ) -> Result<(), LemmyError> {
37     let id = generate_activity_id(
38       UpdateType::Update,
39       &context.settings().get_protocol_and_hostname(),
40     )?;
41     let update = UpdateCommunity {
42       actor: ObjectId::new(actor.actor_id()),
43       to: vec![public()],
44       object: Box::new(community.clone().into_apub(context).await?),
45       cc: vec![community.actor_id()],
46       kind: UpdateType::Update,
47       id: id.clone(),
48       unparsed: Default::default(),
49     };
50
51     let activity = AnnouncableActivities::UpdateCommunity(update);
52     send_activity_in_community(activity, actor, &community, vec![], context).await
53   }
54 }
55
56 #[async_trait::async_trait(?Send)]
57 impl ActivityHandler for UpdateCommunity {
58   type DataType = LemmyContext;
59   type Error = LemmyError;
60
61   fn id(&self) -> &Url {
62     &self.id
63   }
64
65   fn actor(&self) -> &Url {
66     self.actor.inner()
67   }
68
69   #[tracing::instrument(skip_all)]
70   async fn verify(
71     &self,
72     context: &Data<LemmyContext>,
73     request_counter: &mut i32,
74   ) -> Result<(), LemmyError> {
75     verify_is_public(&self.to, &self.cc)?;
76     let community = self.get_community(context, request_counter).await?;
77     verify_person_in_community(&self.actor, &community, context, request_counter).await?;
78     verify_mod_action(
79       &self.actor,
80       self.object.id.inner(),
81       community.id,
82       context,
83       request_counter,
84     )
85     .await?;
86     ApubCommunity::verify(
87       &self.object,
88       &community.actor_id.clone().into(),
89       context,
90       request_counter,
91     )
92     .await?;
93     Ok(())
94   }
95
96   #[tracing::instrument(skip_all)]
97   async fn receive(
98     self,
99     context: &Data<LemmyContext>,
100     request_counter: &mut i32,
101   ) -> Result<(), LemmyError> {
102     let community = self.get_community(context, request_counter).await?;
103
104     let updated_community = self.object.into_form();
105     let cf = CommunityForm {
106       name: updated_community.name,
107       title: updated_community.title,
108       description: updated_community.description,
109       nsfw: updated_community.nsfw,
110       // TODO: icon and banner would be hosted on the other instance, ideally we would copy it to ours
111       icon: updated_community.icon,
112       banner: updated_community.banner,
113       ..CommunityForm::default()
114     };
115     let updated_community = blocking(context.pool(), move |conn| {
116       Community::update(conn, community.id, &cf)
117     })
118     .await??;
119
120     send_community_ws_message(
121       updated_community.id,
122       UserOperationCrud::EditCommunity,
123       None,
124       None,
125       context,
126     )
127     .await?;
128     Ok(())
129   }
130 }
131
132 #[async_trait::async_trait(?Send)]
133 impl GetCommunity for UpdateCommunity {
134   #[tracing::instrument(skip_all)]
135   async fn get_community(
136     &self,
137     context: &LemmyContext,
138     request_counter: &mut i32,
139   ) -> Result<ApubCommunity, LemmyError> {
140     let cid = ObjectId::new(self.object.id.clone());
141     cid
142       .dereference(context, local_instance(context), request_counter)
143       .await
144   }
145 }