diff options
author | Colin Reeder <colin@vpzom.click> | 2020-07-05 23:16:48 -0600 |
---|---|---|
committer | Colin Reeder <colin@vpzom.click> | 2020-07-05 23:16:48 -0600 |
commit | 829a62653ef0f2505960b959a970deecedd63f4c (patch) | |
tree | 96bb488adb5f1071e13159020fef2c2a4a880415 | |
parent | 54bf2bd1734b99e64d9aeeace89a711a7bb03224 (diff) |
Introduce error banners for some forms
-rw-r--r-- | Cargo.lock | 49 | ||||
-rw-r--r-- | Cargo.toml | 3 | ||||
-rw-r--r-- | res/main.css | 8 | ||||
-rw-r--r-- | src/components/mod.rs | 33 | ||||
-rw-r--r-- | src/main.rs | 11 | ||||
-rw-r--r-- | src/routes/mod.rs | 331 | ||||
-rw-r--r-- | src/routes/posts.rs | 9 |
7 files changed, 330 insertions, 114 deletions
@@ -205,6 +205,7 @@ dependencies = [ "ammonia", "fallible-iterator", "ginger", + "http", "hyper", "hyper-tls", "render", @@ -608,6 +609,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] +name = "proc-macro-error" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc175e9777c3116627248584e8f8b3e2987405cabe1c0adf7d1dd28f09dc7880" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "syn-mid", + "version_check", +] + +[[package]] name = "proc-macro2" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -694,7 +721,7 @@ dependencies = [ [[package]] name = "render" version = "0.3.1" -source = "git+https://github.com/vpzomtrrfrt/render.rs?rev=0604925#060492504f5c8b0b0d9716af724bca2388689697" +source = "git+https://github.com/vpzomtrrfrt/render.rs?rev=d996c5d#d996c5d6b5762e7ab5e8b2a161d22d8473e0672b" dependencies = [ "render_macros", ] @@ -702,8 +729,9 @@ dependencies = [ [[package]] name = "render_macros" version = "0.3.1" -source = "git+https://github.com/vpzomtrrfrt/render.rs?rev=0604925#060492504f5c8b0b0d9716af724bca2388689697" +source = "git+https://github.com/vpzomtrrfrt/render.rs?rev=d996c5d#d996c5d6b5762e7ab5e8b2a161d22d8473e0672b" dependencies = [ + "proc-macro-error", "proc-macro2", "quote", "syn", @@ -855,6 +883,17 @@ dependencies = [ ] [[package]] +name = "syn-mid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1038,6 +1077,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55d1e41d56121e07f1e223db0a4def204e45c85425f6a16d462fd07c8d10d74c" [[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] name = "want" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -8,7 +8,7 @@ license = "AGPL-3.0-or-later" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -render = { git = "https://github.com/vpzomtrrfrt/render.rs", rev = "0604925" } +render = { git = "https://github.com/vpzomtrrfrt/render.rs", rev = "d996c5d" } trout = "0.2.0" hyper = "0.13.6" hyper-tls = "0.4.1" @@ -21,3 +21,4 @@ fallible-iterator = "0.2.0" ginger = "0.1.0" ammonia = "3.1.0" urlencoding = "1.1.1" +http = "0.2.1" diff --git a/res/main.css b/res/main.css index be66795..208e8c0 100644 --- a/res/main.css +++ b/res/main.css @@ -28,3 +28,11 @@ body { font-size: 1.2em; margin-right: 1em; } + +.errorBox { + background-color: #FF6D00; + padding: .5em; + display: inline-block; + margin-top: .5em; + margin-bottom: .5em; +} diff --git a/src/components/mod.rs b/src/components/mod.rs index 43e762a..eff9e40 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -237,3 +237,36 @@ impl<'user> render::Render for UserLink<'user> { } } } + +fn maybe_fill_value<'a>(values: &'a Option<&'a serde_json::Value>, name: &str) -> &'a str { + values + .and_then(|values| values.get(name)) + .and_then(serde_json::Value::as_str) + .unwrap_or("") +} + +#[render::component] +pub fn MaybeFillInput<'a>( + values: &'a Option<&'a serde_json::Value>, + r#type: &'a str, + name: &'a str, + required: bool, +) { + render::rsx! { + <input + r#type + name + value={maybe_fill_value(values, name)} + required={if required { "true" } else { "false" }} + /> + } +} + +#[render::component] +pub fn MaybeFillTextArea<'a>(values: &'a Option<&'a serde_json::Value>, name: &'a str) { + render::rsx! { + <textarea name> + {maybe_fill_value(values, name)} + </textarea> + } +} diff --git a/src/main.rs b/src/main.rs index 7dc0567..163a20e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,7 @@ pub enum Error { InternalStr(String), UserError(hyper::Response<hyper::Body>), RoutingError(trout::RoutingFailure), + RemoteError((hyper::StatusCode, String)), } impl<T: 'static + std::error::Error + Send> From<T> for Error { @@ -86,7 +87,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { Ok(val) => val, Err(Error::UserError(res)) => res, Err(Error::RoutingError(err)) => err.to_simple_response(), - Err(Error::Internal(err)) => { + Err(err) => { eprintln!("Error: {:?}", err); simple_response( @@ -94,14 +95,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { "Internal Server Error", ) } - Err(Error::InternalStr(err)) => { - eprintln!("Error: {}", err); - - simple_response( - hyper::StatusCode::INTERNAL_SERVER_ERROR, - "Internal Server Error", - ) - } }) } })) diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 0535f66..7774a4c 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -2,7 +2,7 @@ use serde_derive::Deserialize; use std::borrow::Cow; use std::sync::Arc; -use crate::components::{Content, HTPage, PostItem, UserLink}; +use crate::components::{Content, HTPage, MaybeFillInput, MaybeFillTextArea, PostItem, UserLink}; use crate::resp_types::{RespMinimalAuthorInfo, RespPostCommentInfo, RespPostListPost}; use crate::PageBaseData; @@ -30,14 +30,17 @@ fn get_cookie_map<'a>(src: Option<&'a str>) -> Result<CookieMap<'a>, ginger::Par fn get_cookie_map_for_req<'a>( req: &'a hyper::Request<hyper::Body>, ) -> Result<CookieMap<'a>, crate::Error> { - get_cookie_map(get_cookies_string(req)?).map_err(Into::into) + get_cookie_map_for_headers(req.headers()) } -fn get_cookies_string<'a>( - req: &'a hyper::Request<hyper::Body>, -) -> Result<Option<&'a str>, crate::Error> { - Ok(req - .headers() +fn get_cookie_map_for_headers<'a>( + headers: &'a hyper::HeaderMap, +) -> Result<CookieMap<'a>, crate::Error> { + get_cookie_map(get_cookies_string(headers)?).map_err(Into::into) +} + +fn get_cookies_string<'a>(headers: &'a hyper::HeaderMap) -> Result<Option<&'a str>, crate::Error> { + Ok(headers .get(hyper::header::COOKIE) .map(|x| x.to_str()) .transpose()?) @@ -127,6 +130,16 @@ async fn page_comment( let cookies = get_cookie_map_for_req(&req)?; + page_comment_inner(comment_id, &cookies, ctx, None, None).await +} + +async fn page_comment_inner( + comment_id: i64, + cookies: &CookieMap<'_>, + ctx: Arc<crate::RouteContext>, + display_error: Option<String>, + prev_values: Option<&serde_json::Value>, +) -> Result<hyper::Response<hyper::Body>, crate::Error> { let base_data = fetch_base_data(&ctx.backend_host, &ctx.http_client, &cookies).await?; let api_res = res_to_error( @@ -151,9 +164,16 @@ async fn page_comment( <small><cite><UserLink user={comment.author.as_ref()} /></cite>{":"}</small> <Content src={&comment} /> </p> + { + display_error.map(|msg| { + render::rsx! { + <div class={"errorBox"}>{msg}</div> + } + }) + } <form method={"POST"} action={format!("/comments/{}/submit_reply", comment.id)}> <div> - <textarea name={"content_text"}>{()}</textarea> + <MaybeFillTextArea values={&prev_values} name={"content_text"} /> </div> <button r#type={"submit"}>{"Reply"}</button> </form> @@ -170,6 +190,15 @@ async fn page_comment_delete( let cookies = get_cookie_map_for_req(&req)?; + page_comment_delete_inner(comment_id, ctx, &cookies, None).await +} + +async fn page_comment_delete_inner( + comment_id: i64, + ctx: Arc<crate::RouteContext>, + cookies: &CookieMap<'_>, + display_error: Option<String>, +) -> Result<hyper::Response<hyper::Body>, crate::Error> { let base_data = fetch_base_data(&ctx.backend_host, &ctx.http_client, &cookies).await?; let api_res = res_to_error( @@ -197,6 +226,13 @@ async fn page_comment_delete( </p> <div id={"delete"}> <h2>{"Delete this comment?"}</h2> + { + display_error.map(|msg| { + render::rsx! { + <div class={"errorBox"}>{msg}</div> + } + }) + } <form method={"POST"} action={format!("/comments/{}/delete/confirm", comment.id)}> <a href={format!("/comments/{}/", comment.id)}>{"No, cancel"}</a> {" "} @@ -216,7 +252,7 @@ async fn handler_comment_delete_confirm( let cookies = get_cookie_map_for_req(&req)?; - res_to_error( + let api_res = res_to_error( ctx.http_client .request(with_auth( hyper::Request::delete(format!( @@ -228,12 +264,18 @@ async fn handler_comment_delete_confirm( )?) .await?, ) - .await?; + .await; - Ok(hyper::Response::builder() - .status(hyper::StatusCode::SEE_OTHER) - .header(hyper::header::LOCATION, "/") - .body("Successfully deleted.".into())?) + match api_res { + Ok(_) => Ok(hyper::Response::builder() + .status(hyper::StatusCode::SEE_OTHER) + .header(hyper::header::LOCATION, "/") + .body("Successfully deleted.".into())?), + Err(crate::Error::RemoteError((status, message))) if status.is_client_error() => { + page_comment_delete_inner(comment_id, ctx, &cookies, Some(message)).await + } + Err(other) => Err(other), + } } async fn handler_comment_like( @@ -281,13 +323,12 @@ async fn handler_comment_submit_reply( let (comment_id,) = params; - let cookies_string = get_cookies_string(&req)?.map(ToOwned::to_owned); - let cookies_string = cookies_string.as_deref(); - let cookies = get_cookie_map(cookies_string)?; + let (req_parts, body) = req.into_parts(); + + let cookies = get_cookie_map_for_headers(&req_parts.headers)?; - let body = hyper::body::to_bytes(req.into_body()).await?; + let body = hyper::body::to_bytes(body).await?; let body: serde_json::Value = serde_urlencoded::from_bytes(&body)?; - let body = serde_json::to_vec(&body)?; let api_res = res_to_error( ctx.http_client @@ -296,23 +337,31 @@ async fn handler_comment_submit_reply( "{}/api/unstable/comments/{}/replies", ctx.backend_host, comment_id )) - .body(body.into())?, + .body(serde_json::to_vec(&body)?.into())?, &cookies, )?) .await?, ) - .await?; + .await; - let api_res = hyper::body::to_bytes(api_res.into_body()).await?; - let api_res: CommentsRepliesCreateResponse = serde_json::from_slice(&api_res)?; + match api_res { + Ok(api_res) => { + let api_res = hyper::body::to_bytes(api_res.into_body()).await?; + let api_res: CommentsRepliesCreateResponse = serde_json::from_slice(&api_res)?; - Ok(hyper::Response::builder() - .status(hyper::StatusCode::SEE_OTHER) - .header( - hyper::header::LOCATION, - format!("/posts/{}", api_res.post.id), - ) - .body("Successfully posted.".into())?) + Ok(hyper::Response::builder() + .status(hyper::StatusCode::SEE_OTHER) + .header( + hyper::header::LOCATION, + format!("/posts/{}", api_res.post.id), + ) + .body("Successfully posted.".into())?) + } + Err(crate::Error::RemoteError((status, message))) if status.is_client_error() => { + page_comment_inner(comment_id, &cookies, ctx, Some(message), Some(&body)).await + } + Err(other) => Err(other), + } } async fn page_login( @@ -320,18 +369,34 @@ async fn page_login( ctx: Arc<crate::RouteContext>, req: hyper::Request<hyper::Body>, ) -> Result<hyper::Response<hyper::Body>, crate::Error> { - let cookies = get_cookie_map_for_req(&req)?; + page_login_inner(ctx, req.into_parts().0, None, None).await +} + +async fn page_login_inner( + ctx: Arc<crate::RouteContext>, + req_parts: http::request::Parts, + display_error: Option<String>, + prev_values: Option<&serde_json::Value>, +) -> Result<hyper::Response<hyper::Body>, crate::Error> { + let cookies = get_cookie_map_for_headers(&req_parts.headers)?; let base_data = fetch_base_data(&ctx.backend_host, &ctx.http_client, &cookies).await?; Ok(html_response(render::html! { <HTPage base_data={&base_data}> + { + display_error.map(|msg| { + render::rsx! { + <div class={"errorBox"}>{msg}</div> + } + }) + } <form method={"POST"} action={"/login/submit"}> <p> - <input r#type={"text"} name={"username"} /> + <MaybeFillInput values={&prev_values} r#type={"text"} name={"username"} required={true} /> </p> <p> - <input r#type={"password"} name={"password"} /> + <MaybeFillInput values={&prev_values} r#type={"password"} name={"password"} required={true} /> </p> <button r#type={"submit"}>{"Login"}</button> </form> @@ -345,13 +410,14 @@ async fn page_login( pub async fn res_to_error( res: hyper::Response<hyper::Body>, ) -> Result<hyper::Response<hyper::Body>, crate::Error> { - if res.status().is_success() { + let status = res.status(); + if status.is_success() { Ok(res) } else { let bytes = hyper::body::to_bytes(res.into_body()).await?; - Err(crate::Error::InternalStr(format!( - "Error in remote response: {}", - String::from_utf8_lossy(&bytes) + Err(crate::Error::RemoteError(( + status, + String::from_utf8_lossy(&bytes).into_owned(), ))) } } @@ -366,33 +432,42 @@ async fn handler_login_submit( token: &'a str, } - let body = hyper::body::to_bytes(req.into_body()).await?; + let (req_parts, body) = req.into_parts(); + + let body = hyper::body::to_bytes(body).await?; let body: serde_json::Value = serde_urlencoded::from_bytes(&body)?; - let body = serde_json::to_vec(&body)?; let api_res = res_to_error( ctx.http_client .request( hyper::Request::post(format!("{}/api/unstable/logins", ctx.backend_host)) - .body(body.into())?, + .body(serde_json::to_vec(&body)?.into())?, ) .await?, ) - .await?; + .await; - let api_res = hyper::body::to_bytes(api_res.into_body()).await?; - let api_res: LoginsCreateResponse = serde_json::from_slice(&api_res)?; + match api_res { + Ok(api_res) => { + let api_res = hyper::body::to_bytes(api_res.into_body()).await?; + let api_res: LoginsCreateResponse = serde_json::from_slice(&api_res)?; - let token = api_res.token; + let token = api_res.token; - Ok(hyper::Response::builder() - .status(hyper::StatusCode::SEE_OTHER) - .header( - hyper::header::SET_COOKIE, - format!("hitideToken={}; Path=/; Max-Age={}", token, COOKIE_AGE), - ) - .header(hyper::header::LOCATION, "/") - .body("Successfully logged in.".into())?) + Ok(hyper::Response::builder() + .status(hyper::StatusCode::SEE_OTHER) + .header( + hyper::header::SET_COOKIE, + format!("hitideToken={}; Path=/; Max-Age={}", token, COOKIE_AGE), + ) + .header(hyper::header::LOCATION, "/") + .body("Successfully logged in.".into())?) + } + Err(crate::Error::RemoteError((status, message))) if status.is_client_error() => { + page_login_inner(ctx, req_parts, Some(message), Some(&body)).await + } + Err(other) => Err(other), + } } async fn page_lookup( @@ -416,7 +491,7 @@ async fn page_lookup( id: i64, } - let api_res: Option<Vec<LookupResult>> = if let Some(query) = &query { + let api_res: Option<Result<Vec<LookupResult>, String>> = if let Some(query) = &query { let api_res = res_to_error( ctx.http_client .request( @@ -429,23 +504,31 @@ async fn page_lookup( ) .await?, ) - .await?; - - let api_res = hyper::body::to_bytes(api_res.into_body()).await?; - Some(serde_json::from_slice(&api_res)?) + .await; + + Some(match api_res { + Ok(api_res) => { + let api_res = hyper::body::to_bytes(api_res.into_body()).await?; + Ok(serde_json::from_slice(&api_res)?) + } + Err(crate::Error::RemoteError((status, message))) if status.is_client_error() => { + Err(message) + } + Err(other) => return Err(other), + }) } else { None }; match api_res { - Some(items) if !items.is_empty() => Ok(hyper::Response::builder() + Some(Ok(items)) if !items.is_empty() => Ok(hyper::Response::builder() .status(hyper::StatusCode::FOUND) .header( hyper::header::LOCATION, format!("/communities/{}", items[0].id), ) .body("Redirecting…".into())?), - _ => { + api_res => { Ok(html_response(render::html! { <HTPage base_data={&base_data}> <h1>{"Lookup"}</h1> @@ -455,10 +538,15 @@ async fn page_lookup( { match api_res { None => None, - Some(_) => { + Some(Ok(_)) => { // non-empty case is handled above - Some(render::rsx! { <p>{"Nothing found."}</p> }) + Some(render::rsx! { <p>{Cow::Borrowed("Nothing found.")}</p> }) }, + Some(Err(display_error)) => { + Some(render::rsx! { + <div class={"errorBox"}>{display_error.into()}</div> + }) + } } } </HTPage> @@ -474,15 +562,31 @@ async fn page_new_community( ) -> Result<hyper::Response<hyper::Body>, crate::Error> { let cookies = get_cookie_map_for_req(&req)?; + page_new_community_inner(ctx, &cookies, None, None).await +} + +async fn page_new_community_inner( + ctx: Arc<crate::RouteContext>, + cookies: &CookieMap<'_>, + display_error: Option<String>, + prev_values: Option<&serde_json::Value>, +) -> Result<hyper::Response<hyper::Body>, crate::Error> { let base_data = fetch_base_data(&ctx.backend_host, &ctx.http_client, &cookies).await?; Ok(html_response(render::html! { <HTPage base_data={&base_data}> <h1>{"New Community"}</h1> + { + display_error.map(|msg| { + render::rsx! { + <div class={"errorBox"}>{msg}</div> + } + }) + } <form method={"POST"} action={"/new_community/submit"}> <div> <label> - {"Name: "}<input r#type={"text"} name={"name"} required={"true"} /> + {"Name: "}<MaybeFillInput values={&prev_values} r#type={"text"} name={"name"} required={true} /> </label> </div> <div> @@ -498,13 +602,12 @@ async fn handler_new_community_submit( ctx: Arc<crate::RouteContext>, req: hyper::Request<hyper::Body>, ) -> Result<hyper::Response<hyper::Body>, crate::Error> { - let cookies_string = get_cookies_string(&req)?.map(ToOwned::to_owned); - let cookies_string = cookies_string.as_deref(); - let cookies = get_cookie_map(cookies_string)?; + let (req_parts, body) = req.into_parts(); + + let cookies = get_cookie_map_for_headers(&req_parts.headers)?; - let body = hyper::body::to_bytes(req.into_body()).await?; + let body = hyper::body::to_bytes(body).await?; let body: serde_json::Value = serde_urlencoded::from_bytes(&body)?; - let body = serde_json::to_vec(&body)?; #[derive(Deserialize)] struct CommunitiesCreateResponseCommunity { @@ -520,24 +623,33 @@ async fn handler_new_community_submit( ctx.http_client .request(with_auth( hyper::Request::post(format!("{}/api/unstable/communities", ctx.backend_host)) - .body(body.into())?, + .body(serde_json::to_vec(&body)?.into())?, &cookies, )?) .await?, ) - .await?; - let api_res = hyper::body::to_bytes(api_res.into_body()).await?; - let api_res: CommunitiesCreateResponse = serde_json::from_slice(&api_res)?; + .await; - let community_id = api_res.community.id; + match api_res { + Ok(api_res) => { + let api_res = hyper::body::to_bytes(api_res.into_body()).await?; + let api_res: CommunitiesCreateResponse = serde_json::from_slice(&api_res)?; - Ok(hyper::Response::builder() - .status(hyper::StatusCode::SEE_OTHER) - .header( - hyper::header::LOCATION, - format!("/communities/{}", community_id), - ) - .body("Successfully created.".into())?) + let community_id = api_res.community.id; + + Ok(hyper::Response::builder() + .status(hyper::StatusCode::SEE_OTHER) + .header( + hyper::header::LOCATION, + format!("/communities/{}", community_id), + ) + .body("Successfully created.".into())?) + } + Err(crate::Error::RemoteError((status, message))) if status.is_client_error() => { + page_new_community_inner(ctx, &cookies, Some(message), Some(&body)).await + } + Err(other) => Err(other), + } } async fn page_signup( @@ -545,18 +657,34 @@ async fn page_signup( ctx: Arc<crate::RouteContext>, req: hyper::Request<hyper::Body>, ) -> Result<hyper::Response<hyper::Body>, crate::Error> { - let cookies = get_cookie_map_for_req(&req)?; + page_signup_inner(ctx, req.headers(), None, None).await +} + +async fn page_signup_inner( + ctx: Arc<crate::RouteContext>, + headers: &hyper::HeaderMap, + display_error: Option<String>, + prev_values: Option<&serde_json::Value>, +) -> Result<hyper::Response<hyper::Body>, crate::Error> { + let cookies = get_cookie_map_for_headers(&headers)?; let base_data = fetch_base_data(&ctx.backend_host, &ctx.http_client, &cookies).await?; Ok(html_response(render::html! { <HTPage base_data={&base_data}> + { + display_error.map(|msg| { + render::rsx! { + <div class={"errorBox"}>{msg}</div> + } + }) + } <form method={"POST"} action={"/signup/submit"}> <p> - <input r#type={"text"} name={"username"} /> + <MaybeFillInput values={&prev_values} r#type={"text"} name={"username"} required={true} /> </p> <p> - <input r#type={"password"} name={"password"} /> + <MaybeFillInput values={&prev_values} r#type={"password"} name={"password"} required={true} /> </p> <button r#type={"submit"}>{"Register"}</button> </form> @@ -574,34 +702,43 @@ async fn handler_signup_submit( token: &'a str, } - let body = hyper::body::to_bytes(req.into_body()).await?; + let (req_parts, body) = req.into_parts(); + + let body = hyper::body::to_bytes(body).await?; let mut body: serde_json::Value = serde_urlencoded::from_bytes(&body)?; body["login"] = true.into(); - let body = serde_json::to_vec(&body)?; let api_res = res_to_error( ctx.http_client .request( hyper::Request::post(format!("{}/api/unstable/users", ctx.backend_host)) - .body(body.into())?, + .body(serde_json::to_vec(&body)?.into())?, ) .await?, ) - .await?; + .await; - let api_res = hyper::body::to_bytes(api_res.into_body()).await?; - let api_res: UsersCreateResponse = serde_json::from_slice(&api_res)?; + match api_res { + Ok(api_res) => { + let api_res = hyper::body::to_bytes(api_res.into_body()).await?; + let api_res: UsersCreateResponse = serde_json::from_slice(&api_res)?; - let token = api_res.token; + let token = api_res.token; - Ok(hyper::Response::builder() - .status(hyper::StatusCode::SEE_OTHER) - .header( - hyper::header::SET_COOKIE, - format!("hitideToken={}; Path=/; Max-Age={}", token, COOKIE_AGE), - ) - .header(hyper::header::LOCATION, "/") - .body("Successfully registered new account.".into())?) + Ok(hyper::Response::builder() + .status(hyper::StatusCode::SEE_OTHER) + .header( + hyper::header::SET_COOKIE, + format!("hitideToken={}; Path=/; Max-Age={}", token, COOKIE_AGE), + ) + .header(hyper::header::LOCATION, "/") + .body("Successfully registered new account.".into())?) + } + Err(crate::Error::RemoteError((status, message))) if status.is_client_error() => { + page_signup_inner(ctx, &req_parts.headers, Some(message), Some(&body)).await + } + Err(other) => Err(other), + } } async fn page_user( diff --git a/src/routes/posts.rs b/src/routes/posts.rs index 3137f0e..e5a42f7 100644 --- a/src/routes/posts.rs +++ b/src/routes/posts.rs @@ -1,5 +1,5 @@ use super::{ - fetch_base_data, get_cookie_map, get_cookie_map_for_req, get_cookies_string, html_response, + fetch_base_data, get_cookie_map_for_headers, get_cookie_map_for_req, html_response, res_to_error, with_auth, }; use crate::components::{Comment, CommunityLink, Content, HTPage, UserLink}; @@ -215,11 +215,10 @@ async fn handler_post_submit_reply( ) -> Result<hyper::Response<hyper::Body>, crate::Error> { let (post_id,) = params; - let cookies_string = get_cookies_string(&req)?.map(ToOwned::to_owned); - let cookies_string = cookies_string.as_deref(); - let cookies = get_cookie_map(cookies_string)?; + let (req_parts, body) = req.into_parts(); + let cookies = get_cookie_map_for_headers(&req_parts.headers)?; - let body = hyper::body::to_bytes(req.into_body()).await?; + let body = hyper::body::to_bytes(body).await?; let body: serde_json::Value = serde_urlencoded::from_bytes(&body)?; let body = serde_json::to_vec(&body)?; |