use actix_web::{get, web, HttpResponse, Responder}; use cached::proc_macro::once; use ramhorns::Content; use crate::{ config::Config, template::{get_md_asm, get_md_metadata, read_md_file, File, FileMetadata, Infos}, }; #[get("/blog")] pub async fn index(config: web::Data) -> impl Responder { HttpResponse::Ok().body(get_index(config.get_ref().clone())) } #[derive(Content)] struct BlogIndexTemplate { posts: Option>, } #[derive(Content, Debug)] struct Post { title: String, date: String, url: String, } #[once(time = 60)] pub fn get_index(config: Config) -> String { let location = "data/blog"; let mut entries = std::fs::read_dir(location) .unwrap() .flatten() .filter(|f| f.path().extension().unwrap() == "md") .collect::>(); entries.sort_by_cached_key(|f| { f.metadata() .unwrap() .modified() .unwrap_or(f.metadata().unwrap().created().unwrap()) }); entries.reverse(); let paths = entries .iter() .map(|f| { let _filename = f.file_name(); let filename = _filename.to_string_lossy(); let file_without_ext = filename.split_at(filename.len() - 3).0; let file_metadata = match std::fs::read_to_string(format!("{location}/{filename}")) { Ok(text) => { let md_tree = get_md_asm(&text); let md_nodes = md_tree.children().unwrap(); let mut metadata = get_md_metadata(md_nodes); metadata.title = match metadata.title { Some(t) => Some(t), None => Some(file_without_ext.to_string()), }; metadata } Err(_) => FileMetadata { title: Some(file_without_ext.to_string()), link: None, date: None, }, }; Post { url: file_without_ext.to_string(), title: file_metadata.title.unwrap(), date: file_metadata.date.unwrap_or_default(), } }) .collect::>(); config.tmpl.render( "blog/index.html", BlogIndexTemplate { posts: if paths.is_empty() { None } else { Some(paths) }, }, Infos { page_title: Some("Blog".to_string()), page_desc: Some("Liste des posts d'Anri".to_string()), page_kw: Some(["blog", "blogging"].join(", ")), }, ) } #[derive(Content)] struct BlogPostTemplate { post: Option, } #[get("/blog/{id}")] pub async fn page(path: web::Path<(String,)>, config: web::Data) -> impl Responder { HttpResponse::Ok().body(get_post(path.into_inner().0, config.get_ref().clone())) } pub fn get_post(file: String, config: Config) -> String { let mut post = None; let infos = _get_post(&mut post, file); config .tmpl .render("blog/post.html", BlogPostTemplate { post }, infos) } fn _get_post(post: &mut Option, filename: String) -> Infos { let blog_dir = "data/blog"; let ext = ".md"; *post = read_md_file(&format!("{blog_dir}/{filename}{ext}")); let title = match post { Some(data) => match &data.metadata.info.title { Some(text) => text, None => &filename, }, None => &filename, }; Infos { page_title: Some(format!("Post: {}", title)), page_desc: Some("Blog d'Anri".to_string()), page_kw: Some(["blog", "blogging", "write", "writing"].join(", ")), } }