summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Reeder <colin@vpzom.click>2020-07-15 19:12:13 -0600
committerColin Reeder <colin@vpzom.click>2020-07-15 19:12:13 -0600
commit2a708a587e1eb492ec3c1b1b74656d2c80b54438 (patch)
tree9ad1714bd0fa39bd5983569254aab6b6f350f087
parent62fd45ddfd9ff651c63807dd83cc2591f60c2547 (diff)
User content listing
-rw-r--r--src/components/mod.rs58
-rw-r--r--src/resp_types.rs39
-rw-r--r--src/routes/communities.rs2
-rw-r--r--src/routes/mod.rs48
-rw-r--r--src/routes/posts.rs12
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>