//! templated file handling //! //! Reads files from the filesystem, processes them as a template, and prepares //! a `Response` for them. //! //! See [`templated`] for how templates are handled use axum::{body::Body, response::Response}; use bempline::{Document, Options, options::IncludeMethod}; use paige::Templated; use crate::{ RuntimeError, config::Settings, fs::{self, RequestPath, SafePathBuf}, state::SplormState, templated::TemplateVariables, }; pub async fn send_file( path: RequestPath, state: SplormState, settings: &Settings, ) -> Result { let safe = path.system_path().to_owned(); let string = fs::read_file_to_string(path.system_path()).await?; let template = Templated::parse(&string) .map_err(|_| RuntimeError::not_a_template(path.system_path().to_path_buf()))?; let tvars = TemplateVariables::build(safe.as_path(), &template.frontmatter); tracing::trace!( "page {} has features {:?}", path.web_path(), tvars.features() ); let pt_path = match tvars.template() { Some(name) => { let path = RequestPath::verify_safe(settings.template_dir(), &format!("{name}.html"))?; path.system_path().to_owned() } None => { tracing::trace!( "using default template: {}", settings.default_template_name() ); settings.default_template_path() } }; let mut page_template = get_template(pt_path).await?; tvars.apply_title(&mut page_template); tvars.apply_styles(&mut page_template); tvars.apply_published(&mut page_template); tvars.apply_pathnav(&mut page_template, &path); tvars.apply_opengraph(&mut page_template, &settings, &path); let content = if !tvars.features().is_empty() { let with_features = tvars.apply_features(template.content, &state).await; tvars.apply_markup(&mut page_template, &with_features) } else { tvars.apply_markup(&mut page_template, template.content) }; page_template.set("main", content); Response::builder() .status(200) .header("content-type", "text/html") .body(Body::from(page_template.compile())) .map_err(|_| RuntimeError::Unknown) } async fn get_template(path: SafePathBuf) -> Result { let options = Options::new().include_path(IncludeMethod::Path(path.as_std_path().to_owned())); let str = fs::read_file_to_string(path.as_path()).await?; Document::from_str(str, options) .map_err(|perr| RuntimeError::template_parse_error(perr, path.to_path_buf())) }