diff options
-rw-r--r-- | src/resp_types.rs | 13 | ||||
-rw-r--r-- | src/routes/mod.rs | 124 |
2 files changed, 131 insertions, 6 deletions
diff --git a/src/resp_types.rs b/src/resp_types.rs index 38bbec7..c2d91f3 100644 --- a/src/resp_types.rs +++ b/src/resp_types.rs @@ -95,6 +95,19 @@ pub struct RespMinimalCommunityInfo<'a> { } #[derive(Deserialize, Debug)] +pub struct RespUserInfo<'a> { + #[serde(flatten)] + pub base: RespMinimalAuthorInfo<'a>, + pub description: Cow<'a, str>, +} + +impl<'a> AsRef<RespMinimalAuthorInfo<'a>> for RespUserInfo<'a> { + fn as_ref(&self) -> &RespMinimalAuthorInfo<'a> { + &self.base + } +} + +#[derive(Deserialize, Debug)] pub struct RespLoginInfoUser { pub id: i64, } diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 736a1ff..4d2daf6 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -5,9 +5,7 @@ use std::sync::Arc; use crate::components::{ Comment, Content, HTPage, MaybeFillInput, MaybeFillTextArea, PostItem, ThingItem, UserLink, }; -use crate::resp_types::{ - RespMinimalAuthorInfo, RespPostCommentInfo, RespPostListPost, RespThingInfo, -}; +use crate::resp_types::{RespPostCommentInfo, RespPostListPost, RespThingInfo, RespUserInfo}; use crate::util::author_is_me; use crate::PageBaseData; @@ -899,7 +897,7 @@ async fn page_user( ) .await?; let user = hyper::body::to_bytes(user.into_body()).await?; - let user: RespMinimalAuthorInfo<'_> = serde_json::from_slice(&user)?; + let user: RespUserInfo<'_> = serde_json::from_slice(&user)?; let things = res_to_error( ctx.http_client @@ -916,12 +914,24 @@ async fn page_user( let things = hyper::body::to_bytes(things.into_body()).await?; let things: Vec<RespThingInfo> = serde_json::from_slice(&things)?; - let title = user.username.as_ref(); + let title = user.as_ref().username.as_ref(); Ok(html_response(render::html! { <HTPage base_data={&base_data} title> <h1>{title}</h1> { + if let Some(login) = &base_data.login { + if login.user.id == user_id { + Some(render::rsx! { <a href={format!("/users/{}/edit", user_id)}>{"Edit"}</a> }) + } else { + None + } + } else { + None + } + } + <p>{user.description.as_ref()}</p> + { if things.is_empty() { Some(render::rsx! { <p>{"Looks like there's nothing here."}</p> }) } else { @@ -940,6 +950,97 @@ async fn page_user( })) } +async fn page_user_edit( + params: (i64,), + ctx: Arc<crate::RouteContext>, + req: hyper::Request<hyper::Body>, +) -> Result<hyper::Response<hyper::Body>, crate::Error> { + let (user_id,) = params; + + let cookies = get_cookie_map_for_req(&req)?; + + let base_data = fetch_base_data(&ctx.backend_host, &ctx.http_client, &cookies).await?; + + let is_me = match &base_data.login { + None => false, + Some(login) => login.user.id == user_id, + }; + + if !is_me { + let mut res = html_response(render::html! { + <HTPage base_data={&base_data} title={"Edit Profile"}> + <h1>{"Edit Profile"}</h1> + <div class={"errorBox"}>{"You can only edit your own profile."}</div> + </HTPage> + }); + + *res.status_mut() = hyper::StatusCode::FORBIDDEN; + + return Ok(res); + } + + let user = res_to_error( + ctx.http_client + .request( + hyper::Request::get(format!( + "{}/api/unstable/users/{}", + ctx.backend_host, user_id + )) + .body(Default::default())?, + ) + .await?, + ) + .await?; + let user = hyper::body::to_bytes(user.into_body()).await?; + let user: RespUserInfo<'_> = serde_json::from_slice(&user)?; + + Ok(html_response(render::html! { + <HTPage base_data={&base_data} title={"Edit Profile"}> + <h1>{"Edit Profile"}</h1> + <form method={"POST"} action={format!("/users/{}/edit/submit", user_id)}> + <div> + <label> + {"Profile Description:"}<br /> + <textarea name={"description"}>{user.description.as_ref()}</textarea> + </label> + </div> + <button type={"submit"}>{"Save"}</button> + </form> + </HTPage> + })) +} + +async fn handler_user_edit_submit( + params: (i64,), + ctx: Arc<crate::RouteContext>, + req: hyper::Request<hyper::Body>, +) -> Result<hyper::Response<hyper::Body>, crate::Error> { + let (user_id,) = params; + + let (req_parts, body) = req.into_parts(); + + let cookies = get_cookie_map_for_headers(&req_parts.headers)?; + + let body = hyper::body::to_bytes(body).await?; + let body: serde_json::Value = serde_urlencoded::from_bytes(&body)?; + + res_to_error( + ctx.http_client + .request(with_auth( + hyper::Request::patch(format!("{}/api/unstable/users/me", ctx.backend_host)) + .body(serde_json::to_vec(&body)?.into())?, + &cookies, + )?) + .await?, + ) + .await?; + + Ok(hyper::Response::builder() + .status(hyper::StatusCode::SEE_OTHER) + .header(hyper::header::LOCATION, format!("/users/{}", user_id)) + .body("Successfully created.".into())?) +} + async fn page_home( _: (), ctx: Arc<crate::RouteContext>, @@ -1127,7 +1228,18 @@ pub fn route_root() -> crate::RouteNode<()> { .with_child( "users", crate::RouteNode::new().with_child_parse::<i64, _>( - crate::RouteNode::new().with_handler_async("GET", page_user), + crate::RouteNode::new() + .with_handler_async("GET", page_user) + .with_child( + "edit", + crate::RouteNode::new() + .with_handler_async("GET", page_user_edit) + .with_child( + "submit", + crate::RouteNode::new() + .with_handler_async("POST", handler_user_edit_submit), + ), + ), ), ) } |