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