diff options
author | Colin Reeder <vpzomtrrfrt@gmail.com> | 2020-10-08 09:44:02 -0600 |
---|---|---|
committer | Colin Reeder <vpzomtrrfrt@gmail.com> | 2020-10-08 09:44:02 -0600 |
commit | 3d0f120023526c507e4d97f70fb633288401f260 (patch) | |
tree | 733b2ecb7451f30ef5d041ffe650307ab2044f15 /src | |
parent | 1c2477ed05dde6e54fd445fef82a642f39a159e7 (diff) |
Add image upload to New Post UI
Diffstat (limited to 'src')
-rw-r--r-- | src/resp_types.rs | 5 | ||||
-rw-r--r-- | src/routes/communities.rs | 144 |
2 files changed, 132 insertions, 17 deletions
diff --git a/src/resp_types.rs b/src/resp_types.rs index 279c924..ec5673e 100644 --- a/src/resp_types.rs +++ b/src/resp_types.rs @@ -166,6 +166,11 @@ pub struct JustID { } #[derive(Deserialize, Debug)] +pub struct JustStringID<'a> { + pub id: &'a str, +} + +#[derive(Deserialize, Debug)] pub struct RespYourFollow { pub accepted: bool, } diff --git a/src/routes/communities.rs b/src/routes/communities.rs index 526c89b..909ab4c 100644 --- a/src/routes/communities.rs +++ b/src/routes/communities.rs @@ -1,13 +1,14 @@ use crate::components::{CommunityLink, HTPage, MaybeFillInput, MaybeFillTextArea, PostItem}; use crate::resp_types::{ - JustContentHTML, RespCommunityInfoMaybeYour, RespMinimalAuthorInfo, RespMinimalCommunityInfo, - RespPostListPost, RespYourFollow, + JustContentHTML, JustStringID, RespCommunityInfoMaybeYour, RespMinimalAuthorInfo, + RespMinimalCommunityInfo, RespPostListPost, RespYourFollow, }; use crate::routes::{ fetch_base_data, for_client, get_cookie_map_for_headers, get_cookie_map_for_req, html_response, res_to_error, CookieMap, }; use serde_derive::Deserialize; +use std::borrow::Cow; use std::collections::HashMap; use std::sync::Arc; @@ -722,7 +723,7 @@ async fn page_community_new_post_inner( cookies: &CookieMap<'_>, ctx: Arc<crate::RouteContext>, display_error: Option<String>, - prev_values: Option<&HashMap<&str, serde_json::Value>>, + prev_values: Option<&HashMap<Cow<'_, str>, serde_json::Value>>, display_preview: Option<&str>, ) -> Result<hyper::Response<hyper::Body>, crate::Error> { let base_data = fetch_base_data(&ctx.backend_host, &ctx.http_client, headers, &cookies).await?; @@ -744,7 +745,7 @@ async fn page_community_new_post_inner( } }) } - <form method={"POST"} action={&submit_url}> + <form method={"POST"} action={&submit_url} enctype={"multipart/form-data"}> <table> <tr> <td> @@ -762,6 +763,14 @@ async fn page_community_new_post_inner( <MaybeFillInput values={&prev_values} r#type={"text"} name={"href"} required={false} id={"input_url"} /> </td> </tr> + <tr> + <td> + <label for={"input_image"}>{lang.tr("post_new_image_prompt", None)}</label> + </td> + <td> + <input id={"input_image"} type={"file"} accept={"image/*"} name={"href_media"} /> + </td> + </tr> </table> <label> {lang.tr("text_with_markdown", None)}{":"} @@ -792,12 +801,113 @@ async fn handler_communities_new_post_submit( let (community_id,) = params; let (req_parts, body) = req.into_parts(); + let lang = crate::get_lang_for_headers(&req_parts.headers); let cookies = get_cookie_map_for_headers(&req_parts.headers)?; - let body = hyper::body::to_bytes(body).await?; - let mut body: HashMap<&str, serde_json::Value> = serde_urlencoded::from_bytes(&body)?; - if body.contains_key("preview") { - let md = body + let content_type = req_parts + .headers + .get(hyper::header::CONTENT_TYPE) + .ok_or_else(|| { + crate::Error::InternalStr("missing content-type header in form submission".to_owned()) + })?; + let content_type = std::str::from_utf8(content_type.as_ref())?; + + let boundary = multer::parse_boundary(&content_type)?; + + let mut multipart = multer::Multipart::new(body, boundary); + + let mut body_values: HashMap<Cow<'_, str>, serde_json::Value> = HashMap::new(); + { + let mut error = None; + + loop { + let field = multipart.next_field().await?; + let field = match field { + None => break, + Some(field) => field, + }; + + if field.name().is_none() { + continue; + } + + if field.name().unwrap() == "href_media" { + if body_values.contains_key("href") && body_values["href"] != "" { + error = Some(lang.tr("post_new_href_conflict", None).into_owned()); + } else { + match field.content_type() { + None => { + error = + Some(lang.tr("post_new_missing_content_type", None).into_owned()); + } + Some(mime) => { + println!("will upload media"); + let res = res_to_error( + ctx.http_client + .request(for_client( + hyper::Request::post(format!( + "{}/api/unstable/media", + ctx.backend_host, + )) + .header(hyper::header::CONTENT_TYPE, mime.as_ref()) + .body(hyper::Body::wrap_stream(field))?, + &req_parts.headers, + &cookies, + )?) + .await?, + ) + .await; + + match res { + Err(crate::Error::RemoteError((_, message))) => { + error = Some(message); + } + Err(other) => { + return Err(other); + } + Ok(res) => { + let res = hyper::body::to_bytes(res.into_body()).await?; + let res: JustStringID = serde_json::from_slice(&res)?; + + body_values.insert( + "href".into(), + format!("local-media://{}", res.id).into(), + ); + } + } + + println!("finished media upload"); + } + } + } + } else { + let name = field.name().unwrap(); + if name == "href" && body_values.contains_key("href") && body_values["href"] != "" { + error = Some(lang.tr("post_new_href_conflict", None).into_owned()); + } else { + let name = name.to_owned(); + let value = field.text().await?; + body_values.insert(name.into(), value.into()); + } + } + } + + if let Some(error) = error { + return page_community_new_post_inner( + community_id, + &req_parts.headers, + &cookies, + ctx, + Some(error), + Some(&body_values), + None, + ) + .await; + } + } + + if body_values.contains_key("preview") { + let md = body_values .get("content_markdown") .and_then(|x| x.as_str()) .unwrap_or(""); @@ -828,7 +938,7 @@ async fn handler_communities_new_post_submit( &cookies, ctx, None, - Some(&body), + Some(&body_values), Some(&preview_res.content_html), ) .await @@ -840,7 +950,7 @@ async fn handler_communities_new_post_submit( &cookies, ctx, Some(message), - Some(&body), + Some(&body_values), None, ) .await @@ -849,19 +959,19 @@ async fn handler_communities_new_post_submit( }; } - body.insert("community", community_id.into()); - if body.get("content_markdown").and_then(|x| x.as_str()) == Some("") { - body.remove("content_markdown"); + body_values.insert("community".into(), community_id.into()); + if body_values.get("content_markdown").and_then(|x| x.as_str()) == Some("") { + body_values.remove("content_markdown"); } - if body.get("href").and_then(|x| x.as_str()) == Some("") { - body.remove("href"); + if body_values.get("href").and_then(|x| x.as_str()) == Some("") { + body_values.remove("href"); } let api_res = res_to_error( ctx.http_client .request(for_client( hyper::Request::post(format!("{}/api/unstable/posts", ctx.backend_host)) - .body(serde_json::to_vec(&body)?.into())?, + .body(serde_json::to_vec(&body_values)?.into())?, &req_parts.headers, &cookies, )?) @@ -891,7 +1001,7 @@ async fn handler_communities_new_post_submit( &cookies, ctx, Some(message), - Some(&body), + Some(&body_values), None, ) .await |