use maud::Markup; use maud::html; use super::{append_query, mail_shell, url_join}; pub fn mail_verify_code(code: &str, minutes: u64, purpose: &str, link: Option<&str>) -> Markup { let body = html! { h1 style="font-size:24px;font-weight:700;margin:0 0 8px;" { (purpose) } p style="color:#374151;margin:0 0 8px;" { "Enter the following code to continue. It expires in " (minutes) " minutes." } div class="code" { (code) } @if let Some(url) = link { p style="margin:24px 0 0;" { a href=(url) class="btn" { "Verify email" } } p class="muted" style="margin:16px 0 0;" { "If the button doesn't work, copy this link into your browser:" } p style="word-break:break-all;font-size:13px;color:#2563eb;margin:4px 0 0;" { (url) } } p class="muted" style="margin:16px 0 0;" { "If you didn't request this, you can safely ignore this email." } }; mail_shell(purpose, body) } pub fn render(vars: &serde_json::Value) -> Markup { let code = vars.get("code").and_then(|v| v.as_str()).unwrap_or(""); let minutes = vars.get("minutes").and_then(|v| v.as_u64()).unwrap_or(0); let purpose = vars .get("purpose") .and_then(|v| v.as_str()) .unwrap_or("Verification"); let link = build_link(vars); mail_verify_code(code, minutes, purpose, link.as_deref()) } fn build_link(vars: &serde_json::Value) -> Option { let base_url = vars.get("base_url").and_then(|v| v.as_str())?; let email = vars.get("email").and_then(|v| v.as_str())?; let temp_id = vars.get("temp_id").and_then(|v| v.as_str())?; let code = vars.get("code").and_then(|v| v.as_str()).unwrap_or(""); let mut query = vec![("email", email), ("temp_id", temp_id), ("code", code)]; // Optional slug (signup / password_reset / ...); the human-readable // `purpose` var is a heading and must not leak into the URL. let purpose_slug; if let Some(slug) = vars.get("purpose_slug").and_then(|v| v.as_str()) { purpose_slug = slug; query.push(("purpose", purpose_slug)); } Some(append_query(&url_join(base_url, "/auth/verify-email"), &query)) }