use cratefield_core::{Rendered, Template, TemplateError, TemplateRegistry};
use cratefield_mail_templates::{self as mt, Dir, MailTheme};
use serde::{Deserialize, Serialize};
use serde_json::Value;
pub const TEMPLATE_EMAIL: &str = "notifications/email";
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmailMail {
pub venture: String,
pub subject: String,
pub title: String,
pub body: String,
pub url: Option<String>,
pub lang: String,
pub dir: String,
pub unsubscribe: String,
pub unsubscribe_all: String,
}
struct EmailTemplate {
theme: Option<MailTheme>,
}
impl Template for EmailTemplate {
fn render(&self, data: &Value, _locale: &str) -> Result<Rendered, TemplateError> {
let theme = mt::theme_for_template(self.theme.as_ref(), data);
let data: EmailMail =
serde_json::from_value(data.clone()).map_err(|_| TemplateError::RenderFailed {
id: TEMPLATE_EMAIL.to_owned(),
reason: "the mail data is not the shape this template takes".to_owned(),
})?;
let mut message = mt::Message::new(&data.subject, &data.title)
.preheader(&data.body)
.lang(&data.lang)
.dir(if data.dir == "rtl" {
Dir::Rtl
} else {
Dir::Ltr
})
.paragraph(&data.body);
if let Some(url) = &data.url {
message = message.button("Open", url);
}
Ok(message
.footer_link("Stop receiving these", &data.unsubscribe)
.footer_link("stop all notification email", &data.unsubscribe_all)
.render(&theme)
.into())
}
}
#[must_use]
pub fn default_templates() -> Vec<(String, Box<dyn Template>)> {
templates(None)
}
#[must_use]
pub fn themed_templates(theme: &MailTheme) -> Vec<(String, Box<dyn Template>)> {
templates(Some(theme))
}
fn templates(theme: Option<&MailTheme>) -> Vec<(String, Box<dyn Template>)> {
vec![(
TEMPLATE_EMAIL.to_owned(),
Box::new(EmailTemplate {
theme: theme.cloned(),
}) as Box<dyn Template>,
)]
}
pub(crate) fn render(
registry: &TemplateRegistry,
data: &Value,
locale: &str,
) -> Result<Rendered, TemplateError> {
match registry.render(TEMPLATE_EMAIL, data, locale) {
Err(TemplateError::UnknownTemplate { .. }) => {
EmailTemplate { theme: None }.render(data, locale)
}
other => other,
}
}