Skip to main content

trillium_tera/
tera_conn_ext.rs

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