nomilo/src/template.rs

64 lines
1.7 KiB
Rust

use std::path::Path;
use std::process::exit;
use serde::Serialize;
use rocket::request::Request;
use rocket::response::{self, Responder};
use rocket::http::{Status, ContentType};
use tera::{Tera, Context};
pub struct TemplateState {
tera: Tera,
}
impl TemplateState {
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")) {
Ok(tera) => TemplateState { tera },
Err(e) => {
println!("Loading templates failed: {}", e);
exit(1)
}
}
}
}
pub struct Template<'t, S: Serialize> {
pub name: &'t str,
pub context: S,
}
impl<'r, S: Serialize> Template<'r, S> {
pub fn new(name: &'r str, context: S) -> Self {
Template {
name,
context
}
}
fn render(self, tera: &Tera) -> Result<(ContentType, String), Status> {
let context = Context::from_serialize(self.context).map_err(|e| {
error!("Failed to serialize context: {}", e);
Status::InternalServerError
})?;
let content = tera.render(self.name, &context).map_err(|e| {
error!("Failed to render template `{}`: {}", self.name, e);
Status::InternalServerError
})?;
Ok((ContentType::HTML, content))
}
}
impl<'r, 't, S: Serialize> Responder<'r, 'static> for Template<'t, S> {
fn respond_to(self, request: &'r Request<'_>) -> response::Result<'static> {
let template_state = request.rocket().state::<TemplateState>().ok_or(Status::InternalServerError)?;
self.render(&template_state.tera).respond_to(request)
}
}