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},
16 fetcher::post_or_comment::PostOrComment,
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;
36 get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
38 let comment_id = data.comment_id;
39 let orig_comment = blocking(context.pool(), move |conn| {
40 CommentView::read(conn, comment_id, None)
45 local_user_view.person.id,
46 orig_comment.community.id,
51 // Verify that only the recipient can mark as read
52 if local_user_view.person.id != orig_comment.get_recipient_id() {
53 return Err(ApiError::err("no_comment_edit_allowed").into());
56 // Do the mark as read
58 blocking(context.pool(), move |conn| {
59 Comment::update_read(conn, comment_id, read)
62 .map_err(|_| ApiError::err("couldnt_update_comment"))?;
65 let comment_id = data.comment_id;
66 let person_id = local_user_view.person.id;
67 let comment_view = blocking(context.pool(), move |conn| {
68 CommentView::read(conn, comment_id, Some(person_id))
72 let res = CommentResponse {
74 recipient_ids: Vec::new(),
82 #[async_trait::async_trait(?Send)]
83 impl Perform for SaveComment {
84 type Response = CommentResponse;
88 context: &Data<LemmyContext>,
89 _websocket_id: Option<ConnectionId>,
90 ) -> Result<CommentResponse, LemmyError> {
91 let data: &SaveComment = self;
93 get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
95 let comment_saved_form = CommentSavedForm {
96 comment_id: data.comment_id,
97 person_id: local_user_view.person.id,
101 let save_comment = move |conn: &'_ _| CommentSaved::save(conn, &comment_saved_form);
102 if blocking(context.pool(), save_comment).await?.is_err() {
103 return Err(ApiError::err("couldnt_save_comment").into());
106 let unsave_comment = move |conn: &'_ _| CommentSaved::unsave(conn, &comment_saved_form);
107 if blocking(context.pool(), unsave_comment).await?.is_err() {
108 return Err(ApiError::err("couldnt_save_comment").into());
112 let comment_id = data.comment_id;
113 let person_id = local_user_view.person.id;
114 let comment_view = blocking(context.pool(), move |conn| {
115 CommentView::read(conn, comment_id, Some(person_id))
121 recipient_ids: Vec::new(),
127 #[async_trait::async_trait(?Send)]
128 impl Perform for CreateCommentLike {
129 type Response = CommentResponse;
133 context: &Data<LemmyContext>,
134 websocket_id: Option<ConnectionId>,
135 ) -> Result<CommentResponse, LemmyError> {
136 let data: &CreateCommentLike = self;
137 let local_user_view =
138 get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
140 let mut recipient_ids = Vec::<LocalUserId>::new();
142 // Don't do a downvote if site has downvotes disabled
143 check_downvotes_enabled(data.score, context.pool()).await?;
145 let comment_id = data.comment_id;
146 let orig_comment = blocking(context.pool(), move |conn| {
147 CommentView::read(conn, comment_id, None)
152 local_user_view.person.id,
153 orig_comment.community.id,
159 local_user_view.person.id,
160 orig_comment.get_recipient_id(),
165 // Add parent user to recipients
166 let recipient_id = orig_comment.get_recipient_id();
167 if let Ok(local_recipient) = blocking(context.pool(), move |conn| {
168 LocalUserView::read_person(conn, recipient_id)
172 recipient_ids.push(local_recipient.local_user.id);
175 let like_form = CommentLikeForm {
176 comment_id: data.comment_id,
177 post_id: orig_comment.post.id,
178 person_id: local_user_view.person.id,
182 // Remove any likes first
183 let person_id = local_user_view.person.id;
184 blocking(context.pool(), move |conn| {
185 CommentLike::remove(conn, person_id, comment_id)
189 // Only add the like if the score isnt 0
190 let comment = orig_comment.comment;
191 let object = PostOrComment::Comment(Box::new(comment));
192 let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
194 let like_form2 = like_form.clone();
195 let like = move |conn: &'_ _| CommentLike::like(conn, &like_form2);
196 if blocking(context.pool(), like).await?.is_err() {
197 return Err(ApiError::err("couldnt_like_comment").into());
202 &local_user_view.person,
203 orig_comment.community.id,
204 like_form.score.try_into()?,
209 // API doesn't distinguish between Undo/Like and Undo/Dislike
212 &local_user_view.person,
213 orig_comment.community.id,
220 send_comment_ws_message(
222 UserOperation::CreateCommentLike,
225 Some(local_user_view.person.id),