2 use actix_web::web::Data;
3 use lemmy_api_common::{
6 check_downvotes_enabled,
9 get_local_user_view_from_jwt,
14 vote::{Vote, VoteType},
18 use lemmy_db_queries::{source::comment::Comment_, Likeable, Saveable};
19 use lemmy_db_schema::{source::comment::*, LocalUserId};
20 use lemmy_db_views::{comment_view::CommentView, local_user_view::LocalUserView};
21 use lemmy_utils::{ApiError, ConnectionId, LemmyError};
22 use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperation};
23 use std::convert::TryInto;
25 #[async_trait::async_trait(?Send)]
26 impl Perform for MarkCommentAsRead {
27 type Response = CommentResponse;
31 context: &Data<LemmyContext>,
32 _websocket_id: Option<ConnectionId>,
33 ) -> Result<CommentResponse, LemmyError> {
34 let data: &MarkCommentAsRead = self;
35 let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
37 let comment_id = data.comment_id;
38 let orig_comment = blocking(context.pool(), move |conn| {
39 CommentView::read(conn, comment_id, None)
44 local_user_view.person.id,
45 orig_comment.community.id,
50 // Verify that only the recipient can mark as read
51 if local_user_view.person.id != orig_comment.get_recipient_id() {
52 return Err(ApiError::err("no_comment_edit_allowed").into());
55 // Do the mark as read
57 blocking(context.pool(), move |conn| {
58 Comment::update_read(conn, comment_id, read)
61 .map_err(|_| ApiError::err("couldnt_update_comment"))?;
64 let comment_id = data.comment_id;
65 let person_id = local_user_view.person.id;
66 let comment_view = blocking(context.pool(), move |conn| {
67 CommentView::read(conn, comment_id, Some(person_id))
71 let res = CommentResponse {
73 recipient_ids: Vec::new(),
81 #[async_trait::async_trait(?Send)]
82 impl Perform for SaveComment {
83 type Response = CommentResponse;
87 context: &Data<LemmyContext>,
88 _websocket_id: Option<ConnectionId>,
89 ) -> Result<CommentResponse, LemmyError> {
90 let data: &SaveComment = self;
91 let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
93 let comment_saved_form = CommentSavedForm {
94 comment_id: data.comment_id,
95 person_id: local_user_view.person.id,
99 let save_comment = move |conn: &'_ _| CommentSaved::save(conn, &comment_saved_form);
100 if blocking(context.pool(), save_comment).await?.is_err() {
101 return Err(ApiError::err("couldnt_save_comment").into());
104 let unsave_comment = move |conn: &'_ _| CommentSaved::unsave(conn, &comment_saved_form);
105 if blocking(context.pool(), unsave_comment).await?.is_err() {
106 return Err(ApiError::err("couldnt_save_comment").into());
110 let comment_id = data.comment_id;
111 let person_id = local_user_view.person.id;
112 let comment_view = blocking(context.pool(), move |conn| {
113 CommentView::read(conn, comment_id, Some(person_id))
119 recipient_ids: Vec::new(),
125 #[async_trait::async_trait(?Send)]
126 impl Perform for CreateCommentLike {
127 type Response = CommentResponse;
131 context: &Data<LemmyContext>,
132 websocket_id: Option<ConnectionId>,
133 ) -> Result<CommentResponse, LemmyError> {
134 let data: &CreateCommentLike = self;
135 let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
137 let mut recipient_ids = Vec::<LocalUserId>::new();
139 // Don't do a downvote if site has downvotes disabled
140 check_downvotes_enabled(data.score, context.pool()).await?;
142 let comment_id = data.comment_id;
143 let orig_comment = blocking(context.pool(), move |conn| {
144 CommentView::read(conn, comment_id, None)
149 local_user_view.person.id,
150 orig_comment.community.id,
156 local_user_view.person.id,
157 orig_comment.get_recipient_id(),
162 // Add parent user to recipients
163 let recipient_id = orig_comment.get_recipient_id();
164 if let Ok(local_recipient) = blocking(context.pool(), move |conn| {
165 LocalUserView::read_person(conn, recipient_id)
169 recipient_ids.push(local_recipient.local_user.id);
172 let like_form = CommentLikeForm {
173 comment_id: data.comment_id,
174 post_id: orig_comment.post.id,
175 person_id: local_user_view.person.id,
179 // Remove any likes first
180 let person_id = local_user_view.person.id;
181 blocking(context.pool(), move |conn| {
182 CommentLike::remove(conn, person_id, comment_id)
186 // Only add the like if the score isnt 0
187 let comment = orig_comment.comment;
188 let object = PostOrComment::Comment(Box::new(comment));
189 let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
191 let like_form2 = like_form.clone();
192 let like = move |conn: &'_ _| CommentLike::like(conn, &like_form2);
193 if blocking(context.pool(), like).await?.is_err() {
194 return Err(ApiError::err("couldnt_like_comment").into());
199 &local_user_view.person,
200 orig_comment.community.id,
201 like_form.score.try_into()?,
206 // API doesn't distinguish between Undo/Like and Undo/Dislike
209 &local_user_view.person,
210 orig_comment.community.id,
217 send_comment_ws_message(
219 UserOperation::CreateCommentLike,
222 Some(local_user_view.person.id),