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
52pub 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}