bbox_core/
templates.rs

1use actix_web::{http::header, web, FromRequest, HttpRequest, HttpResponse};
2use minijinja::{path_loader, Environment, Error, State};
3use rust_embed::RustEmbed;
4use serde::Serialize;
5
6#[derive(RustEmbed)]
7#[folder = "src/empty/"]
8pub struct NoTemplates;
9
10#[cfg(feature = "html")]
11#[derive(RustEmbed)]
12#[folder = "templates/"]
13struct BaseTemplates;
14
15#[cfg(not(feature = "html"))]
16type BaseTemplates = NoTemplates;
17
18fn truncate(_state: &State, value: String, new_len: usize) -> Result<String, Error> {
19    let mut s = value;
20    s.truncate(new_len);
21    Ok(s)
22}
23
24pub fn create_env(path: &str, _extensions: &[&str]) -> Environment<'static> {
25    let mut env = create_base_env();
26    env.set_loader(path_loader(path));
27    env
28}
29
30pub fn create_env_embedded<E: RustEmbed>() -> Environment<'static> {
31    let mut env = create_base_env();
32    for f in E::iter() {
33        add_embedded_template::<E>(&mut env, &f);
34    }
35    env
36}
37
38fn create_base_env() -> Environment<'static> {
39    let mut env = Environment::new();
40    env.add_filter("truncate", truncate);
41    for f in BaseTemplates::iter() {
42        add_embedded_template::<BaseTemplates>(&mut env, &f);
43    }
44    env
45}
46
47fn add_embedded_template<E: RustEmbed>(env: &mut Environment<'static>, fname: &str) {
48    let templ = String::from_utf8(E::get(fname).unwrap().data.to_vec()).unwrap();
49    env.add_template_owned(fname.to_string(), templ).unwrap();
50}
51
52/// Return rendered template
53pub async fn render_endpoint<S: Serialize>(
54    env: &Environment<'static>,
55    template: &str,
56    ctx: S,
57) -> actix_web::Result<HttpResponse, actix_web::Error> {
58    let template = env.get_template(template).expect("couln't load template");
59    let page = template.render(ctx).expect("template render failed");
60    Ok(HttpResponse::Ok().content_type("text/html").body(page))
61}
62
63pub async fn html_accepted(req: &HttpRequest) -> bool {
64    if cfg!(not(feature = "html")) {
65        return false;
66    }
67
68    if req.path().ends_with(".json") {
69        return false;
70    }
71    web::Header::<header::Accept>::extract(req)
72        .await
73        .map(|accept| &accept.preference().to_string() == "text/html")
74        .unwrap_or(false)
75}