]> Untitled Git - lemmy.git/blob - crates/api_crud/src/post/update.rs
Sanitize html (#3708)
[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   build_response::build_post_response,
5   context::LemmyContext,
6   post::{EditPost, PostResponse},
7   request::fetch_site_data,
8   utils::{
9     check_community_ban,
10     local_site_to_slur_regex,
11     local_user_view_from_jwt,
12     sanitize_html_opt,
13   },
14 };
15 use lemmy_db_schema::{
16   source::{
17     actor_language::CommunityLanguage,
18     local_site::LocalSite,
19     post::{Post, PostUpdateForm},
20   },
21   traits::Crud,
22   utils::{diesel_option_overwrite, naive_now},
23 };
24 use lemmy_utils::{
25   error::{LemmyError, LemmyErrorExt, LemmyErrorType},
26   utils::{
27     slurs::check_slurs_opt,
28     validation::{check_url_scheme, clean_url_params, is_valid_body_field, is_valid_post_title},
29   },
30 };
31
32 #[async_trait::async_trait(?Send)]
33 impl PerformCrud for EditPost {
34   type Response = PostResponse;
35
36   #[tracing::instrument(skip(context))]
37   async fn perform(&self, context: &Data<LemmyContext>) -> Result<PostResponse, LemmyError> {
38     let data: &EditPost = self;
39     let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
40     let local_site = LocalSite::read(&mut context.pool()).await?;
41
42     let data_url = data.url.as_ref();
43
44     // TODO No good way to handle a clear.
45     // Issue link: https://github.com/LemmyNet/lemmy/issues/2287
46     let url = Some(data_url.map(clean_url_params).map(Into::into));
47
48     let slur_regex = local_site_to_slur_regex(&local_site);
49     check_slurs_opt(&data.name, &slur_regex)?;
50     check_slurs_opt(&data.body, &slur_regex)?;
51
52     if let Some(name) = &data.name {
53       is_valid_post_title(name)?;
54     }
55
56     is_valid_body_field(&data.body, true)?;
57     check_url_scheme(&data.url)?;
58
59     let post_id = data.post_id;
60     let orig_post = Post::read(&mut context.pool(), post_id).await?;
61
62     check_community_ban(
63       local_user_view.person.id,
64       orig_post.community_id,
65       &mut context.pool(),
66     )
67     .await?;
68
69     // Verify that only the creator can edit
70     if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) {
71       return Err(LemmyErrorType::NoPostEditAllowed)?;
72     }
73
74     // Fetch post links and Pictrs cached image
75     let data_url = data.url.as_ref();
76     let (metadata_res, thumbnail_url) =
77       fetch_site_data(context.client(), context.settings(), data_url, true).await;
78     let (embed_title, embed_description, embed_video_url) = metadata_res
79       .map(|u| (Some(u.title), Some(u.description), Some(u.embed_video_url)))
80       .unwrap_or_default();
81
82     let name = sanitize_html_opt(&data.name);
83     let body = sanitize_html_opt(&data.body);
84     let body = diesel_option_overwrite(body);
85     let embed_title = embed_title.map(|e| sanitize_html_opt(&e));
86     let embed_description = embed_description.map(|e| sanitize_html_opt(&e));
87
88     let language_id = self.language_id;
89     CommunityLanguage::is_allowed_community_language(
90       &mut context.pool(),
91       language_id,
92       orig_post.community_id,
93     )
94     .await?;
95
96     let post_form = PostUpdateForm::builder()
97       .name(name)
98       .url(url)
99       .body(body)
100       .nsfw(data.nsfw)
101       .embed_title(embed_title)
102       .embed_description(embed_description)
103       .embed_video_url(embed_video_url)
104       .language_id(data.language_id)
105       .thumbnail_url(Some(thumbnail_url))
106       .updated(Some(Some(naive_now())))
107       .build();
108
109     let post_id = data.post_id;
110     Post::update(&mut context.pool(), post_id, &post_form)
111       .await
112       .with_lemmy_type(LemmyErrorType::CouldntUpdatePost)?;
113
114     build_post_response(
115       context,
116       orig_post.community_id,
117       local_user_view.person.id,
118       post_id,
119     )
120     .await
121   }
122 }