webserver_base/templates/
template_registry.rsuse crate::TemplateRegistryError;
use chrono::{DateTime, Utc};
use handlebars::{handlebars_helper, Handlebars};
use serde::Serialize;
use std::path::PathBuf;
use std::{env, fs};
use tracing::instrument;
handlebars_helper!(
    join: |list: Vec<String>| list.join(",")
);
handlebars_helper!(
    pretty_date: |date: DateTime<Utc>| date.format("%B %e, %Y").to_string()
);
#[derive(Clone)]
pub struct TemplateRegistry<'a> {
    handlebars: Handlebars<'a>,
}
impl TemplateRegistry<'_> {
    #[instrument(skip_all)]
    pub fn new() -> Result<Self, TemplateRegistryError> {
        let mut handlebars = Handlebars::new();
        handlebars.register_helper("join", Box::new(join));
        handlebars.register_helper("pretty_date", Box::new(pretty_date));
        handlebars.set_strict_mode(true);
        let mut html_path: PathBuf = env::current_dir()?;
        html_path.push("html");
        let template_files: Vec<PathBuf> =
            TemplateRegistry::find_all_template_files(&mut html_path)?;
        for template_file in template_files {
            let file_name = template_file
                .file_stem()
                .expect("failed to extract stem (non-file-extension) part of template file name")
                .to_string_lossy();
            handlebars.register_template_file(file_name.as_ref(), &template_file)?;
        }
        Ok(Self { handlebars })
    }
    #[instrument(skip_all)]
    fn find_all_template_files(
        html_path: &mut PathBuf,
    ) -> Result<Vec<PathBuf>, TemplateRegistryError> {
        let mut template_files: Vec<PathBuf> = vec![];
        for directory in &["layouts", "pages", "partials"] {
            html_path.push(directory);
            template_files.extend(TemplateRegistry::get_all_files(html_path)?);
            html_path.pop();
        }
        Ok(template_files)
    }
    #[instrument(skip_all)]
    fn get_all_files(current_dir: &PathBuf) -> Result<Vec<PathBuf>, TemplateRegistryError> {
        let mut files: Vec<PathBuf> = vec![];
        for entry in fs::read_dir(current_dir)? {
            let entry = entry?;
            let path = entry.path();
            files.push(path);
        }
        Ok(files)
    }
    #[instrument(skip_all)]
    pub fn render<T>(&self, name: &str, data: &T) -> Result<String, TemplateRegistryError>
    where
        T: Serialize,
    {
        let rendered_template: String = self.handlebars.render(name, data)?;
        Ok(rendered_template)
    }
}