]> Untitled Git - lemmy.git/blob - crates/api_crud/src/post/read.rs
fbab8d67191cc810a9cbe1a93f3b6820974d953b
[lemmy.git] / crates / api_crud / src / post / read.rs
1 use crate::PerformCrud;
2 use actix_web::web::Data;
3 use lemmy_api_common::{
4   post::{GetPost, GetPostResponse},
5   utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt, mark_post_as_read},
6 };
7 use lemmy_db_schema::{
8   source::comment::Comment,
9   traits::{Crud, DeleteableOrRemoveable},
10 };
11 use lemmy_db_views::structs::PostView;
12 use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
13 use lemmy_utils::{error::LemmyError, ConnectionId};
14 use lemmy_websocket::{messages::GetPostUsersOnline, LemmyContext};
15
16 #[async_trait::async_trait(?Send)]
17 impl PerformCrud for GetPost {
18   type Response = GetPostResponse;
19
20   #[tracing::instrument(skip(context, _websocket_id))]
21   async fn perform(
22     &self,
23     context: &Data<LemmyContext>,
24     _websocket_id: Option<ConnectionId>,
25   ) -> Result<GetPostResponse, LemmyError> {
26     let data: &GetPost = self;
27     let local_user_view =
28       get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
29         .await?;
30
31     check_private_instance(&local_user_view, context.pool()).await?;
32
33     let person_id = local_user_view.map(|u| u.person.id);
34
35     // I'd prefer fetching the post_view by a comment join, but it adds a lot of boilerplate
36     let post_id = if let Some(id) = data.id {
37       id
38     } else if let Some(comment_id) = data.comment_id {
39       blocking(context.pool(), move |conn| Comment::read(conn, comment_id))
40         .await?
41         .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_post"))?
42         .post_id
43     } else {
44       Err(LemmyError::from_message("couldnt_find_post"))?
45     };
46
47     let mut post_view = blocking(context.pool(), move |conn| {
48       PostView::read(conn, post_id, person_id)
49     })
50     .await?
51     .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_post"))?;
52
53     // Mark the post as read
54     let post_id = post_view.post.id;
55     if let Some(person_id) = person_id {
56       mark_post_as_read(person_id, post_id, context.pool()).await?;
57     }
58
59     // Necessary for the sidebar subscribed
60     let community_id = post_view.community.id;
61     let mut community_view = blocking(context.pool(), move |conn| {
62       CommunityView::read(conn, community_id, person_id)
63     })
64     .await?
65     .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?;
66
67     // Blank out deleted or removed info for non-logged in users
68     if person_id.is_none() {
69       if post_view.post.deleted || post_view.post.removed {
70         post_view.post = post_view.post.blank_out_deleted_or_removed_info();
71       }
72
73       if community_view.community.deleted || community_view.community.removed {
74         community_view.community = community_view.community.blank_out_deleted_or_removed_info();
75       }
76     }
77
78     let moderators = blocking(context.pool(), move |conn| {
79       CommunityModeratorView::for_community(conn, community_id)
80     })
81     .await??;
82
83     let online = context
84       .chat_server()
85       .send(GetPostUsersOnline { post_id })
86       .await
87       .unwrap_or(1);
88
89     // Return the jwt
90     Ok(GetPostResponse {
91       post_view,
92       community_view,
93       moderators,
94       online,
95     })
96   }
97 }