eternaltwin_email_formatter 0.16.4

Email formatter for Eternaltwin emails
Documentation
use async_trait::async_trait;
use eternaltwin_core::core::LocaleId;
use eternaltwin_core::email::{EmailBody, EmailContent, EmailFormatter, EmailSubject, VerifyRegistrationEmail};
use eternaltwin_core::forum::MarktwinText;
use eternaltwin_core::types::WeakError;
use marktwin::emitter::emit_html;
use marktwin::grammar::Grammar;
use std::str::FromStr;

pub struct HtmlEmailFormatter;

#[async_trait]
impl EmailFormatter for HtmlEmailFormatter {
  async fn verify_registration_email(
    &self,
    locale: LocaleId,
    data: &VerifyRegistrationEmail,
  ) -> Result<EmailContent, WeakError> {
    let registration_uri = format!(
      "https://eternaltwin.org/register/verified-email?token={}",
      data.token.as_str()
    );
    let content = match locale {
      LocaleId::FrFr => EmailContent {
        subject: "Inscription à Eternaltwin".parse().unwrap(),
        body_text: format!(
          "Bienvenue sur Eternaltwin !\nVeuillez cliquez sur le lien suivant pour valider votre inscription : {}\n",
          registration_uri
        )
        .parse()
        .unwrap(),
        body_html: None,
      },
      _ => EmailContent {
        subject: "Eternaltwin registration".parse().unwrap(),
        body_text: format!(
          "Welcome to Eternaltwin!\nPlease click on the following link to complete your registration: {}\n",
          registration_uri
        )
        .parse()
        .unwrap(),
        body_html: None,
      },
    };
    Ok(content)
  }

  async fn marktwin(&self, subject: EmailSubject, data: &MarktwinText) -> Result<EmailContent, WeakError> {
    let grammar = Grammar::full();
    let body = marktwin::parser::parse(&grammar, data.as_str());
    let body =
      marktwin::ast::concrete::Root::try_from(body.syntax()).map_err(|()| WeakError::new("malformed input"))?;
    let text = EmailBody::from_str(data.as_str()).map_err(WeakError::wrap)?;
    let html = {
      let mut bytes: Vec<u8> = Vec::new();
      emit_html(&mut bytes, &body).map_err(WeakError::wrap)?;
      String::from_utf8(bytes).map_err(WeakError::wrap)?
    };
    Ok(EmailContent {
      subject,
      body_text: text,
      body_html: Some(html),
    })
  }
}

#[cfg(test)]
mod test {
  use crate::html::HtmlEmailFormatter;
  use eternaltwin_core::core::LocaleId;
  use eternaltwin_core::email::{EmailContent, EmailFormatter, VerifyRegistrationEmail};

  #[tokio::test]
  async fn verify_registration_en() {
    let formatter = HtmlEmailFormatter;

    let actual = formatter
      .verify_registration_email(
        LocaleId::EnUs,
        &VerifyRegistrationEmail {
          token: "abcdef".to_string(),
        },
      )
      .await
      .unwrap();

    let expected = EmailContent {
      subject: "Eternaltwin registration".parse().unwrap(),
      body_text: r#"Welcome to Eternaltwin!
Please click on the following link to complete your registration: https://eternaltwin.org/register/verified-email?token=abcdef
"#
      .parse()
      .unwrap(),
      body_html: None,
    };

    assert_eq!(actual, expected);
  }
  #[tokio::test]
  async fn verify_registration_fr() {
    let formatter = HtmlEmailFormatter;

    let actual = formatter
      .verify_registration_email(
        LocaleId::FrFr,
        &VerifyRegistrationEmail {
          token: "abcdef".to_string(),
        },
      )
      .await
      .unwrap();

    let expected = EmailContent {
      subject: "Inscription à Eternaltwin".parse().unwrap(),
      body_text: r#"Bienvenue sur Eternaltwin !
Veuillez cliquez sur le lien suivant pour valider votre inscription : https://eternaltwin.org/register/verified-email?token=abcdef
"#
      .parse()
      .unwrap(),
      body_html: None,
    };

    assert_eq!(actual, expected);
  }
}