]> Untitled Git - lemmy.git/blob - crates/api_crud/src/post/update.rs
Add diesel_async, get rid of blocking function (#2510)
[lemmy.git] / crates / api_crud / src / post / update.rs
1 use crate::PerformCrud;
2 use actix_web::web::Data;
3 use lemmy_api_common::{
4   post::{EditPost, PostResponse},
5   request::fetch_site_data,
6   utils::{
7     check_community_ban,
8     check_community_deleted_or_removed,
9     get_local_user_view_from_jwt,
10     local_site_to_slur_regex,
11   },
12 };
13 use lemmy_apub::protocol::activities::{
14   create_or_update::post::CreateOrUpdatePost,
15   CreateOrUpdateType,
16 };
17 use lemmy_db_schema::{
18   source::{
19     actor_language::CommunityLanguage,
20     local_site::LocalSite,
21     post::{Post, PostUpdateForm},
22   },
23   traits::Crud,
24   utils::diesel_option_overwrite,
25 };
26 use lemmy_utils::{
27   error::LemmyError,
28   utils::{check_slurs_opt, clean_url_params, is_valid_post_title},
29   ConnectionId,
30 };
31 use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud};
32
33 #[async_trait::async_trait(?Send)]
34 impl PerformCrud for EditPost {
35   type Response = PostResponse;
36
37   #[tracing::instrument(skip(context, websocket_id))]
38   async fn perform(
39     &self,
40     context: &Data<LemmyContext>,
41     websocket_id: Option<ConnectionId>,
42   ) -> Result<PostResponse, LemmyError> {
43     let data: &EditPost = self;
44     let local_user_view =
45       get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
46     let local_site = LocalSite::read(context.pool()).await?;
47
48     let data_url = data.url.as_ref();
49
50     // TODO No good way to handle a clear.
51     // Issue link: https://github.com/LemmyNet/lemmy/issues/2287
52     let url = Some(data_url.map(clean_url_params).map(Into::into));
53     let body = diesel_option_overwrite(&data.body);
54
55     let slur_regex = local_site_to_slur_regex(&local_site);
56     check_slurs_opt(&data.name, &slur_regex)?;
57     check_slurs_opt(&data.body, &slur_regex)?;
58
59     if let Some(name) = &data.name {
60       if !is_valid_post_title(name) {
61         return Err(LemmyError::from_message("invalid_post_title"));
62       }
63     }
64
65     let post_id = data.post_id;
66     let orig_post = Post::read(context.pool(), post_id).await?;
67
68     check_community_ban(
69       local_user_view.person.id,
70       orig_post.community_id,
71       context.pool(),
72     )
73     .await?;
74     check_community_deleted_or_removed(orig_post.community_id, context.pool()).await?;
75
76     // Verify that only the creator can edit
77     if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) {
78       return Err(LemmyError::from_message("no_post_edit_allowed"));
79     }
80
81     // Fetch post links and Pictrs cached image
82     let data_url = data.url.as_ref();
83     let (metadata_res, thumbnail_url) =
84       fetch_site_data(context.client(), context.settings(), data_url).await;
85     let (embed_title, embed_description, embed_video_url) = metadata_res
86       .map(|u| (Some(u.title), Some(u.description), Some(u.embed_video_url)))
87       .unwrap_or_default();
88
89     let language_id = self.language_id;
90     CommunityLanguage::is_allowed_community_language(
91       context.pool(),
92       language_id,
93       orig_post.community_id,
94     )
95     .await?;
96
97     let post_form = PostUpdateForm::builder()
98       .name(data.name.to_owned())
99       .url(url)
100       .body(body)
101       .nsfw(data.nsfw)
102       .embed_title(embed_title)
103       .embed_description(embed_description)
104       .embed_video_url(embed_video_url)
105       .language_id(data.language_id)
106       .thumbnail_url(Some(thumbnail_url))
107       .build();
108
109     let post_id = data.post_id;
110     let res = Post::update(context.pool(), post_id, &post_form).await;
111     let updated_post: Post = match res {
112       Ok(post) => post,
113       Err(e) => {
114         let err_type = if e.to_string() == "value too long for type character varying(200)" {
115           "post_title_too_long"
116         } else {
117           "couldnt_update_post"
118         };
119
120         return Err(LemmyError::from_error_message(e, err_type));
121       }
122     };
123
124     // Send apub update
125     CreateOrUpdatePost::send(
126       updated_post.into(),
127       &local_user_view.person.clone().into(),
128       CreateOrUpdateType::Update,
129       context,
130     )
131     .await?;
132
133     send_post_ws_message(
134       data.post_id,
135       UserOperationCrud::EditPost,
136       websocket_id,
137       Some(local_user_view.person.id),
138       context,
139     )
140     .await
141   }
142 }