diff options
author | Colin Reeder <colin@vpzom.click> | 2020-07-15 19:12:13 -0600 |
---|---|---|
committer | Colin Reeder <colin@vpzom.click> | 2020-07-15 19:12:13 -0600 |
commit | 2a708a587e1eb492ec3c1b1b74656d2c80b54438 (patch) | |
tree | 9ad1714bd0fa39bd5983569254aab6b6f350f087 | |
parent | 62fd45ddfd9ff651c63807dd83cc2591f60c2547 (diff) |
User content listing
-rw-r--r-- | src/components/mod.rs | 58 | ||||
-rw-r--r-- | src/resp_types.rs | 39 | ||||
-rw-r--r-- | src/routes/communities.rs | 2 | ||||
-rw-r--r-- | src/routes/mod.rs | 48 | ||||
-rw-r--r-- | src/routes/posts.rs | 12 |
5 files changed, 133 insertions, 26 deletions
diff --git a/src/components/mod.rs b/src/components/mod.rs index 1c0e76c..a8aaa1b 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -2,7 +2,8 @@ use std::borrow::{Borrow, Cow}; use std::collections::HashMap; use crate::resp_types::{ - RespMinimalAuthorInfo, RespMinimalCommunityInfo, RespPostCommentInfo, RespPostListPost, + RespMinimalAuthorInfo, RespMinimalCommunityInfo, RespPostCommentInfo, RespPostInfo, + RespPostListPost, RespThingComment, RespThingInfo, }; use crate::util::{abbreviate_link, author_is_me}; use crate::PageBaseData; @@ -122,7 +123,16 @@ impl<'a> HavingContent for RespPostCommentInfo<'a> { } } -impl<'a> HavingContent for RespPostListPost<'a> { +impl<'a> HavingContent for RespThingComment<'a> { + fn content_text(&self) -> Option<&str> { + self.content_text.as_deref() + } + fn content_html(&self) -> Option<&str> { + self.content_html.as_deref() + } +} + +impl<'a> HavingContent for RespPostInfo<'a> { fn content_text(&self) -> Option<&str> { self.content_text.as_deref() } @@ -202,11 +212,11 @@ pub fn HTPage<'a, Children: render::Render>( } #[render::component] -pub fn PostItem<'post>(post: &'post RespPostListPost<'post>, in_community: bool) { +pub fn PostItem<'post>(post: &'post RespPostListPost<'post>, in_community: bool, no_user: bool) { render::rsx! { <li> - <a href={format!("/posts/{}", post.id)}> - {post.title.as_ref()} + <a href={format!("/posts/{}", post.as_ref().id)}> + {post.as_ref().title.as_ref()} </a> { if let Some(href) = &post.href { @@ -221,7 +231,18 @@ pub fn PostItem<'post>(post: &'post RespPostListPost<'post>, in_community: bool) } } <br /> - {"Submitted by "}<UserLink user={post.author.as_ref()} /> + {"Submitted"} + { + if no_user { + None + } else { + Some(render::rsx! { + <> + {" by "}<UserLink user={post.author.as_ref()} /> + </> + }) + } + } { if !in_community { Some(render::rsx! { @@ -235,6 +256,31 @@ pub fn PostItem<'post>(post: &'post RespPostListPost<'post>, in_community: bool) } } +pub struct ThingItem<'a> { + pub thing: &'a RespThingInfo<'a>, +} + +impl<'a> render::Render for ThingItem<'a> { + fn render_into<W: std::fmt::Write>(self, writer: &mut W) -> std::fmt::Result { + match self.thing { + RespThingInfo::Post(post) => { + (PostItem { post, in_community: false, no_user: true }).render_into(writer) + }, + RespThingInfo::Comment(comment) => { + (render::rsx! { + <li> + <small> + <a href={format!("/comments/{}", comment.id)}>{"Comment"}</a> + {" on "}<a href={format!("/posts/{}", comment.post.id)}>{comment.post.title.as_ref()}</a>{":"} + </small> + <Content src={comment} /> + </li> + }).render_into(writer) + } + } + } +} + pub struct UserLink<'user> { pub user: Option<&'user RespMinimalAuthorInfo<'user>>, } diff --git a/src/resp_types.rs b/src/resp_types.rs index f1e5bc1..38bbec7 100644 --- a/src/resp_types.rs +++ b/src/resp_types.rs @@ -10,12 +10,16 @@ pub struct RespMinimalAuthorInfo<'a> { } #[derive(Deserialize, Debug)] -pub struct RespPostListPost<'a> { +pub struct RespMinimalPostInfo<'a> { pub id: i64, pub title: Cow<'a, str>, +} + +#[derive(Deserialize, Debug)] +pub struct RespPostListPost<'a> { + #[serde(flatten)] + pub base: RespMinimalPostInfo<'a>, pub href: Option<Cow<'a, str>>, - pub content_text: Option<Cow<'a, str>>, - pub content_html: Option<Cow<'a, str>>, #[serde(borrow)] pub author: Option<RespMinimalAuthorInfo<'a>>, pub created: Cow<'a, str>, @@ -23,6 +27,32 @@ pub struct RespPostListPost<'a> { pub community: RespMinimalCommunityInfo<'a>, } +impl<'a> AsRef<RespMinimalPostInfo<'a>> for RespPostListPost<'a> { + fn as_ref(&self) -> &RespMinimalPostInfo<'a> { + &self.base + } +} + +#[derive(Deserialize, Debug)] +#[serde(tag = "type")] +pub enum RespThingInfo<'a> { + #[serde(rename = "post")] + Post(RespPostListPost<'a>), + #[serde(rename = "comment")] + #[serde(borrow)] + Comment(RespThingComment<'a>), +} + +#[derive(Deserialize, Debug)] +pub struct RespThingComment<'a> { + pub id: i64, + pub created: Cow<'a, str>, + pub content_text: Option<Cow<'a, str>>, + pub content_html: Option<Cow<'a, str>>, + #[serde(borrow)] + pub post: RespMinimalPostInfo<'a>, +} + #[derive(Deserialize, Debug)] pub struct RespPostCommentInfo<'a> { pub id: i64, @@ -41,6 +71,9 @@ pub struct RespPostCommentInfo<'a> { pub struct RespPostInfo<'a> { #[serde(flatten, borrow)] pub base: RespPostListPost<'a>, + + pub content_text: Option<Cow<'a, str>>, + pub content_html: Option<Cow<'a, str>>, pub score: i64, #[serde(borrow)] pub comments: Vec<RespPostCommentInfo<'a>>, diff --git a/src/routes/communities.rs b/src/routes/communities.rs index c541ea1..76899cb 100644 --- a/src/routes/communities.rs +++ b/src/routes/communities.rs @@ -201,7 +201,7 @@ async fn page_community( } <ul> {posts.iter().map(|post| { - PostItem { post, in_community: true } + PostItem { post, in_community: true, no_user: false } }).collect::<Vec<_>>()} </ul> </HTPage> diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 629a4d7..a6e87f4 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -3,9 +3,11 @@ use std::borrow::Cow; use std::sync::Arc; use crate::components::{ - Comment, Content, HTPage, MaybeFillInput, MaybeFillTextArea, PostItem, UserLink, + Comment, Content, HTPage, MaybeFillInput, MaybeFillTextArea, PostItem, ThingItem, UserLink, +}; +use crate::resp_types::{ + RespMinimalAuthorInfo, RespPostCommentInfo, RespPostListPost, RespThingInfo, }; -use crate::resp_types::{RespMinimalAuthorInfo, RespPostCommentInfo, RespPostListPost}; use crate::util::author_is_me; use crate::PageBaseData; @@ -884,7 +886,7 @@ async fn page_user( let base_data = fetch_base_data(&ctx.backend_host, &ctx.http_client, &cookies).await?; - let api_res = res_to_error( + let user = res_to_error( ctx.http_client .request( hyper::Request::get(format!( @@ -896,18 +898,44 @@ async fn page_user( .await?, ) .await?; + let user = hyper::body::to_bytes(user.into_body()).await?; + let user: RespMinimalAuthorInfo<'_> = serde_json::from_slice(&user)?; - let api_res = hyper::body::to_bytes(api_res.into_body()).await?; - let user: RespMinimalAuthorInfo<'_> = serde_json::from_slice(&api_res)?; + let things = res_to_error( + ctx.http_client + .request( + hyper::Request::get(format!( + "{}/api/unstable/users/{}/things", + ctx.backend_host, user_id, + )) + .body(Default::default())?, + ) + .await?, + ) + .await?; + 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(); Ok(html_response(render::html! { <HTPage base_data={&base_data} title> <h1>{title}</h1> - <p> - <em>{"User post listing is not currently implemented."}</em> - </p> + { + if things.is_empty() { + Some(render::rsx! { <p>{"Looks like there's nothing here."}</p> }) + } else { + None + } + } + <ul> + { + things.iter().map(|thing| { + ThingItem { thing } + }) + .collect::<Vec<_>>() + } + </ul> </HTPage> })) } @@ -959,7 +987,7 @@ async fn page_home( } <ul> {api_res.iter().map(|post| { - PostItem { post, in_community: false } + PostItem { post, in_community: false, no_user: false } }).collect::<Vec<_>>()} </ul> </HTPage> @@ -1013,7 +1041,7 @@ async fn page_all_inner( } <ul> {api_res.iter().map(|post| { - PostItem { post, in_community: false } + PostItem { post, in_community: false, no_user: false } }).collect::<Vec<_>>()} </ul> </HTPage> diff --git a/src/routes/posts.rs b/src/routes/posts.rs index fd6cf26..522d2c5 100644 --- a/src/routes/posts.rs +++ b/src/routes/posts.rs @@ -41,7 +41,7 @@ async fn page_post( let post: RespPostInfo = serde_json::from_slice(&api_res)?; - let title = post.as_ref().title.as_ref(); + let title = post.as_ref().as_ref().title.as_ref(); Ok(html_response(render::html! { <HTPage base_data={&base_data} title={title}> @@ -83,7 +83,7 @@ async fn page_post( } } } - <Content src={post.as_ref()} /> + <Content src={&post} /> { if author_is_me(&post.as_ref().author, &base_data.login) { Some(render::rsx! { @@ -100,7 +100,7 @@ async fn page_post( { if base_data.login.is_some() { Some(render::rsx! { - <form method={"POST"} action={format!("/posts/{}/submit_reply", post.as_ref().id)}> + <form method={"POST"} action={format!("/posts/{}/submit_reply", post.as_ref().as_ref().id)}> <div> <textarea name={"content_text"}>{()}</textarea> </div> @@ -155,10 +155,10 @@ async fn page_post_delete( Ok(html_response(render::html! { <HTPage base_data={&base_data} title={"Delete Post"}> - <h1>{post.as_ref().title.as_ref()}</h1> + <h1>{post.as_ref().as_ref().title.as_ref()}</h1> <h2>{"Delete this post?"}</h2> - <form method={"POST"} action={format!("/posts/{}/delete/confirm", post.as_ref().id)}> - <a href={format!("/posts/{}/", post.as_ref().id)}>{"No, cancel"}</a> + <form method={"POST"} action={format!("/posts/{}/delete/confirm", post.as_ref().as_ref().id)}> + <a href={format!("/posts/{}/", post.as_ref().as_ref().id)}>{"No, cancel"}</a> {" "} <button r#type={"submit"}>{"Yes, delete"}</button> </form> |