Skip to main content

trillium_tera/
tera_conn_ext.rs

1use crate::TeraHandler;
2use serde::Serialize;
3use tera::{Context, Tera};
4use trillium::{Conn, KnownHeaderName};
5
6/**
7Extends trillium::Conn with tera template-rendering functionality.
8*/
9pub trait TeraConnExt {
10    /// Adds a key-value pair to the assigns [`Context`], where the key is
11    /// a &str and the value is any [`Serialize`] type.
12    fn assign(self, key: &str, value: impl Serialize) -> Self;
13
14    /// Uses the accumulated assigns context to render the template by
15    /// registered name to the conn body and return the conn. Halts
16    /// and sets a 200 status on successful render. Must be run
17    /// downsequence of the [`TeraHandler`], and will panic if the
18    /// TeraHandler has not already been called.
19    fn render(self, template: &str) -> Self;
20
21    /// Retrieves a reference to the [`Tera`] instance. Must be called
22    /// downsequence of the [`TeraHandler`], and will panic if the
23    /// TeraHandler has not already been called.
24    fn tera(&self) -> &Tera;
25
26    /// retrieves a reference to the tera assigns context. must be run
27    /// downsequence of the [`TeraHandler`], and will panic if the
28    /// TeraHandler has not already been called.
29    fn context_mut(&mut self) -> &mut Context;
30
31    /// Retrieves a reference to the tera assigns context. Must be run
32    /// downsequence of the [`TeraHandler`], and will panic if the
33    /// TeraHandler has not already been called.
34    fn context(&self) -> &Context;
35}
36
37impl TeraConnExt for Conn {
38    fn assign(mut self, key: &str, value: impl Serialize) -> Self {
39        self.context_mut().insert(key, &value);
40        self
41    }
42
43    fn tera(&self) -> &Tera {
44        self.state::<TeraHandler>()
45            .expect("tera must be run after the tera handler")
46            .tera()
47    }
48
49    fn context_mut(&mut self) -> &mut Context {
50        self.state_mut()
51            .expect("context_mut must be run after the tera handler")
52    }
53
54    fn context(&self) -> &Context {
55        self.state()
56            .expect("context must be run after the tera handler")
57    }
58
59    fn render(mut self, template_name: &str) -> Self {
60        let context = self.context();
61        match self.tera().render(template_name, context) {
62            Ok(string) => {
63                if let Some(mime) = mime_guess::from_path(template_name).first_raw() {
64                    self.response_headers_mut()
65                        .try_insert(KnownHeaderName::ContentType, mime);
66                }
67
68                self.ok(string)
69            }
70
71            Err(e) => {
72                log::error!("{:?}", &e);
73                self.with_status(500).with_body(e.to_string())
74            }
75        }
76    }
77}