]> Untitled Git - lemmy.git/blob - crates/apub/src/fetcher/objects.rs
Rewrite apub comment (de)serialization using structs (ref #1657)
[lemmy.git] / crates / apub / src / fetcher / objects.rs
1 use crate::{
2   fetcher::fetch::fetch_remote_object,
3   objects::{comment::Note, post::Page, FromApub},
4   PostOrComment,
5 };
6 use anyhow::anyhow;
7 use diesel::result::Error::NotFound;
8 use lemmy_api_common::blocking;
9 use lemmy_db_queries::{ApubObject, Crud};
10 use lemmy_db_schema::source::{comment::Comment, post::Post};
11 use lemmy_utils::LemmyError;
12 use lemmy_websocket::LemmyContext;
13 use log::debug;
14 use url::Url;
15
16 /// Gets a post by its apub ID. If it exists locally, it is returned directly. Otherwise it is
17 /// pulled from its apub ID, inserted and returned.
18 ///
19 /// The parent community is also pulled if necessary. Comments are not pulled.
20 pub async fn get_or_fetch_and_insert_post(
21   post_ap_id: &Url,
22   context: &LemmyContext,
23   recursion_counter: &mut i32,
24 ) -> Result<Post, LemmyError> {
25   let post_ap_id_owned = post_ap_id.to_owned();
26   let post = blocking(context.pool(), move |conn| {
27     Post::read_from_apub_id(conn, &post_ap_id_owned.into())
28   })
29   .await?;
30
31   match post {
32     Ok(p) => Ok(p),
33     Err(NotFound {}) => {
34       debug!("Fetching and creating remote post: {}", post_ap_id);
35       let page =
36         fetch_remote_object::<Page>(context.client(), post_ap_id, recursion_counter).await?;
37       let post = Post::from_apub(
38         &page,
39         context,
40         post_ap_id.to_owned(),
41         recursion_counter,
42         false,
43       )
44       .await?;
45
46       Ok(post)
47     }
48     Err(e) => Err(e.into()),
49   }
50 }
51
52 /// Gets a comment by its apub ID. If it exists locally, it is returned directly. Otherwise it is
53 /// pulled from its apub ID, inserted and returned.
54 ///
55 /// The parent community, post and comment are also pulled if necessary.
56 pub async fn get_or_fetch_and_insert_comment(
57   comment_ap_id: &Url,
58   context: &LemmyContext,
59   recursion_counter: &mut i32,
60 ) -> Result<Comment, LemmyError> {
61   let comment_ap_id_owned = comment_ap_id.to_owned();
62   let comment = blocking(context.pool(), move |conn| {
63     Comment::read_from_apub_id(conn, &comment_ap_id_owned.into())
64   })
65   .await?;
66
67   match comment {
68     Ok(p) => Ok(p),
69     Err(NotFound {}) => {
70       debug!(
71         "Fetching and creating remote comment and its parents: {}",
72         comment_ap_id
73       );
74       let comment =
75         fetch_remote_object::<Note>(context.client(), comment_ap_id, recursion_counter).await?;
76       let comment = Comment::from_apub(
77         &comment,
78         context,
79         comment_ap_id.to_owned(),
80         recursion_counter,
81         false,
82       )
83       .await?;
84
85       let post_id = comment.post_id;
86       let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
87       if post.locked {
88         return Err(anyhow!("Post is locked").into());
89       }
90
91       Ok(comment)
92     }
93     Err(e) => Err(e.into()),
94   }
95 }
96
97 pub async fn get_or_fetch_and_insert_post_or_comment(
98   ap_id: &Url,
99   context: &LemmyContext,
100   recursion_counter: &mut i32,
101 ) -> Result<PostOrComment, LemmyError> {
102   Ok(
103     match get_or_fetch_and_insert_post(ap_id, context, recursion_counter).await {
104       Ok(p) => PostOrComment::Post(Box::new(p)),
105       Err(_) => {
106         let c = get_or_fetch_and_insert_comment(ap_id, context, recursion_counter).await?;
107         PostOrComment::Comment(Box::new(c))
108       }
109     },
110   )
111 }