]> Untitled Git - lemmy.git/blob - crates/api_crud/src/comment/delete.rs
Don't drop error context when adding a message to errors (#1958)
[lemmy.git] / crates / api_crud / src / comment / delete.rs
1 use crate::PerformCrud;
2 use actix_web::web::Data;
3 use lemmy_api_common::{
4   blocking,
5   check_community_ban,
6   comment::*,
7   get_local_user_view_from_jwt,
8   is_mod_or_admin,
9 };
10 use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove, DeletableObjects};
11 use lemmy_db_schema::{
12   source::{
13     comment::Comment,
14     community::Community,
15     moderator::{ModRemoveComment, ModRemoveCommentForm},
16     post::Post,
17   },
18   traits::Crud,
19 };
20 use lemmy_db_views::comment_view::CommentView;
21 use lemmy_utils::{ConnectionId, LemmyError};
22 use lemmy_websocket::{
23   send::{send_comment_ws_message, send_local_notifs},
24   LemmyContext,
25   UserOperationCrud,
26 };
27
28 #[async_trait::async_trait(?Send)]
29 impl PerformCrud for DeleteComment {
30   type Response = CommentResponse;
31
32   #[tracing::instrument(skip(context, websocket_id))]
33   async fn perform(
34     &self,
35     context: &Data<LemmyContext>,
36     websocket_id: Option<ConnectionId>,
37   ) -> Result<CommentResponse, LemmyError> {
38     let data: &DeleteComment = self;
39     let local_user_view =
40       get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
41
42     let comment_id = data.comment_id;
43     let orig_comment = blocking(context.pool(), move |conn| {
44       CommentView::read(conn, comment_id, None)
45     })
46     .await??;
47
48     // Dont delete it if its already been deleted.
49     if orig_comment.comment.deleted == data.deleted {
50       return Err(LemmyError::from_message("couldnt_update_comment"));
51     }
52
53     check_community_ban(
54       local_user_view.person.id,
55       orig_comment.community.id,
56       context.pool(),
57     )
58     .await?;
59
60     // Verify that only the creator can delete
61     if local_user_view.person.id != orig_comment.creator.id {
62       return Err(LemmyError::from_message("no_comment_edit_allowed"));
63     }
64
65     // Do the delete
66     let deleted = data.deleted;
67     let updated_comment = blocking(context.pool(), move |conn| {
68       Comment::update_deleted(conn, comment_id, deleted)
69     })
70     .await?
71     .map_err(LemmyError::from)
72     .map_err(|e| e.with_message("couldnt_update_comment"))?;
73
74     let post_id = updated_comment.post_id;
75     let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
76     let recipient_ids = send_local_notifs(
77       vec![],
78       &updated_comment,
79       &local_user_view.person,
80       &post,
81       false,
82       context,
83     )
84     .await?;
85
86     // Send the apub message
87     let community = blocking(context.pool(), move |conn| {
88       Community::read(conn, orig_comment.post.community_id)
89     })
90     .await??;
91     send_apub_delete(
92       &local_user_view.person.clone().into(),
93       &community.clone().into(),
94       DeletableObjects::Comment(Box::new(updated_comment.into())),
95       deleted,
96       context,
97     )
98     .await?;
99
100     send_comment_ws_message(
101       data.comment_id,
102       UserOperationCrud::DeleteComment,
103       websocket_id,
104       None, // TODO a comment delete might clear forms?
105       Some(local_user_view.person.id),
106       recipient_ids,
107       context,
108     )
109     .await
110   }
111 }
112
113 #[async_trait::async_trait(?Send)]
114 impl PerformCrud for RemoveComment {
115   type Response = CommentResponse;
116
117   #[tracing::instrument(skip(context, websocket_id))]
118   async fn perform(
119     &self,
120     context: &Data<LemmyContext>,
121     websocket_id: Option<ConnectionId>,
122   ) -> Result<CommentResponse, LemmyError> {
123     let data: &RemoveComment = self;
124     let local_user_view =
125       get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
126
127     let comment_id = data.comment_id;
128     let orig_comment = blocking(context.pool(), move |conn| {
129       CommentView::read(conn, comment_id, None)
130     })
131     .await??;
132
133     check_community_ban(
134       local_user_view.person.id,
135       orig_comment.community.id,
136       context.pool(),
137     )
138     .await?;
139
140     // Verify that only a mod or admin can remove
141     is_mod_or_admin(
142       context.pool(),
143       local_user_view.person.id,
144       orig_comment.community.id,
145     )
146     .await?;
147
148     // Do the remove
149     let removed = data.removed;
150     let updated_comment = blocking(context.pool(), move |conn| {
151       Comment::update_removed(conn, comment_id, removed)
152     })
153     .await?
154     .map_err(LemmyError::from)
155     .map_err(|e| e.with_message("couldnt_update_comment"))?;
156
157     // Mod tables
158     let form = ModRemoveCommentForm {
159       mod_person_id: local_user_view.person.id,
160       comment_id: data.comment_id,
161       removed: Some(removed),
162       reason: data.reason.to_owned(),
163     };
164     blocking(context.pool(), move |conn| {
165       ModRemoveComment::create(conn, &form)
166     })
167     .await??;
168
169     let post_id = updated_comment.post_id;
170     let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
171     let recipient_ids = send_local_notifs(
172       vec![],
173       &updated_comment,
174       &local_user_view.person.clone(),
175       &post,
176       false,
177       context,
178     )
179     .await?;
180
181     // Send the apub message
182     let community = blocking(context.pool(), move |conn| {
183       Community::read(conn, orig_comment.post.community_id)
184     })
185     .await??;
186     send_apub_remove(
187       &local_user_view.person.clone().into(),
188       &community.into(),
189       DeletableObjects::Comment(Box::new(updated_comment.into())),
190       data.reason.clone().unwrap_or_else(|| "".to_string()),
191       removed,
192       context,
193     )
194     .await?;
195
196     send_comment_ws_message(
197       data.comment_id,
198       UserOperationCrud::RemoveComment,
199       websocket_id,
200       None, // TODO maybe this might clear other forms
201       Some(local_user_view.person.id),
202       recipient_ids,
203       context,
204     )
205     .await
206   }
207 }