]> Untitled Git - lemmy.git/blob - crates/apub/src/fetcher/post_or_comment.rs
68e176b0145ccc8ca1b078c89e2d90f42fbbbb7a
[lemmy.git] / crates / apub / src / fetcher / post_or_comment.rs
1 use crate::{
2   objects::{comment::ApubComment, community::ApubCommunity, post::ApubPost},
3   protocol::{
4     objects::{note::Note, page::Page},
5     InCommunity,
6   },
7 };
8 use activitypub_federation::traits::ApubObject;
9 use chrono::NaiveDateTime;
10 use lemmy_api_common::context::LemmyContext;
11 use lemmy_db_schema::{
12   source::{community::Community, post::Post},
13   traits::Crud,
14 };
15 use lemmy_utils::error::LemmyError;
16 use serde::Deserialize;
17 use url::Url;
18
19 #[derive(Clone, Debug)]
20 pub enum PostOrComment {
21   Post(Box<ApubPost>),
22   Comment(Box<ApubComment>),
23 }
24
25 #[derive(Deserialize)]
26 #[serde(untagged)]
27 pub enum PageOrNote {
28   Page(Box<Page>),
29   Note(Box<Note>),
30 }
31
32 #[async_trait::async_trait(?Send)]
33 impl ApubObject for PostOrComment {
34   type DataType = LemmyContext;
35   type ApubType = PageOrNote;
36   type DbType = ();
37   type Error = LemmyError;
38
39   fn last_refreshed_at(&self) -> Option<NaiveDateTime> {
40     None
41   }
42
43   // TODO: this can probably be implemented using a single sql query
44   #[tracing::instrument(skip_all)]
45   async fn read_from_apub_id(
46     object_id: Url,
47     data: &Self::DataType,
48   ) -> Result<Option<Self>, LemmyError> {
49     let post = ApubPost::read_from_apub_id(object_id.clone(), data).await?;
50     Ok(match post {
51       Some(o) => Some(PostOrComment::Post(Box::new(o))),
52       None => ApubComment::read_from_apub_id(object_id, data)
53         .await?
54         .map(|c| PostOrComment::Comment(Box::new(c))),
55     })
56   }
57
58   #[tracing::instrument(skip_all)]
59   async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> {
60     match self {
61       PostOrComment::Post(p) => p.delete(data).await,
62       PostOrComment::Comment(c) => c.delete(data).await,
63     }
64   }
65
66   async fn into_apub(self, _data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
67     unimplemented!()
68   }
69
70   #[tracing::instrument(skip_all)]
71   async fn verify(
72     apub: &Self::ApubType,
73     expected_domain: &Url,
74     data: &Self::DataType,
75     request_counter: &mut i32,
76   ) -> Result<(), LemmyError> {
77     match apub {
78       PageOrNote::Page(a) => ApubPost::verify(a, expected_domain, data, request_counter).await,
79       PageOrNote::Note(a) => ApubComment::verify(a, expected_domain, data, request_counter).await,
80     }
81   }
82
83   #[tracing::instrument(skip_all)]
84   async fn from_apub(
85     apub: PageOrNote,
86     context: &LemmyContext,
87     request_counter: &mut i32,
88   ) -> Result<Self, LemmyError> {
89     Ok(match apub {
90       PageOrNote::Page(p) => PostOrComment::Post(Box::new(
91         ApubPost::from_apub(*p, context, request_counter).await?,
92       )),
93       PageOrNote::Note(n) => PostOrComment::Comment(Box::new(
94         ApubComment::from_apub(*n, context, request_counter).await?,
95       )),
96     })
97   }
98 }
99
100 #[async_trait::async_trait(?Send)]
101 impl InCommunity for PostOrComment {
102   async fn community(
103     &self,
104     context: &LemmyContext,
105     _: &mut i32,
106   ) -> Result<ApubCommunity, LemmyError> {
107     let cid = match self {
108       PostOrComment::Post(p) => p.community_id,
109       PostOrComment::Comment(c) => Post::read(context.pool(), c.post_id).await?.community_id,
110     };
111     Ok(Community::read(context.pool(), cid).await?.into())
112   }
113 }