]> Untitled Git - lemmy.git/blob - crates/api/src/post.rs
Add show_read_posts filter. Fixes #1561
[lemmy.git] / crates / api / src / post.rs
1 use crate::Perform;
2 use actix_web::web::Data;
3 use lemmy_api_common::{
4   blocking,
5   check_community_ban,
6   check_downvotes_enabled,
7   get_local_user_view_from_jwt,
8   is_mod_or_admin,
9   mark_post_as_read,
10   post::*,
11 };
12 use lemmy_apub::{ApubLikeableType, ApubObjectType};
13 use lemmy_db_queries::{source::post::Post_, Crud, Likeable, Saveable};
14 use lemmy_db_schema::source::{moderator::*, post::*};
15 use lemmy_db_views::post_view::PostView;
16 use lemmy_utils::{ApiError, ConnectionId, LemmyError};
17 use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation};
18
19 #[async_trait::async_trait(?Send)]
20 impl Perform for CreatePostLike {
21   type Response = PostResponse;
22
23   async fn perform(
24     &self,
25     context: &Data<LemmyContext>,
26     websocket_id: Option<ConnectionId>,
27   ) -> Result<PostResponse, LemmyError> {
28     let data: &CreatePostLike = &self;
29     let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
30
31     // Don't do a downvote if site has downvotes disabled
32     check_downvotes_enabled(data.score, context.pool()).await?;
33
34     // Check for a community ban
35     let post_id = data.post_id;
36     let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
37
38     check_community_ban(local_user_view.person.id, post.community_id, context.pool()).await?;
39
40     let like_form = PostLikeForm {
41       post_id: data.post_id,
42       person_id: local_user_view.person.id,
43       score: data.score,
44     };
45
46     // Remove any likes first
47     let person_id = local_user_view.person.id;
48     blocking(context.pool(), move |conn| {
49       PostLike::remove(conn, person_id, post_id)
50     })
51     .await??;
52
53     // Only add the like if the score isnt 0
54     let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
55     if do_add {
56       let like_form2 = like_form.clone();
57       let like = move |conn: &'_ _| PostLike::like(conn, &like_form2);
58       if blocking(context.pool(), like).await?.is_err() {
59         return Err(ApiError::err("couldnt_like_post").into());
60       }
61
62       if like_form.score == 1 {
63         post.send_like(&local_user_view.person, context).await?;
64       } else if like_form.score == -1 {
65         post.send_dislike(&local_user_view.person, context).await?;
66       }
67     } else {
68       post
69         .send_undo_like(&local_user_view.person, context)
70         .await?;
71     }
72
73     // Mark the post as read
74     mark_post_as_read(person_id, post_id, context.pool()).await?;
75
76     let post_id = data.post_id;
77     let person_id = local_user_view.person.id;
78     let post_view = blocking(context.pool(), move |conn| {
79       PostView::read(conn, post_id, Some(person_id))
80     })
81     .await?
82     .map_err(|_| ApiError::err("couldnt_find_post"))?;
83
84     let res = PostResponse { post_view };
85
86     context.chat_server().do_send(SendPost {
87       op: UserOperation::CreatePostLike,
88       post: res.clone(),
89       websocket_id,
90     });
91
92     Ok(res)
93   }
94 }
95
96 #[async_trait::async_trait(?Send)]
97 impl Perform for LockPost {
98   type Response = PostResponse;
99
100   async fn perform(
101     &self,
102     context: &Data<LemmyContext>,
103     websocket_id: Option<ConnectionId>,
104   ) -> Result<PostResponse, LemmyError> {
105     let data: &LockPost = &self;
106     let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
107
108     let post_id = data.post_id;
109     let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
110
111     check_community_ban(
112       local_user_view.person.id,
113       orig_post.community_id,
114       context.pool(),
115     )
116     .await?;
117
118     // Verify that only the mods can lock
119     is_mod_or_admin(
120       context.pool(),
121       local_user_view.person.id,
122       orig_post.community_id,
123     )
124     .await?;
125
126     // Update the post
127     let post_id = data.post_id;
128     let locked = data.locked;
129     let updated_post = blocking(context.pool(), move |conn| {
130       Post::update_locked(conn, post_id, locked)
131     })
132     .await??;
133
134     // Mod tables
135     let form = ModLockPostForm {
136       mod_person_id: local_user_view.person.id,
137       post_id: data.post_id,
138       locked: Some(locked),
139     };
140     blocking(context.pool(), move |conn| ModLockPost::create(conn, &form)).await??;
141
142     // apub updates
143     updated_post
144       .send_update(&local_user_view.person, context)
145       .await?;
146
147     // Refetch the post
148     let post_id = data.post_id;
149     let post_view = blocking(context.pool(), move |conn| {
150       PostView::read(conn, post_id, Some(local_user_view.person.id))
151     })
152     .await??;
153
154     let res = PostResponse { post_view };
155
156     context.chat_server().do_send(SendPost {
157       op: UserOperation::LockPost,
158       post: res.clone(),
159       websocket_id,
160     });
161
162     Ok(res)
163   }
164 }
165
166 #[async_trait::async_trait(?Send)]
167 impl Perform for StickyPost {
168   type Response = PostResponse;
169
170   async fn perform(
171     &self,
172     context: &Data<LemmyContext>,
173     websocket_id: Option<ConnectionId>,
174   ) -> Result<PostResponse, LemmyError> {
175     let data: &StickyPost = &self;
176     let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
177
178     let post_id = data.post_id;
179     let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
180
181     check_community_ban(
182       local_user_view.person.id,
183       orig_post.community_id,
184       context.pool(),
185     )
186     .await?;
187
188     // Verify that only the mods can sticky
189     is_mod_or_admin(
190       context.pool(),
191       local_user_view.person.id,
192       orig_post.community_id,
193     )
194     .await?;
195
196     // Update the post
197     let post_id = data.post_id;
198     let stickied = data.stickied;
199     let updated_post = blocking(context.pool(), move |conn| {
200       Post::update_stickied(conn, post_id, stickied)
201     })
202     .await??;
203
204     // Mod tables
205     let form = ModStickyPostForm {
206       mod_person_id: local_user_view.person.id,
207       post_id: data.post_id,
208       stickied: Some(stickied),
209     };
210     blocking(context.pool(), move |conn| {
211       ModStickyPost::create(conn, &form)
212     })
213     .await??;
214
215     // Apub updates
216     // TODO stickied should pry work like locked for ease of use
217     updated_post
218       .send_update(&local_user_view.person, context)
219       .await?;
220
221     // Refetch the post
222     let post_id = data.post_id;
223     let post_view = blocking(context.pool(), move |conn| {
224       PostView::read(conn, post_id, Some(local_user_view.person.id))
225     })
226     .await??;
227
228     let res = PostResponse { post_view };
229
230     context.chat_server().do_send(SendPost {
231       op: UserOperation::StickyPost,
232       post: res.clone(),
233       websocket_id,
234     });
235
236     Ok(res)
237   }
238 }
239
240 #[async_trait::async_trait(?Send)]
241 impl Perform for SavePost {
242   type Response = PostResponse;
243
244   async fn perform(
245     &self,
246     context: &Data<LemmyContext>,
247     _websocket_id: Option<ConnectionId>,
248   ) -> Result<PostResponse, LemmyError> {
249     let data: &SavePost = &self;
250     let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
251
252     let post_saved_form = PostSavedForm {
253       post_id: data.post_id,
254       person_id: local_user_view.person.id,
255     };
256
257     if data.save {
258       let save = move |conn: &'_ _| PostSaved::save(conn, &post_saved_form);
259       if blocking(context.pool(), save).await?.is_err() {
260         return Err(ApiError::err("couldnt_save_post").into());
261       }
262     } else {
263       let unsave = move |conn: &'_ _| PostSaved::unsave(conn, &post_saved_form);
264       if blocking(context.pool(), unsave).await?.is_err() {
265         return Err(ApiError::err("couldnt_save_post").into());
266       }
267     }
268
269     let post_id = data.post_id;
270     let person_id = local_user_view.person.id;
271     let post_view = blocking(context.pool(), move |conn| {
272       PostView::read(conn, post_id, Some(person_id))
273     })
274     .await??;
275
276     // Mark the post as read
277     mark_post_as_read(person_id, post_id, context.pool()).await?;
278
279     Ok(PostResponse { post_view })
280   }
281 }