]> Untitled Git - lemmy.git/blob - crates/apub/src/collections/community_featured.rs
Make functions work with both connection and pool (#3420)
[lemmy.git] / crates / apub / src / collections / community_featured.rs
1 use crate::{
2   objects::{community::ApubCommunity, post::ApubPost},
3   protocol::collections::group_featured::GroupFeatured,
4 };
5 use activitypub_federation::{
6   config::Data,
7   kinds::collection::OrderedCollectionType,
8   protocol::verification::verify_domains_match,
9   traits::{ActivityHandler, Collection, Object},
10 };
11 use futures::future::{join_all, try_join_all};
12 use lemmy_api_common::{context::LemmyContext, utils::generate_featured_url};
13 use lemmy_db_schema::{source::post::Post, utils::FETCH_LIMIT_MAX};
14 use lemmy_utils::error::LemmyError;
15 use url::Url;
16
17 #[derive(Clone, Debug)]
18 pub(crate) struct ApubCommunityFeatured(Vec<ApubPost>);
19
20 #[async_trait::async_trait]
21 impl Collection for ApubCommunityFeatured {
22   type Owner = ApubCommunity;
23   type DataType = LemmyContext;
24   type Kind = GroupFeatured;
25   type Error = LemmyError;
26
27   async fn read_local(
28     owner: &Self::Owner,
29     data: &Data<Self::DataType>,
30   ) -> Result<Self::Kind, Self::Error> {
31     let ordered_items = try_join_all(
32       Post::list_featured_for_community(&mut data.pool(), owner.id)
33         .await?
34         .into_iter()
35         .map(ApubPost::from)
36         .map(|p| p.into_json(data)),
37     )
38     .await?;
39     Ok(GroupFeatured {
40       r#type: OrderedCollectionType::OrderedCollection,
41       id: generate_featured_url(&owner.actor_id)?.into(),
42       total_items: ordered_items.len() as i32,
43       ordered_items,
44     })
45   }
46
47   async fn verify(
48     apub: &Self::Kind,
49     expected_domain: &Url,
50     _data: &Data<Self::DataType>,
51   ) -> Result<(), Self::Error> {
52     verify_domains_match(expected_domain, &apub.id)?;
53     Ok(())
54   }
55
56   async fn from_json(
57     apub: Self::Kind,
58     _owner: &Self::Owner,
59     data: &Data<Self::DataType>,
60   ) -> Result<Self, Self::Error>
61   where
62     Self: Sized,
63   {
64     let mut posts = apub.ordered_items;
65     if posts.len() as i64 > FETCH_LIMIT_MAX {
66       posts = posts
67         .get(0..(FETCH_LIMIT_MAX as usize))
68         .unwrap_or_default()
69         .to_vec();
70     }
71
72     // We intentionally ignore errors here. This is because the outbox might contain posts from old
73     // Lemmy versions, or from other software which we cant parse. In that case, we simply skip the
74     // item and only parse the ones that work.
75     // process items in parallel, to avoid long delay from fetch_site_metadata() and other processing
76     join_all(posts.into_iter().map(|post| {
77       async {
78         // use separate request counter for each item, otherwise there will be problems with
79         // parallel processing
80         let verify = post.verify(data).await;
81         if verify.is_ok() {
82           post.receive(data).await.ok();
83         }
84       }
85     }))
86     .await;
87
88     // This return value is unused, so just set an empty vec
89     Ok(ApubCommunityFeatured(Vec::new()))
90   }
91 }