1 use std::convert::TryInto;
3 use actix_web::web::Data;
5 use lemmy_api_common::{
8 check_downvotes_enabled,
11 get_local_user_view_from_jwt,
14 fetcher::post_or_comment::PostOrComment,
15 protocol::activities::voting::{
17 vote::{Vote, VoteType},
20 use lemmy_db_schema::{
21 newtypes::LocalUserId,
23 traits::{Likeable, Saveable},
25 use lemmy_db_views::{comment_view::CommentView, local_user_view::LocalUserView};
26 use lemmy_utils::{ApiError, ConnectionId, LemmyError};
27 use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperation};
31 #[async_trait::async_trait(?Send)]
32 impl Perform for MarkCommentAsRead {
33 type Response = CommentResponse;
37 context: &Data<LemmyContext>,
38 _websocket_id: Option<ConnectionId>,
39 ) -> Result<CommentResponse, LemmyError> {
40 let data: &MarkCommentAsRead = self;
42 get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
44 let comment_id = data.comment_id;
45 let orig_comment = blocking(context.pool(), move |conn| {
46 CommentView::read(conn, comment_id, None)
51 local_user_view.person.id,
52 orig_comment.community.id,
57 // Verify that only the recipient can mark as read
58 if local_user_view.person.id != orig_comment.get_recipient_id() {
59 return Err(ApiError::err_plain("no_comment_edit_allowed").into());
62 // Do the mark as read
64 blocking(context.pool(), move |conn| {
65 Comment::update_read(conn, comment_id, read)
68 .map_err(|_| ApiError::err_plain("couldnt_update_comment"))?;
71 let comment_id = data.comment_id;
72 let person_id = local_user_view.person.id;
73 let comment_view = blocking(context.pool(), move |conn| {
74 CommentView::read(conn, comment_id, Some(person_id))
78 let res = CommentResponse {
80 recipient_ids: Vec::new(),
88 #[async_trait::async_trait(?Send)]
89 impl Perform for SaveComment {
90 type Response = CommentResponse;
94 context: &Data<LemmyContext>,
95 _websocket_id: Option<ConnectionId>,
96 ) -> Result<CommentResponse, LemmyError> {
97 let data: &SaveComment = self;
99 get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
101 let comment_saved_form = CommentSavedForm {
102 comment_id: data.comment_id,
103 person_id: local_user_view.person.id,
107 let save_comment = move |conn: &'_ _| CommentSaved::save(conn, &comment_saved_form);
108 blocking(context.pool(), save_comment)
110 .map_err(|e| ApiError::err("couldnt_save_comment", e))?;
112 let unsave_comment = move |conn: &'_ _| CommentSaved::unsave(conn, &comment_saved_form);
113 blocking(context.pool(), unsave_comment)
115 .map_err(|e| ApiError::err("couldnt_save_comment", e))?;
118 let comment_id = data.comment_id;
119 let person_id = local_user_view.person.id;
120 let comment_view = blocking(context.pool(), move |conn| {
121 CommentView::read(conn, comment_id, Some(person_id))
127 recipient_ids: Vec::new(),
133 #[async_trait::async_trait(?Send)]
134 impl Perform for CreateCommentLike {
135 type Response = CommentResponse;
139 context: &Data<LemmyContext>,
140 websocket_id: Option<ConnectionId>,
141 ) -> Result<CommentResponse, LemmyError> {
142 let data: &CreateCommentLike = self;
143 let local_user_view =
144 get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
146 let mut recipient_ids = Vec::<LocalUserId>::new();
148 // Don't do a downvote if site has downvotes disabled
149 check_downvotes_enabled(data.score, context.pool()).await?;
151 let comment_id = data.comment_id;
152 let orig_comment = blocking(context.pool(), move |conn| {
153 CommentView::read(conn, comment_id, None)
158 local_user_view.person.id,
159 orig_comment.community.id,
165 local_user_view.person.id,
166 orig_comment.get_recipient_id(),
171 // Add parent user to recipients
172 let recipient_id = orig_comment.get_recipient_id();
173 if let Ok(local_recipient) = blocking(context.pool(), move |conn| {
174 LocalUserView::read_person(conn, recipient_id)
178 recipient_ids.push(local_recipient.local_user.id);
181 let like_form = CommentLikeForm {
182 comment_id: data.comment_id,
183 post_id: orig_comment.post.id,
184 person_id: local_user_view.person.id,
188 // Remove any likes first
189 let person_id = local_user_view.person.id;
190 blocking(context.pool(), move |conn| {
191 CommentLike::remove(conn, person_id, comment_id)
195 // Only add the like if the score isnt 0
196 let comment = orig_comment.comment;
197 let object = PostOrComment::Comment(Box::new(comment.into()));
198 let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
200 let like_form2 = like_form.clone();
201 let like = move |conn: &'_ _| CommentLike::like(conn, &like_form2);
202 blocking(context.pool(), like)
204 .map_err(|e| ApiError::err("couldnt_like_comment", e))?;
208 &local_user_view.person.clone().into(),
209 orig_comment.community.id,
210 like_form.score.try_into()?,
215 // API doesn't distinguish between Undo/Like and Undo/Dislike
218 &local_user_view.person.clone().into(),
219 orig_comment.community.id,
226 send_comment_ws_message(
228 UserOperation::CreateCommentLike,
231 Some(local_user_view.person.id),