1 use std::convert::TryInto;
3 use actix_web::web::Data;
5 use lemmy_api_common::{
8 check_downvotes_enabled,
10 get_local_user_view_from_jwt,
13 fetcher::post_or_comment::PostOrComment,
14 protocol::activities::voting::{
16 vote::{Vote, VoteType},
19 use lemmy_db_schema::{
20 newtypes::LocalUserId,
22 traits::{Likeable, Saveable},
24 use lemmy_db_views::{comment_view::CommentView, local_user_view::LocalUserView};
25 use lemmy_utils::{ConnectionId, LemmyError};
26 use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperation};
30 #[async_trait::async_trait(?Send)]
31 impl Perform for MarkCommentAsRead {
32 type Response = CommentResponse;
34 #[tracing::instrument(skip(context, _websocket_id))]
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)
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(LemmyError::from_message("no_comment_edit_allowed"));
55 // Do the mark as read
57 blocking(context.pool(), move |conn| {
58 Comment::update_read(conn, comment_id, read)
61 .map_err(LemmyError::from)
62 .map_err(|e| e.with_message("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;
86 #[tracing::instrument(skip(context, _websocket_id))]
89 context: &Data<LemmyContext>,
90 _websocket_id: Option<ConnectionId>,
91 ) -> Result<CommentResponse, LemmyError> {
92 let data: &SaveComment = self;
94 get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
96 let comment_saved_form = CommentSavedForm {
97 comment_id: data.comment_id,
98 person_id: local_user_view.person.id,
102 let save_comment = move |conn: &'_ _| CommentSaved::save(conn, &comment_saved_form);
103 blocking(context.pool(), save_comment)
105 .map_err(LemmyError::from)
106 .map_err(|e| e.with_message("couldnt_save_comment"))?;
108 let unsave_comment = move |conn: &'_ _| CommentSaved::unsave(conn, &comment_saved_form);
109 blocking(context.pool(), unsave_comment)
111 .map_err(LemmyError::from)
112 .map_err(|e| e.with_message("couldnt_save_comment"))?;
115 let comment_id = data.comment_id;
116 let person_id = local_user_view.person.id;
117 let comment_view = blocking(context.pool(), move |conn| {
118 CommentView::read(conn, comment_id, Some(person_id))
124 recipient_ids: Vec::new(),
130 #[async_trait::async_trait(?Send)]
131 impl Perform for CreateCommentLike {
132 type Response = CommentResponse;
134 #[tracing::instrument(skip(context, websocket_id))]
137 context: &Data<LemmyContext>,
138 websocket_id: Option<ConnectionId>,
139 ) -> Result<CommentResponse, LemmyError> {
140 let data: &CreateCommentLike = self;
141 let local_user_view =
142 get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
144 let mut recipient_ids = Vec::<LocalUserId>::new();
146 // Don't do a downvote if site has downvotes disabled
147 check_downvotes_enabled(data.score, context.pool()).await?;
149 let comment_id = data.comment_id;
150 let orig_comment = blocking(context.pool(), move |conn| {
151 CommentView::read(conn, comment_id, None)
156 local_user_view.person.id,
157 orig_comment.community.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.into()));
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 blocking(context.pool(), like)
195 .map_err(LemmyError::from)
196 .map_err(|e| e.with_message("couldnt_like_comment"))?;
200 &local_user_view.person.clone().into(),
201 orig_comment.community.id,
202 like_form.score.try_into()?,
207 // API doesn't distinguish between Undo/Like and Undo/Dislike
210 &local_user_view.person.clone().into(),
211 orig_comment.community.id,
218 send_comment_ws_message(
220 UserOperation::CreateCommentLike,
223 Some(local_user_view.person.id),