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