]> Untitled Git - lemmy.git/blob - crates/api_crud/src/comment/create.rs
Rewrite delete activities (#1699)
[lemmy.git] / crates / api_crud / src / comment / create.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   get_post,
9   send_local_notifs,
10 };
11 use lemmy_apub::{
12   activities::{
13     comment::create_or_update::CreateOrUpdateComment,
14     voting::vote::{Vote, VoteType},
15     CreateOrUpdateType,
16   },
17   generate_apub_endpoint,
18   EndpointType,
19   PostOrComment,
20 };
21 use lemmy_db_queries::{source::comment::Comment_, Crud, Likeable};
22 use lemmy_db_schema::source::comment::*;
23 use lemmy_utils::{
24   utils::{remove_slurs, scrape_text_for_mentions},
25   ApiError,
26   ConnectionId,
27   LemmyError,
28 };
29 use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperationCrud};
30
31 #[async_trait::async_trait(?Send)]
32 impl PerformCrud for CreateComment {
33   type Response = CommentResponse;
34
35   async fn perform(
36     &self,
37     context: &Data<LemmyContext>,
38     websocket_id: Option<ConnectionId>,
39   ) -> Result<CommentResponse, LemmyError> {
40     let data: &CreateComment = self;
41     let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
42
43     let content_slurs_removed = remove_slurs(&data.content.to_owned());
44
45     // Check for a community ban
46     let post_id = data.post_id;
47     let post = get_post(post_id, context.pool()).await?;
48     let community_id = post.community_id;
49
50     check_community_ban(local_user_view.person.id, community_id, context.pool()).await?;
51
52     // Check if post is locked, no new comments
53     if post.locked {
54       return Err(ApiError::err("locked").into());
55     }
56
57     // If there's a parent_id, check to make sure that comment is in that post
58     if let Some(parent_id) = data.parent_id {
59       // Make sure the parent comment exists
60       let parent = blocking(context.pool(), move |conn| Comment::read(conn, parent_id))
61         .await?
62         .map_err(|_| ApiError::err("couldnt_create_comment"))?;
63       if parent.post_id != post_id {
64         return Err(ApiError::err("couldnt_create_comment").into());
65       }
66     }
67
68     let comment_form = CommentForm {
69       content: content_slurs_removed,
70       parent_id: data.parent_id.to_owned(),
71       post_id: data.post_id,
72       creator_id: local_user_view.person.id,
73       ..CommentForm::default()
74     };
75
76     // Create the comment
77     let comment_form2 = comment_form.clone();
78     let inserted_comment = blocking(context.pool(), move |conn| {
79       Comment::create(conn, &comment_form2)
80     })
81     .await?
82     .map_err(|_| ApiError::err("couldnt_create_comment"))?;
83
84     // Necessary to update the ap_id
85     let inserted_comment_id = inserted_comment.id;
86     let updated_comment: Comment =
87       blocking(context.pool(), move |conn| -> Result<Comment, LemmyError> {
88         let apub_id =
89           generate_apub_endpoint(EndpointType::Comment, &inserted_comment_id.to_string())?;
90         Ok(Comment::update_ap_id(conn, inserted_comment_id, apub_id)?)
91       })
92       .await?
93       .map_err(|_| ApiError::err("couldnt_create_comment"))?;
94
95     CreateOrUpdateComment::send(
96       &updated_comment,
97       &local_user_view.person,
98       CreateOrUpdateType::Create,
99       context,
100     )
101     .await?;
102
103     // Scan the comment for user mentions, add those rows
104     let post_id = post.id;
105     let mentions = scrape_text_for_mentions(&comment_form.content);
106     let recipient_ids = send_local_notifs(
107       mentions,
108       updated_comment.clone(),
109       local_user_view.person.clone(),
110       post,
111       context.pool(),
112       true,
113     )
114     .await?;
115
116     // You like your own comment by default
117     let like_form = CommentLikeForm {
118       comment_id: inserted_comment.id,
119       post_id,
120       person_id: local_user_view.person.id,
121       score: 1,
122     };
123
124     let like = move |conn: &'_ _| CommentLike::like(conn, &like_form);
125     if blocking(context.pool(), like).await?.is_err() {
126       return Err(ApiError::err("couldnt_like_comment").into());
127     }
128
129     let object = PostOrComment::Comment(Box::new(updated_comment));
130     Vote::send(
131       &object,
132       &local_user_view.person,
133       community_id,
134       VoteType::Like,
135       context,
136     )
137     .await?;
138
139     // If its a comment to yourself, mark it as read
140     if local_user_view.person.id == inserted_comment.creator_id {
141       let comment_id = inserted_comment.id;
142       blocking(context.pool(), move |conn| {
143         Comment::update_read(conn, comment_id, true)
144       })
145       .await?
146       .map_err(|_| ApiError::err("couldnt_update_comment"))?;
147     }
148
149     send_comment_ws_message(
150       inserted_comment.id,
151       UserOperationCrud::CreateComment,
152       websocket_id,
153       data.form_id.to_owned(),
154       Some(local_user_view.person.id),
155       recipient_ids,
156       context,
157     )
158     .await
159   }
160 }