]> Untitled Git - lemmy.git/blob - crates/api_crud/src/comment/delete.rs
adbc3cc5b668496becce853120184a54e699a2f2
[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_in_community, 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     let res = send_comment_ws_message(
87       data.comment_id,
88       UserOperationCrud::DeleteComment,
89       websocket_id,
90       None, // TODO a comment delete might clear forms?
91       Some(local_user_view.person.id),
92       recipient_ids,
93       context,
94     )
95     .await?;
96
97     // Send the apub message
98     let community = blocking(context.pool(), move |conn| {
99       Community::read(conn, orig_comment.post.community_id)
100     })
101     .await??;
102     let deletable = DeletableObjects::Comment(Box::new(updated_comment.clone().into()));
103     send_apub_delete_in_community(
104       local_user_view.person,
105       community,
106       deletable,
107       None,
108       deleted,
109       context,
110     )
111     .await?;
112
113     Ok(res)
114   }
115 }
116
117 #[async_trait::async_trait(?Send)]
118 impl PerformCrud for RemoveComment {
119   type Response = CommentResponse;
120
121   #[tracing::instrument(skip(context, websocket_id))]
122   async fn perform(
123     &self,
124     context: &Data<LemmyContext>,
125     websocket_id: Option<ConnectionId>,
126   ) -> Result<CommentResponse, LemmyError> {
127     let data: &RemoveComment = self;
128     let local_user_view =
129       get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
130
131     let comment_id = data.comment_id;
132     let orig_comment = blocking(context.pool(), move |conn| {
133       CommentView::read(conn, comment_id, None)
134     })
135     .await??;
136
137     check_community_ban(
138       local_user_view.person.id,
139       orig_comment.community.id,
140       context.pool(),
141     )
142     .await?;
143
144     // Verify that only a mod or admin can remove
145     is_mod_or_admin(
146       context.pool(),
147       local_user_view.person.id,
148       orig_comment.community.id,
149     )
150     .await?;
151
152     // Do the remove
153     let removed = data.removed;
154     let updated_comment = blocking(context.pool(), move |conn| {
155       Comment::update_removed(conn, comment_id, removed)
156     })
157     .await?
158     .map_err(LemmyError::from)
159     .map_err(|e| e.with_message("couldnt_update_comment"))?;
160
161     // Mod tables
162     let form = ModRemoveCommentForm {
163       mod_person_id: local_user_view.person.id,
164       comment_id: data.comment_id,
165       removed: Some(removed),
166       reason: data.reason.to_owned(),
167     };
168     blocking(context.pool(), move |conn| {
169       ModRemoveComment::create(conn, &form)
170     })
171     .await??;
172
173     let post_id = updated_comment.post_id;
174     let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
175     let recipient_ids = send_local_notifs(
176       vec![],
177       &updated_comment,
178       &local_user_view.person.clone(),
179       &post,
180       false,
181       context,
182     )
183     .await?;
184
185     let res = send_comment_ws_message(
186       data.comment_id,
187       UserOperationCrud::RemoveComment,
188       websocket_id,
189       None, // TODO maybe this might clear other forms
190       Some(local_user_view.person.id),
191       recipient_ids,
192       context,
193     )
194     .await?;
195
196     // Send the apub message
197     let community = blocking(context.pool(), move |conn| {
198       Community::read(conn, orig_comment.post.community_id)
199     })
200     .await??;
201     let deletable = DeletableObjects::Comment(Box::new(updated_comment.clone().into()));
202     send_apub_delete_in_community(
203       local_user_view.person,
204       community,
205       deletable,
206       data.reason.clone().or_else(|| Some("".to_string())),
207       removed,
208       context,
209     )
210     .await?;
211
212     Ok(res)
213   }
214 }