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