summaryrefslogtreecommitdiffstats
path: root/src/routes/mod.rs
diff options
context:
space:
mode:
authorColin Reeder <colin@vpzom.click>2020-06-29 23:34:28 -0600
committerColin Reeder <colin@vpzom.click>2020-06-29 23:34:28 -0600
commit34126a8421eab043202b693fb55df13d3334a8f7 (patch)
tree6234e84786a5ef9e9268cf8f87b8fe73eef41716 /src/routes/mod.rs
parent1c9e1a95cfdd1394724f4edb48a5598438e0d163 (diff)
Split off more modules
Diffstat (limited to 'src/routes/mod.rs')
-rw-r--r--src/routes/mod.rs330
1 files changed, 4 insertions, 326 deletions
diff --git a/src/routes/mod.rs b/src/routes/mod.rs
index 6e3a7d8..06f5448 100644
--- a/src/routes/mod.rs
+++ b/src/routes/mod.rs
@@ -2,6 +2,10 @@ use serde_derive::Deserialize;
use std::borrow::Cow;
use std::sync::Arc;
+use crate::components::{Content, HTPage, PostItem, UserLink};
+use crate::resp_types::{RespPostCommentInfo, RespPostListPost};
+use crate::PageBaseData;
+
mod communities;
mod posts;
mod r#static;
@@ -54,32 +58,6 @@ fn with_auth(
Ok(new_req)
}
-fn author_is_me(author: &Option<RespMinimalAuthorInfo<'_>>, login: &Option<RespLoginInfo>) -> bool {
- if let Some(author) = author {
- if let Some(login) = login {
- if author.id == login.user.id {
- return true;
- }
- }
- }
- false
-}
-
-#[derive(Deserialize, Debug)]
-struct RespLoginInfoUser {
- id: i64,
-}
-
-#[derive(Deserialize, Debug)]
-struct RespLoginInfo {
- user: RespLoginInfoUser,
-}
-
-#[derive(Debug)]
-struct PageBaseData {
- login: Option<RespLoginInfo>,
-}
-
async fn fetch_base_data(
backend_host: &str,
http_client: &crate::HttpClient,
@@ -106,306 +84,6 @@ async fn fetch_base_data(
Ok(PageBaseData { login })
}
-#[derive(Deserialize, Debug)]
-struct RespMinimalAuthorInfo<'a> {
- id: i64,
- username: Cow<'a, str>,
- local: bool,
- host: Cow<'a, str>,
-}
-
-trait HavingContent {
- fn content_text(&self) -> Option<&str>;
- fn content_html(&self) -> Option<&str>;
-}
-
-#[derive(Deserialize, Debug)]
-struct RespPostListPost<'a> {
- id: i64,
- title: Cow<'a, str>,
- href: Option<Cow<'a, str>>,
- content_text: Option<Cow<'a, str>>,
- content_html: Option<Cow<'a, str>>,
- #[serde(borrow)]
- author: Option<RespMinimalAuthorInfo<'a>>,
- created: Cow<'a, str>,
- #[serde(borrow)]
- community: RespMinimalCommunityInfo<'a>,
-}
-
-impl<'a> HavingContent for RespPostListPost<'a> {
- fn content_text(&self) -> Option<&str> {
- self.content_text.as_deref()
- }
- fn content_html(&self) -> Option<&str> {
- self.content_html.as_deref()
- }
-}
-
-#[derive(Deserialize, Debug)]
-struct RespPostCommentInfo<'a> {
- id: i64,
- #[serde(borrow)]
- author: Option<RespMinimalAuthorInfo<'a>>,
- created: Cow<'a, str>,
- content_text: Option<Cow<'a, str>>,
- content_html: Option<Cow<'a, str>>,
- #[serde(borrow)]
- replies: Option<Vec<RespPostCommentInfo<'a>>>,
-}
-
-impl<'a> HavingContent for RespPostCommentInfo<'a> {
- fn content_text(&self) -> Option<&str> {
- self.content_text.as_deref()
- }
- fn content_html(&self) -> Option<&str> {
- self.content_html.as_deref()
- }
-}
-
-#[derive(Deserialize, Debug)]
-struct RespPostInfo<'a> {
- #[serde(flatten, borrow)]
- pub base: RespPostListPost<'a>,
- pub score: i64,
- #[serde(borrow)]
- pub comments: Vec<RespPostCommentInfo<'a>>,
-}
-
-impl<'a> AsRef<RespPostListPost<'a>> for RespPostInfo<'a> {
- fn as_ref(&self) -> &RespPostListPost<'a> {
- &self.base
- }
-}
-
-#[render::component]
-fn HTPage<'base_data, Children: render::Render>(
- base_data: &'base_data PageBaseData,
- children: Children,
-) {
- render::rsx! {
- <>
- <render::html::HTML5Doctype />
- <html>
- <head>
- <meta charset={"utf-8"} />
- <link rel={"stylesheet"} href={"/static/main.css"} />
- </head>
- <body>
- <header class={"mainHeader"}>
- <div class={"left actionList"}>
- <a href={"/"} class={"siteName"}>{"lotide"}</a>
- <a href={"/communities"}>{"Communities"}</a>
- </div>
- <div class={"right actionList"}>
- {
- match base_data.login {
- Some(_) => None,
- None => {
- Some(render::rsx! {
- <a href={"/login"}>{"Login"}</a>
- })
- }
- }
- }
- </div>
- </header>
- {children}
- </body>
- </html>
- </>
- }
-}
-
-fn abbreviate_link(href: &str) -> &str {
- // Attempt to find the hostname from the URL
- match href.find("://") {
- Some(idx1) => match href[(idx1 + 3)..].find('/') {
- Some(idx2) => Some(&href[(idx1 + 3)..(idx1 + 3 + idx2)]),
- None => None,
- },
- None => None,
- }
- .unwrap_or(href)
-}
-
-#[render::component]
-fn PostItem<'post>(post: &'post RespPostListPost<'post>, in_community: bool) {
- render::rsx! {
- <li>
- <a href={format!("/posts/{}", post.id)}>
- {post.title.as_ref()}
- </a>
- {
- if let Some(href) = &post.href {
- Some(render::rsx! {
- <>
- {" "}
- <em><a href={href.as_ref()}>{abbreviate_link(&href)}{" ↗"}</a></em>
- </>
- })
- } else {
- None
- }
- }
- <br />
- {"Submitted by "}<UserLink user={post.author.as_ref()} />
- {
- if !in_community {
- Some(render::rsx! {
- <>{" to "}<CommunityLink community={&post.community} /></>
- })
- } else {
- None
- }
- }
- </li>
- }
-}
-
-#[derive(Deserialize, Debug)]
-struct RespMinimalCommunityInfo<'a> {
- id: i64,
- name: Cow<'a, str>,
- local: bool,
- host: Cow<'a, str>,
-}
-
-struct UserLink<'user> {
- user: Option<&'user RespMinimalAuthorInfo<'user>>,
-}
-
-impl<'user> render::Render for UserLink<'user> {
- fn render_into<W: std::fmt::Write>(self, writer: &mut W) -> std::fmt::Result {
- match self.user {
- None => "[unknown]".render_into(writer),
- Some(user) => {
- let href = format!("/users/{}", user.id);
- (render::rsx! {
- <a href={&href}>
- {
- (if user.local {
- user.username.as_ref().into()
- } else {
- Cow::Owned(format!("{}@{}", user.username, user.host))
- }).as_ref()
- }
- </a>
- })
- .render_into(writer)
- }
- }
- }
-}
-
-struct CommunityLink<'community> {
- community: &'community RespMinimalCommunityInfo<'community>,
-}
-impl<'community> render::Render for CommunityLink<'community> {
- fn render_into<W: std::fmt::Write>(self, writer: &mut W) -> std::fmt::Result {
- let community = &self.community;
-
- let href = format!("/communities/{}", community.id);
- (render::rsx! {
- <a href={&href}>
- {
- (if community.local {
- community.name.as_ref().into()
- } else {
- Cow::Owned(format!("{}@{}", community.name, community.host))
- }).as_ref()
- }
- </a>
- })
- .render_into(writer)
- }
-}
-
-struct Content<'a, T: HavingContent + 'a> {
- src: &'a T,
-}
-
-impl<'a, T: HavingContent + 'a> render::Render for Content<'a, T> {
- fn render_into<W: std::fmt::Write>(self, writer: &mut W) -> std::fmt::Result {
- match self.src.content_html() {
- Some(html) => {
- let cleaned = ammonia::clean(&html);
- writer.write_str("<p>")?;
- render::raw!(cleaned.as_ref()).render_into(writer)?;
- writer.write_str("</p>")?;
- }
- None => match self.src.content_text() {
- Some(text) => {
- writer.write_str("<p>")?;
- text.render_into(writer)?;
- writer.write_str("</p>")?;
- }
- None => {}
- },
- }
-
- Ok(())
- }
-}
-
-#[render::component]
-fn Comment<'comment, 'base_data>(
- comment: &'comment RespPostCommentInfo<'comment>,
- base_data: &'base_data PageBaseData,
-) {
- render::rsx! {
- <li>
- <small><cite><UserLink user={comment.author.as_ref()} /></cite>{":"}</small>
- <Content src={comment} />
- <div class={"actionList"}>
- {
- if base_data.login.is_some() {
- Some(render::rsx! {
- <>
- <form method={"POST"} action={format!("/comments/{}/like", comment.id)} style={"display: inline"}>
- <button r#type={"submit"}>{"Like"}</button>
- </form>
- <a href={format!("/comments/{}", comment.id)}>{"reply"}</a>
- </>
- })
- } else {
- None
- }
- }
- {
- if author_is_me(&comment.author, &base_data.login) {
- Some(render::rsx! {
- <a href={format!("/comments/{}/delete", comment.id)}>{"delete"}</a>
- })
- } else {
- None
- }
- }
- </div>
-
- {
- match &comment.replies {
- Some(replies) => {
- Some(render::rsx! {
- <ul>
- {
- replies.iter().map(|reply| {
- render::rsx! {
- <Comment comment={reply} base_data />
- }
- })
- .collect::<Vec<_>>()
- }
- </ul>
- })
- },
- None => None,
- }
- }
- </li>
- }
-}
-
fn html_response(html: String) -> hyper::Response<hyper::Body> {
let mut res = hyper::Response::new(html.into());
res.headers_mut().insert(