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::{send::send_post_ws_message, 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?;
101 UserOperation::CreatePostLike,
103 Some(local_user_view.person.id),
110 #[async_trait::async_trait(?Send)]
111 impl Perform for LockPost {
112 type Response = PostResponse;
116 context: &Data<LemmyContext>,
117 websocket_id: Option<ConnectionId>,
118 ) -> Result<PostResponse, LemmyError> {
119 let data: &LockPost = self;
120 let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
122 let post_id = data.post_id;
123 let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
126 local_user_view.person.id,
127 orig_post.community_id,
132 // Verify that only the mods can lock
135 local_user_view.person.id,
136 orig_post.community_id,
141 let post_id = data.post_id;
142 let locked = data.locked;
143 let updated_post = blocking(context.pool(), move |conn| {
144 Post::update_locked(conn, post_id, locked)
149 let form = ModLockPostForm {
150 mod_person_id: local_user_view.person.id,
151 post_id: data.post_id,
152 locked: Some(locked),
154 blocking(context.pool(), move |conn| ModLockPost::create(conn, &form)).await??;
157 CreateOrUpdatePost::send(
159 &local_user_view.person,
160 CreateOrUpdateType::Update,
165 send_post_ws_message(
167 UserOperation::LockPost,
169 Some(local_user_view.person.id),
176 #[async_trait::async_trait(?Send)]
177 impl Perform for StickyPost {
178 type Response = PostResponse;
182 context: &Data<LemmyContext>,
183 websocket_id: Option<ConnectionId>,
184 ) -> Result<PostResponse, LemmyError> {
185 let data: &StickyPost = self;
186 let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
188 let post_id = data.post_id;
189 let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
192 local_user_view.person.id,
193 orig_post.community_id,
198 // Verify that only the mods can sticky
201 local_user_view.person.id,
202 orig_post.community_id,
207 let post_id = data.post_id;
208 let stickied = data.stickied;
209 let updated_post = blocking(context.pool(), move |conn| {
210 Post::update_stickied(conn, post_id, stickied)
215 let form = ModStickyPostForm {
216 mod_person_id: local_user_view.person.id,
217 post_id: data.post_id,
218 stickied: Some(stickied),
220 blocking(context.pool(), move |conn| {
221 ModStickyPost::create(conn, &form)
226 // TODO stickied should pry work like locked for ease of use
227 CreateOrUpdatePost::send(
229 &local_user_view.person,
230 CreateOrUpdateType::Update,
235 send_post_ws_message(
237 UserOperation::StickyPost,
239 Some(local_user_view.person.id),
246 #[async_trait::async_trait(?Send)]
247 impl Perform for SavePost {
248 type Response = PostResponse;
252 context: &Data<LemmyContext>,
253 _websocket_id: Option<ConnectionId>,
254 ) -> Result<PostResponse, LemmyError> {
255 let data: &SavePost = self;
256 let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
258 let post_saved_form = PostSavedForm {
259 post_id: data.post_id,
260 person_id: local_user_view.person.id,
264 let save = move |conn: &'_ _| PostSaved::save(conn, &post_saved_form);
265 if blocking(context.pool(), save).await?.is_err() {
266 return Err(ApiError::err("couldnt_save_post").into());
269 let unsave = move |conn: &'_ _| PostSaved::unsave(conn, &post_saved_form);
270 if blocking(context.pool(), unsave).await?.is_err() {
271 return Err(ApiError::err("couldnt_save_post").into());
275 let post_id = data.post_id;
276 let person_id = local_user_view.person.id;
277 let post_view = blocking(context.pool(), move |conn| {
278 PostView::read(conn, post_id, Some(person_id))
282 // Mark the post as read
283 mark_post_as_read(person_id, post_id, context.pool()).await?;
285 Ok(PostResponse { post_view })