use anyhow::{Context, Error}; use std::{collections::HashMap, fs}; use warp::hyper::StatusCode; use crate::{ parser::parse, post::{Post, PostParser}, }; pub struct Blog { //pages: Vec<Page>, posts: Vec<(String, Post)>, } impl Blog { pub fn new() -> Result<Self, Error> { /*let pages = fs::read_dir("pages")? .map(|path| Page::new(path?)?) .collect();*/ let posts = fs::read_dir("posts")? .map(|path| { let path = path?.path(); let file_name = path .file_stem() .context("Could not get file name")? .to_str() .context("Could not convert filename into string")? .to_owned(); let slug = format!("/posts/{}", file_name.replace('-', "_").replace(' ', "-")); Ok(( slug, parse(PostParser::default(), &fs::read_to_string(path)?)?, )) }) .collect::<Result<_, anyhow::Error>>()?; Ok(Self { posts }) } fn home(&self) -> Result<String, Error> { let mut content = r#"<div class="centered"><h1>Stephen's Site</h1>Rewritten in Rust!</div><h4>Recent Posts</h4>"# .to_string(); for (slug, post) in &self.posts { content.push_str(&post.link(slug)); content.push_str("<br>"); } Ok(dress_page("Stephen's Site", &content)) } } pub struct RenderedBlog { pages: HashMap<String, String>, not_found: String, } impl RenderedBlog { pub fn get(&self, path: &str) -> (StatusCode, &str) { self.pages .get(path) .map(|x| (StatusCode::OK, x.as_str())) .unwrap_or((StatusCode::NOT_FOUND, &self.not_found)) } } impl TryFrom<Blog> for RenderedBlog { type Error = Error; fn try_from(b: Blog) -> Result<Self, Error> { let mut pages = HashMap::new(); for (slug, p) in &b.posts { let body = dress_page(&p.title, &p.html()?); pages.insert(slug.to_string(), body); } pages.insert( "/style.css".to_string(), include_str!("assets/style.css").to_string(), ); let home = b.home()?; pages.insert("/".to_string(), home); let not_found = dress_page("Page not found", include_str!("assets/404.html")); Ok(Self { not_found, pages }) } } fn dress_page(title: &str, content: &str) -> String { format!( r#"<html><head><link rel="stylesheet" href="/style.css" /><title>{title}</title></head><body><a href="/">Home</a><hr>{content}</body></html>"# ) }