]> Untitled Git - lemmy.git/blob - crates/api_crud/src/post/read.rs
Rework error handling (fixes #1714) (#2135)
[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   blocking,
5   check_private_instance,
6   get_local_user_view_from_jwt_opt,
7   mark_post_as_read,
8   post::*,
9   resolve_actor_identifier,
10 };
11 use lemmy_db_schema::{
12   from_opt_str_to_opt_enum,
13   source::community::Community,
14   traits::DeleteableOrRemoveable,
15   ListingType,
16   SortType,
17 };
18 use lemmy_db_views::{
19   comment_view::CommentQueryBuilder,
20   post_view::{PostQueryBuilder, PostView},
21 };
22 use lemmy_db_views_actor::{
23   community_moderator_view::CommunityModeratorView,
24   community_view::CommunityView,
25 };
26 use lemmy_utils::{ConnectionId, LemmyError};
27 use lemmy_websocket::{messages::GetPostUsersOnline, LemmyContext};
28
29 #[async_trait::async_trait(?Send)]
30 impl PerformCrud for GetPost {
31   type Response = GetPostResponse;
32
33   #[tracing::instrument(skip(context, _websocket_id))]
34   async fn perform(
35     &self,
36     context: &Data<LemmyContext>,
37     _websocket_id: Option<ConnectionId>,
38   ) -> Result<GetPostResponse, LemmyError> {
39     let data: &GetPost = self;
40     let local_user_view =
41       get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
42         .await?;
43
44     check_private_instance(&local_user_view, context.pool()).await?;
45
46     let show_bot_accounts = local_user_view
47       .as_ref()
48       .map(|t| t.local_user.show_bot_accounts);
49     let person_id = local_user_view.map(|u| u.person.id);
50
51     let id = data.id;
52     let mut post_view = blocking(context.pool(), move |conn| {
53       PostView::read(conn, id, person_id)
54     })
55     .await?
56     .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_post"))?;
57
58     // Mark the post as read
59     if let Some(person_id) = person_id {
60       mark_post_as_read(person_id, id, context.pool()).await?;
61     }
62
63     let id = data.id;
64     let mut comments = blocking(context.pool(), move |conn| {
65       CommentQueryBuilder::create(conn)
66         .my_person_id(person_id)
67         .show_bot_accounts(show_bot_accounts)
68         .post_id(id)
69         .limit(9999)
70         .list()
71     })
72     .await??;
73
74     // Necessary for the sidebar
75     let community_id = post_view.community.id;
76     let mut community_view = blocking(context.pool(), move |conn| {
77       CommunityView::read(conn, community_id, person_id)
78     })
79     .await?
80     .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?;
81
82     // Blank out deleted or removed info for non-logged in users
83     if person_id.is_none() {
84       if post_view.post.deleted || post_view.post.removed {
85         post_view.post = post_view.post.blank_out_deleted_or_removed_info();
86       }
87
88       for cv in comments
89         .iter_mut()
90         .filter(|cv| cv.comment.deleted || cv.comment.removed)
91       {
92         cv.comment = cv.to_owned().comment.blank_out_deleted_or_removed_info();
93       }
94       if community_view.community.deleted || community_view.community.removed {
95         community_view.community = community_view.community.blank_out_deleted_or_removed_info();
96       }
97     }
98
99     let moderators = blocking(context.pool(), move |conn| {
100       CommunityModeratorView::for_community(conn, community_id)
101     })
102     .await??;
103
104     let online = context
105       .chat_server()
106       .send(GetPostUsersOnline { post_id: data.id })
107       .await
108       .unwrap_or(1);
109
110     // Return the jwt
111     Ok(GetPostResponse {
112       post_view,
113       community_view,
114       comments,
115       moderators,
116       online,
117     })
118   }
119 }
120
121 #[async_trait::async_trait(?Send)]
122 impl PerformCrud for GetPosts {
123   type Response = GetPostsResponse;
124
125   #[tracing::instrument(skip(context, _websocket_id))]
126   async fn perform(
127     &self,
128     context: &Data<LemmyContext>,
129     _websocket_id: Option<ConnectionId>,
130   ) -> Result<GetPostsResponse, LemmyError> {
131     let data: &GetPosts = self;
132     let local_user_view =
133       get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
134         .await?;
135
136     check_private_instance(&local_user_view, context.pool()).await?;
137
138     let person_id = local_user_view.to_owned().map(|l| l.person.id);
139
140     let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
141     let show_bot_accounts = local_user_view
142       .as_ref()
143       .map(|t| t.local_user.show_bot_accounts);
144     let show_read_posts = local_user_view
145       .as_ref()
146       .map(|t| t.local_user.show_read_posts);
147
148     let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
149     let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.type_);
150
151     let page = data.page;
152     let limit = data.limit;
153     let community_id = data.community_id;
154     let community_actor_id = if let Some(name) = &data.community_name {
155       resolve_actor_identifier::<Community>(name, context.pool())
156         .await
157         .ok()
158         .map(|c| c.actor_id)
159     } else {
160       None
161     };
162     let saved_only = data.saved_only;
163
164     let mut posts = blocking(context.pool(), move |conn| {
165       PostQueryBuilder::create(conn)
166         .listing_type(listing_type)
167         .sort(sort)
168         .show_nsfw(show_nsfw)
169         .show_bot_accounts(show_bot_accounts)
170         .show_read_posts(show_read_posts)
171         .community_id(community_id)
172         .community_actor_id(community_actor_id)
173         .saved_only(saved_only)
174         .my_person_id(person_id)
175         .page(page)
176         .limit(limit)
177         .list()
178     })
179     .await?
180     .map_err(|e| LemmyError::from_error_message(e, "couldnt_get_posts"))?;
181
182     // Blank out deleted or removed info for non-logged in users
183     if person_id.is_none() {
184       for pv in posts
185         .iter_mut()
186         .filter(|p| p.post.deleted || p.post.removed)
187       {
188         pv.post = pv.to_owned().post.blank_out_deleted_or_removed_info();
189       }
190
191       for pv in posts
192         .iter_mut()
193         .filter(|p| p.community.deleted || p.community.removed)
194       {
195         pv.community = pv.to_owned().community.blank_out_deleted_or_removed_info();
196       }
197     }
198
199     Ok(GetPostsResponse { posts })
200   }
201 }