use actix_web::{http::header, web, FromRequest, HttpRequest, HttpResponse};
use minijinja::{path_loader, Environment, Error, State};
use rust_embed::RustEmbed;
use serde::Serialize;
#[derive(RustEmbed)]
#[folder = "src/empty/"]
pub struct NoTemplates;
#[cfg(feature = "html")]
#[derive(RustEmbed)]
#[folder = "templates/"]
struct BaseTemplates;
#[cfg(not(feature = "html"))]
type BaseTemplates = NoTemplates;
fn truncate(_state: &State, value: String, new_len: usize) -> Result<String, Error> {
let mut s = value;
s.truncate(new_len);
Ok(s)
}
pub fn create_env(path: &str, _extensions: &[&str]) -> Environment<'static> {
let mut env = create_base_env();
env.set_loader(path_loader(path));
env
}
pub fn create_env_embedded<E: RustEmbed>() -> Environment<'static> {
let mut env = create_base_env();
for f in E::iter() {
add_embedded_template::<E>(&mut env, &f);
}
env
}
fn create_base_env() -> Environment<'static> {
let mut env = Environment::new();
env.add_filter("truncate", truncate);
for f in BaseTemplates::iter() {
add_embedded_template::<BaseTemplates>(&mut env, &f);
}
env
}
fn add_embedded_template<E: RustEmbed>(env: &mut Environment<'static>, fname: &str) {
let templ = String::from_utf8(E::get(fname).unwrap().data.to_vec()).unwrap();
env.add_template_owned(fname.to_string(), templ).unwrap();
}
pub async fn render_endpoint<S: Serialize>(
env: &Environment<'static>,
template: &str,
ctx: S,
) -> actix_web::Result<HttpResponse, actix_web::Error> {
let template = env.get_template(template).expect("couln't load template");
let page = template.render(ctx).expect("template render failed");
Ok(HttpResponse::Ok().content_type("text/html").body(page))
}
pub async fn html_accepted(req: &HttpRequest) -> bool {
if cfg!(not(feature = "html")) {
return false;
}
if req.path().ends_with(".json") {
return false;
}
web::Header::<header::Accept>::extract(req)
.await
.map(|accept| &accept.preference().to_string() == "text/html")
.unwrap_or(false)
}