]> Untitled Git - lemmy.git/blob - crates/apub/src/fetcher/community.rs
Merge branch 'remove_settings_and_secret_singletons_squashed'
[lemmy.git] / crates / apub / src / fetcher / community.rs
1 use crate::{
2   activities::community::announce::AnnounceActivity,
3   fetcher::{fetch::fetch_remote_object, object_id::ObjectId},
4   objects::community::Group,
5 };
6 use activitystreams::collection::{CollectionExt, OrderedCollection};
7 use anyhow::Context;
8 use lemmy_api_common::blocking;
9 use lemmy_apub_lib::ActivityHandler;
10 use lemmy_db_queries::Joinable;
11 use lemmy_db_schema::source::{
12   community::{Community, CommunityModerator, CommunityModeratorForm},
13   person::Person,
14 };
15 use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView;
16 use lemmy_utils::{location_info, LemmyError};
17 use lemmy_websocket::LemmyContext;
18 use url::Url;
19
20 pub(crate) async fn update_community_mods(
21   group: &Group,
22   community: &Community,
23   context: &LemmyContext,
24   request_counter: &mut i32,
25 ) -> Result<(), LemmyError> {
26   let new_moderators = fetch_community_mods(context, group, request_counter).await?;
27   let community_id = community.id;
28   let current_moderators = blocking(context.pool(), move |conn| {
29     CommunityModeratorView::for_community(conn, community_id)
30   })
31   .await??;
32   // Remove old mods from database which arent in the moderators collection anymore
33   for mod_user in &current_moderators {
34     if !new_moderators.contains(&mod_user.moderator.actor_id.clone().into()) {
35       let community_moderator_form = CommunityModeratorForm {
36         community_id: mod_user.community.id,
37         person_id: mod_user.moderator.id,
38       };
39       blocking(context.pool(), move |conn| {
40         CommunityModerator::leave(conn, &community_moderator_form)
41       })
42       .await??;
43     }
44   }
45
46   // Add new mods to database which have been added to moderators collection
47   for mod_id in new_moderators {
48     let mod_id = ObjectId::new(mod_id);
49     let mod_user: Person = mod_id.dereference(context, request_counter).await?;
50
51     if !current_moderators
52       .clone()
53       .iter()
54       .map(|c| c.moderator.actor_id.clone())
55       .any(|x| x == mod_user.actor_id)
56     {
57       let community_moderator_form = CommunityModeratorForm {
58         community_id: community.id,
59         person_id: mod_user.id,
60       };
61       blocking(context.pool(), move |conn| {
62         CommunityModerator::join(conn, &community_moderator_form)
63       })
64       .await??;
65     }
66   }
67
68   Ok(())
69 }
70
71 pub(crate) async fn fetch_community_outbox(
72   context: &LemmyContext,
73   outbox: &Url,
74   recursion_counter: &mut i32,
75 ) -> Result<(), LemmyError> {
76   let outbox = fetch_remote_object::<OrderedCollection>(
77     context.client(),
78     &context.settings(),
79     outbox,
80     recursion_counter,
81   )
82   .await?;
83   let outbox_activities = outbox.items().context(location_info!())?.clone();
84   let mut outbox_activities = outbox_activities.many().context(location_info!())?;
85   if outbox_activities.len() > 20 {
86     outbox_activities = outbox_activities[0..20].to_vec();
87   }
88
89   for announce in outbox_activities {
90     // TODO: instead of converting like this, we should create a struct CommunityOutbox with
91     //       AnnounceActivity as inner type, but that gives me stackoverflow
92     let ser = serde_json::to_string(&announce)?;
93     let announce: AnnounceActivity = serde_json::from_str(&ser)?;
94     announce.receive(context, recursion_counter).await?;
95   }
96
97   Ok(())
98 }
99
100 async fn fetch_community_mods(
101   context: &LemmyContext,
102   group: &Group,
103   recursion_counter: &mut i32,
104 ) -> Result<Vec<Url>, LemmyError> {
105   if let Some(mods_url) = &group.moderators {
106     let mods = fetch_remote_object::<OrderedCollection>(
107       context.client(),
108       &context.settings(),
109       mods_url,
110       recursion_counter,
111     )
112     .await?;
113     let mods = mods
114       .items()
115       .map(|i| i.as_many())
116       .flatten()
117       .context(location_info!())?
118       .iter()
119       .filter_map(|i| i.as_xsd_any_uri())
120       .map(|u| u.to_owned())
121       .collect();
122     Ok(mods)
123   } else {
124     Ok(vec![])
125   }
126 }