allowthem_server/
browser_templates.rs1use std::sync::Arc;
2
3use axum::response::Html;
4use minijinja::Environment;
5
6use crate::browser_error::BrowserError;
7
8const BASE_HTML: &str = include_str!("templates/base.html");
9const LOGIN_HTML: &str = include_str!("templates/login.html");
10const REGISTER_HTML: &str = include_str!("templates/register.html");
11const SETTINGS_HTML: &str = include_str!("templates/settings.html");
12const CONSENT_HTML: &str = include_str!("templates/consent.html");
13const FORGOT_PASSWORD_HTML: &str = include_str!("templates/forgot_password.html");
14const RESET_PASSWORD_HTML: &str = include_str!("templates/reset_password.html");
15const MFA_SETUP_HTML: &str = include_str!("templates/mfa_setup.html");
16const MFA_RECOVERY_HTML: &str = include_str!("templates/mfa_recovery.html");
17const MFA_CHALLENGE_HTML: &str = include_str!("templates/mfa_challenge.html");
18const MODELINE_PARTIAL: &str = include_str!("templates/_partials/_modeline.html");
19const FLASH_PARTIAL: &str = include_str!("templates/_partials/_flash.html");
20const SPLASH_PARTIAL: &str = include_str!("templates/_partials/_splash.html");
21const AUTH_SHELL_PARTIAL: &str = include_str!("templates/_partials/_auth_shell.html");
22const APP_SHELL_PARTIAL: &str = include_str!("templates/_partials/_app_shell.html");
23const SIDEBAR_NAV_PARTIAL: &str = include_str!("templates/_partials/_sidebar_nav.html");
24const AUTH_MACROS_PARTIAL: &str = include_str!("templates/_partials/_auth_macros.html");
25const AUTH_OOB_HEAD_PARTIAL: &str = include_str!("templates/_partials/_auth_oob_head.html");
26const AUTH_MAIN_LOGIN_PARTIAL: &str = include_str!("templates/_partials/_auth_main_login.html");
27const AUTH_MAIN_REGISTER_PARTIAL: &str =
28 include_str!("templates/_partials/_auth_main_register.html");
29const AUTH_MAIN_FORGOT_PW_PARTIAL: &str =
30 include_str!("templates/_partials/_auth_main_forgot_password.html");
31const AUTH_MAIN_RESET_PW_PARTIAL: &str =
32 include_str!("templates/_partials/_auth_main_reset_password.html");
33const AUTH_MAIN_MFA_CHALLENGE_PARTIAL: &str =
34 include_str!("templates/_partials/_auth_main_mfa_challenge.html");
35const AUTH_MAIN_MFA_SETUP_PARTIAL: &str =
36 include_str!("templates/_partials/_auth_main_mfa_setup.html");
37const AUTH_MAIN_MFA_RECOVERY_PARTIAL: &str =
38 include_str!("templates/_partials/_auth_main_mfa_recovery.html");
39const AUTH_MAIN_CONSENT_PARTIAL: &str = include_str!("templates/_partials/_auth_main_consent.html");
40const ERROR_HTML: &str = include_str!("templates/error.html");
41
42pub fn add_default_browser_templates(env: &mut Environment<'static>) {
95 env.add_filter("datefmt", |value: String| -> String {
96 if value.len() >= 16 {
97 let date = &value[..10];
98 let time = &value[11..16];
99 format!("{date} {time} UTC")
100 } else {
101 value
102 }
103 });
104
105 env.add_template_owned("base.html", BASE_HTML)
106 .expect("base.html");
107 env.add_template_owned("login.html", LOGIN_HTML)
108 .expect("login.html");
109 env.add_template_owned("register.html", REGISTER_HTML)
110 .expect("register.html");
111 env.add_template_owned("settings.html", SETTINGS_HTML)
112 .expect("settings.html");
113 env.add_template_owned("consent.html", CONSENT_HTML)
114 .expect("consent.html");
115 env.add_template_owned("forgot_password.html", FORGOT_PASSWORD_HTML)
116 .expect("forgot_password.html");
117 env.add_template_owned("reset_password.html", RESET_PASSWORD_HTML)
118 .expect("reset_password.html");
119 env.add_template_owned("mfa_setup.html", MFA_SETUP_HTML)
120 .expect("mfa_setup.html");
121 env.add_template_owned("mfa_recovery.html", MFA_RECOVERY_HTML)
122 .expect("mfa_recovery.html");
123 env.add_template_owned("mfa_challenge.html", MFA_CHALLENGE_HTML)
124 .expect("mfa_challenge.html");
125 env.add_template_owned("_partials/_modeline.html", MODELINE_PARTIAL)
126 .expect("_partials/_modeline.html");
127 env.add_template_owned("_partials/_flash.html", FLASH_PARTIAL)
128 .expect("_partials/_flash.html");
129 env.add_template_owned("_partials/_splash.html", SPLASH_PARTIAL)
130 .expect("_partials/_splash.html");
131 env.add_template_owned("_partials/_auth_shell.html", AUTH_SHELL_PARTIAL)
132 .expect("_partials/_auth_shell.html");
133 env.add_template_owned("_partials/_app_shell.html", APP_SHELL_PARTIAL)
134 .expect("_partials/_app_shell.html");
135 env.add_template_owned("_partials/_sidebar_nav.html", SIDEBAR_NAV_PARTIAL)
136 .expect("_partials/_sidebar_nav.html");
137 env.add_template_owned("_partials/_auth_macros.html", AUTH_MACROS_PARTIAL)
138 .expect("_partials/_auth_macros.html");
139 env.add_template_owned("_partials/_auth_oob_head.html", AUTH_OOB_HEAD_PARTIAL)
140 .expect("_partials/_auth_oob_head.html");
141 env.add_template_owned("_partials/_auth_main_login.html", AUTH_MAIN_LOGIN_PARTIAL)
142 .expect("_partials/_auth_main_login.html");
143 env.add_template_owned(
144 "_partials/_auth_main_register.html",
145 AUTH_MAIN_REGISTER_PARTIAL,
146 )
147 .expect("_partials/_auth_main_register.html");
148 env.add_template_owned(
149 "_partials/_auth_main_forgot_password.html",
150 AUTH_MAIN_FORGOT_PW_PARTIAL,
151 )
152 .expect("_partials/_auth_main_forgot_password.html");
153 env.add_template_owned(
154 "_partials/_auth_main_reset_password.html",
155 AUTH_MAIN_RESET_PW_PARTIAL,
156 )
157 .expect("_partials/_auth_main_reset_password.html");
158 env.add_template_owned(
159 "_partials/_auth_main_mfa_challenge.html",
160 AUTH_MAIN_MFA_CHALLENGE_PARTIAL,
161 )
162 .expect("_partials/_auth_main_mfa_challenge.html");
163 env.add_template_owned(
164 "_partials/_auth_main_mfa_setup.html",
165 AUTH_MAIN_MFA_SETUP_PARTIAL,
166 )
167 .expect("_partials/_auth_main_mfa_setup.html");
168 env.add_template_owned(
169 "_partials/_auth_main_mfa_recovery.html",
170 AUTH_MAIN_MFA_RECOVERY_PARTIAL,
171 )
172 .expect("_partials/_auth_main_mfa_recovery.html");
173 env.add_template_owned(
174 "_partials/_auth_main_consent.html",
175 AUTH_MAIN_CONSENT_PARTIAL,
176 )
177 .expect("_partials/_auth_main_consent.html");
178 env.add_template_owned("error.html", ERROR_HTML)
179 .expect("error.html");
180}
181
182pub fn build_default_browser_env() -> Arc<Environment<'static>> {
183 let mut env = Environment::new();
184 add_default_browser_templates(&mut env);
185 Arc::new(env)
186}
187
188pub fn render(
189 env: &Environment<'_>,
190 template_name: &str,
191 ctx: minijinja::value::Value,
192) -> Result<Html<String>, BrowserError> {
193 let tmpl = env.get_template(template_name)?;
194 let rendered = tmpl.render(ctx)?;
195 Ok(Html(rendered))
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201
202 #[test]
203 fn default_env_loads_all_browser_templates() {
204 let env = build_default_browser_env();
205 for name in [
206 "base.html",
207 "login.html",
208 "register.html",
209 "settings.html",
210 "consent.html",
211 "forgot_password.html",
212 "reset_password.html",
213 "mfa_setup.html",
214 "mfa_recovery.html",
215 "mfa_challenge.html",
216 "_partials/_modeline.html",
217 "_partials/_flash.html",
218 "_partials/_splash.html",
219 "_partials/_auth_shell.html",
220 "_partials/_app_shell.html",
221 "_partials/_sidebar_nav.html",
222 "_partials/_auth_macros.html",
223 "_partials/_auth_oob_head.html",
224 "_partials/_auth_main_login.html",
225 "_partials/_auth_main_register.html",
226 "_partials/_auth_main_forgot_password.html",
227 "_partials/_auth_main_reset_password.html",
228 "_partials/_auth_main_mfa_challenge.html",
229 "_partials/_auth_main_mfa_setup.html",
230 "_partials/_auth_main_mfa_recovery.html",
231 "_partials/_auth_main_consent.html",
232 "error.html",
233 ] {
234 assert!(
235 env.get_template(name).is_ok(),
236 "template {name} should be loadable"
237 );
238 }
239 }
240
241 #[test]
242 fn render_produces_html() {
243 let env = build_default_browser_env();
244 let result = render(
245 &env,
246 "login.html",
247 minijinja::context! {
248 csrf_token => "test",
249 is_production => false,
250 },
251 );
252 assert!(result.is_ok());
253 }
254}