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)
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(LemmyError::from_message("no_comment_edit_allowed"));
62 // Do the mark as read
64 blocking(context.pool(), move |conn| {
65 Comment::update_read(conn, comment_id, read)
68 .map_err(LemmyError::from)
69 .map_err(|e| e.with_message("couldnt_update_comment"))?;
72 let comment_id = data.comment_id;
73 let person_id = local_user_view.person.id;
74 let comment_view = blocking(context.pool(), move |conn| {
75 CommentView::read(conn, comment_id, Some(person_id))
79 let res = CommentResponse {
81 recipient_ids: Vec::new(),
89 #[async_trait::async_trait(?Send)]
90 impl Perform for SaveComment {
91 type Response = CommentResponse;
93 #[tracing::instrument(skip(context, _websocket_id))]
96 context: &Data<LemmyContext>,
97 _websocket_id: Option<ConnectionId>,
98 ) -> Result<CommentResponse, LemmyError> {
99 let data: &SaveComment = self;
100 let local_user_view =
101 get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
103 let comment_saved_form = CommentSavedForm {
104 comment_id: data.comment_id,
105 person_id: local_user_view.person.id,
109 let save_comment = move |conn: &'_ _| CommentSaved::save(conn, &comment_saved_form);
110 blocking(context.pool(), save_comment)
112 .map_err(LemmyError::from)
113 .map_err(|e| e.with_message("couldnt_save_comment"))?;
115 let unsave_comment = move |conn: &'_ _| CommentSaved::unsave(conn, &comment_saved_form);
116 blocking(context.pool(), unsave_comment)
118 .map_err(LemmyError::from)
119 .map_err(|e| e.with_message("couldnt_save_comment"))?;
122 let comment_id = data.comment_id;
123 let person_id = local_user_view.person.id;
124 let comment_view = blocking(context.pool(), move |conn| {
125 CommentView::read(conn, comment_id, Some(person_id))
131 recipient_ids: Vec::new(),
137 #[async_trait::async_trait(?Send)]
138 impl Perform for CreateCommentLike {
139 type Response = CommentResponse;
141 #[tracing::instrument(skip(context, websocket_id))]
144 context: &Data<LemmyContext>,
145 websocket_id: Option<ConnectionId>,
146 ) -> Result<CommentResponse, LemmyError> {
147 let data: &CreateCommentLike = self;
148 let local_user_view =
149 get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
151 let mut recipient_ids = Vec::<LocalUserId>::new();
153 // Don't do a downvote if site has downvotes disabled
154 check_downvotes_enabled(data.score, context.pool()).await?;
156 let comment_id = data.comment_id;
157 let orig_comment = blocking(context.pool(), move |conn| {
158 CommentView::read(conn, comment_id, None)
163 local_user_view.person.id,
164 orig_comment.community.id,
169 // Add parent user to recipients
170 let recipient_id = orig_comment.get_recipient_id();
171 if let Ok(local_recipient) = blocking(context.pool(), move |conn| {
172 LocalUserView::read_person(conn, recipient_id)
176 recipient_ids.push(local_recipient.local_user.id);
179 let like_form = CommentLikeForm {
180 comment_id: data.comment_id,
181 post_id: orig_comment.post.id,
182 person_id: local_user_view.person.id,
186 // Remove any likes first
187 let person_id = local_user_view.person.id;
188 blocking(context.pool(), move |conn| {
189 CommentLike::remove(conn, person_id, comment_id)
193 // Only add the like if the score isnt 0
194 let comment = orig_comment.comment;
195 let object = PostOrComment::Comment(Box::new(comment.into()));
196 let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
198 let like_form2 = like_form.clone();
199 let like = move |conn: &'_ _| CommentLike::like(conn, &like_form2);
200 blocking(context.pool(), like)
202 .map_err(LemmyError::from)
203 .map_err(|e| e.with_message("couldnt_like_comment"))?;
207 &local_user_view.person.clone().into(),
208 orig_comment.community.id,
209 like_form.score.try_into()?,
214 // API doesn't distinguish between Undo/Like and Undo/Dislike
217 &local_user_view.person.clone().into(),
218 orig_comment.community.id,
225 send_comment_ws_message(
227 UserOperation::CreateCommentLike,
230 Some(local_user_view.person.id),