Skip to content
Snippets Groups Projects
blog.rs 2.67 KiB
Newer Older
Stephen D's avatar
Stephen D committed
use anyhow::{Context, Error};
use std::{collections::HashMap, fs};
use warp::hyper::StatusCode;

use crate::{
    parser::{parse, parse_org, parse_org_summary},
    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>"#.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>"#
    )
}