2022-04-29 02:29:10 +00:00
|
|
|
use std::path::Path;
|
|
|
|
use std::process::exit;
|
2024-12-22 21:36:26 +00:00
|
|
|
use std::sync::Arc;
|
2022-04-29 02:29:10 +00:00
|
|
|
|
2024-12-22 21:36:26 +00:00
|
|
|
use axum::response::{Html, IntoResponse};
|
2022-04-29 02:29:10 +00:00
|
|
|
use serde::Serialize;
|
|
|
|
use tera::{Tera, Context};
|
|
|
|
|
2024-12-22 21:36:26 +00:00
|
|
|
use crate::errors::Error;
|
|
|
|
|
2022-04-29 02:29:10 +00:00
|
|
|
|
2024-12-22 21:36:26 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct TemplateEngine {
|
|
|
|
tera: Arc<Tera>,
|
2022-04-29 02:29:10 +00:00
|
|
|
}
|
|
|
|
|
2024-12-22 21:36:26 +00:00
|
|
|
pub enum TemplateError {
|
|
|
|
SerializationError { reason: Box<dyn std::error::Error> },
|
|
|
|
RenderError { name: String, reason: Box<dyn std::error::Error> },
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TemplateEngine {
|
2022-04-29 02:33:00 +00:00
|
|
|
pub fn new(template_directory: &Path) -> Self {
|
|
|
|
let template_glob = template_directory.join("**").join("*");
|
|
|
|
match Tera::new(template_glob.to_str().expect("valid glob path string")) {
|
2024-12-22 21:36:26 +00:00
|
|
|
Ok(tera) => TemplateEngine { tera: Arc::new(tera) },
|
2022-04-29 02:33:00 +00:00
|
|
|
Err(e) => {
|
|
|
|
println!("Loading templates failed: {}", e);
|
|
|
|
exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-12-22 21:36:26 +00:00
|
|
|
|
|
|
|
pub fn render<S: Serialize>(&self, name: &str, context: S) -> Result<String, TemplateError> {
|
|
|
|
let context = Context::from_serialize(context).map_err(|e| {
|
|
|
|
TemplateError::SerializationError { reason: Box::new(e) }
|
|
|
|
})?;
|
|
|
|
|
|
|
|
let content = self.tera.render(name, &context).map_err(|e| {
|
|
|
|
TemplateError::RenderError { name: name.into(), reason: Box::new(e) }
|
|
|
|
})?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(content)
|
|
|
|
}
|
2022-04-29 02:29:10 +00:00
|
|
|
}
|
|
|
|
|
2024-12-22 21:36:26 +00:00
|
|
|
pub struct Template<'n, S: Serialize> {
|
|
|
|
pub name: &'n str,
|
|
|
|
pub engine: TemplateEngine,
|
2022-04-29 02:33:00 +00:00
|
|
|
pub context: S,
|
2022-04-29 02:29:10 +00:00
|
|
|
}
|
|
|
|
|
2024-12-22 21:36:26 +00:00
|
|
|
impl<'n, S: Serialize> Template<'n, S> {
|
|
|
|
pub fn new(name: &'n str, engine: TemplateEngine, context: S) -> Self {
|
2022-04-29 02:33:00 +00:00
|
|
|
Template {
|
|
|
|
name,
|
2024-12-22 21:36:26 +00:00
|
|
|
engine,
|
|
|
|
context,
|
2022-04-29 02:33:00 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-29 02:29:10 +00:00
|
|
|
}
|
|
|
|
|
2024-12-22 21:36:26 +00:00
|
|
|
impl<S: Serialize> IntoResponse for Template<'_, S> {
|
|
|
|
fn into_response(self) -> axum::response::Response {
|
|
|
|
let res = self.engine.render(self.name, self.context);
|
2022-04-29 02:29:10 +00:00
|
|
|
|
2024-12-22 21:36:26 +00:00
|
|
|
match res {
|
|
|
|
Ok(content) => Html(content).into_response(),
|
|
|
|
Err(err) => Error::from(err).into_response(),
|
|
|
|
}
|
2022-04-29 02:29:10 +00:00
|
|
|
}
|
|
|
|
}
|