2 use actix_web::web::Data;
3 use lemmy_api_common::{
6 check_downvotes_enabled,
7 get_local_user_view_from_jwt,
14 post::create_or_update::CreateOrUpdatePost,
17 vote::{Vote, VoteType},
23 use lemmy_db_queries::{source::post::Post_, Crud, Likeable, Saveable};
24 use lemmy_db_schema::source::{moderator::*, post::*};
25 use lemmy_db_views::post_view::PostView;
26 use lemmy_utils::{ApiError, ConnectionId, LemmyError};
27 use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation};
28 use std::convert::TryInto;
30 #[async_trait::async_trait(?Send)]
31 impl Perform for CreatePostLike {
32 type Response = PostResponse;
36 context: &Data<LemmyContext>,
37 websocket_id: Option<ConnectionId>,
38 ) -> Result<PostResponse, LemmyError> {
39 let data: &CreatePostLike = self;
40 let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
42 // Don't do a downvote if site has downvotes disabled
43 check_downvotes_enabled(data.score, context.pool()).await?;
45 // Check for a community ban
46 let post_id = data.post_id;
47 let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
49 check_community_ban(local_user_view.person.id, post.community_id, context.pool()).await?;
51 let like_form = PostLikeForm {
52 post_id: data.post_id,
53 person_id: local_user_view.person.id,
57 // Remove any likes first
58 let person_id = local_user_view.person.id;
59 blocking(context.pool(), move |conn| {
60 PostLike::remove(conn, person_id, post_id)
64 let community_id = post.community_id;
65 let object = PostOrComment::Post(Box::new(post));
67 // Only add the like if the score isnt 0
68 let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
70 let like_form2 = like_form.clone();
71 let like = move |conn: &'_ _| PostLike::like(conn, &like_form2);
72 if blocking(context.pool(), like).await?.is_err() {
73 return Err(ApiError::err("couldnt_like_post").into());
78 &local_user_view.person,
80 like_form.score.try_into()?,
85 // API doesn't distinguish between Undo/Like and Undo/Dislike
88 &local_user_view.person,
96 // Mark the post as read
97 mark_post_as_read(person_id, post_id, context.pool()).await?;
99 let post_id = data.post_id;
100 let person_id = local_user_view.person.id;
101 let post_view = blocking(context.pool(), move |conn| {
102 PostView::read(conn, post_id, Some(person_id))
105 .map_err(|_| ApiError::err("couldnt_find_post"))?;
107 let res = PostResponse { post_view };
109 context.chat_server().do_send(SendPost {
110 op: UserOperation::CreatePostLike,
119 #[async_trait::async_trait(?Send)]
120 impl Perform for LockPost {
121 type Response = PostResponse;
125 context: &Data<LemmyContext>,
126 websocket_id: Option<ConnectionId>,
127 ) -> Result<PostResponse, LemmyError> {
128 let data: &LockPost = self;
129 let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
131 let post_id = data.post_id;
132 let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
135 local_user_view.person.id,
136 orig_post.community_id,
141 // Verify that only the mods can lock
144 local_user_view.person.id,
145 orig_post.community_id,
150 let post_id = data.post_id;
151 let locked = data.locked;
152 let updated_post = blocking(context.pool(), move |conn| {
153 Post::update_locked(conn, post_id, locked)
158 let form = ModLockPostForm {
159 mod_person_id: local_user_view.person.id,
160 post_id: data.post_id,
161 locked: Some(locked),
163 blocking(context.pool(), move |conn| ModLockPost::create(conn, &form)).await??;
166 CreateOrUpdatePost::send(
168 &local_user_view.person,
169 CreateOrUpdateType::Update,
175 let post_id = data.post_id;
176 let post_view = blocking(context.pool(), move |conn| {
177 PostView::read(conn, post_id, Some(local_user_view.person.id))
181 let res = PostResponse { post_view };
183 context.chat_server().do_send(SendPost {
184 op: UserOperation::LockPost,
193 #[async_trait::async_trait(?Send)]
194 impl Perform for StickyPost {
195 type Response = PostResponse;
199 context: &Data<LemmyContext>,
200 websocket_id: Option<ConnectionId>,
201 ) -> Result<PostResponse, LemmyError> {
202 let data: &StickyPost = self;
203 let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
205 let post_id = data.post_id;
206 let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
209 local_user_view.person.id,
210 orig_post.community_id,
215 // Verify that only the mods can sticky
218 local_user_view.person.id,
219 orig_post.community_id,
224 let post_id = data.post_id;
225 let stickied = data.stickied;
226 let updated_post = blocking(context.pool(), move |conn| {
227 Post::update_stickied(conn, post_id, stickied)
232 let form = ModStickyPostForm {
233 mod_person_id: local_user_view.person.id,
234 post_id: data.post_id,
235 stickied: Some(stickied),
237 blocking(context.pool(), move |conn| {
238 ModStickyPost::create(conn, &form)
243 // TODO stickied should pry work like locked for ease of use
244 CreateOrUpdatePost::send(
246 &local_user_view.person,
247 CreateOrUpdateType::Update,
253 let post_id = data.post_id;
254 let post_view = blocking(context.pool(), move |conn| {
255 PostView::read(conn, post_id, Some(local_user_view.person.id))
259 let res = PostResponse { post_view };
261 context.chat_server().do_send(SendPost {
262 op: UserOperation::StickyPost,
271 #[async_trait::async_trait(?Send)]
272 impl Perform for SavePost {
273 type Response = PostResponse;
277 context: &Data<LemmyContext>,
278 _websocket_id: Option<ConnectionId>,
279 ) -> Result<PostResponse, LemmyError> {
280 let data: &SavePost = self;
281 let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
283 let post_saved_form = PostSavedForm {
284 post_id: data.post_id,
285 person_id: local_user_view.person.id,
289 let save = move |conn: &'_ _| PostSaved::save(conn, &post_saved_form);
290 if blocking(context.pool(), save).await?.is_err() {
291 return Err(ApiError::err("couldnt_save_post").into());
294 let unsave = move |conn: &'_ _| PostSaved::unsave(conn, &post_saved_form);
295 if blocking(context.pool(), unsave).await?.is_err() {
296 return Err(ApiError::err("couldnt_save_post").into());
300 let post_id = data.post_id;
301 let person_id = local_user_view.person.id;
302 let post_view = blocking(context.pool(), move |conn| {
303 PostView::read(conn, post_id, Some(person_id))
307 // Mark the post as read
308 mark_post_as_read(person_id, post_id, context.pool()).await?;
310 Ok(PostResponse { post_view })