150 lines
3.7 KiB
Rust
150 lines
3.7 KiB
Rust
use askama::Template;
|
|
use brass_db::models::{Event, Function, User};
|
|
use lettre::{
|
|
message::{Mailbox, MultiPart, SinglePart},
|
|
Address, AsyncTransport, Message,
|
|
};
|
|
|
|
use crate::{
|
|
filters,
|
|
mail::Mailer,
|
|
utils::{
|
|
ApplicationError,
|
|
DateTimeFormat::{DayMonthYear, HourMinute, WeekdayDayMonthYear},
|
|
},
|
|
};
|
|
|
|
impl Mailer {
|
|
pub async fn send_assignment_created_mail(
|
|
&self,
|
|
user: &User,
|
|
assigned_function: &Function,
|
|
event: &Event,
|
|
) -> Result<(), ApplicationError> {
|
|
let message = build(
|
|
&self.hostname,
|
|
&user.name,
|
|
&user.email,
|
|
assigned_function,
|
|
event,
|
|
)?;
|
|
self.transport.send(message).await?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "emails/notify_planned.txt")]
|
|
struct NotifyPlannedMailTemplatePlain<'a> {
|
|
name: &'a str,
|
|
function: &'a Function,
|
|
event: &'a Event,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "emails/notify_planned.html")]
|
|
struct NotifyPlannedMailTemplateHtml<'a> {
|
|
name: &'a str,
|
|
function: &'a Function,
|
|
event: &'a Event,
|
|
}
|
|
|
|
fn build(
|
|
hostname: &str,
|
|
name: &str,
|
|
email: &str,
|
|
function: &Function,
|
|
event: &Event,
|
|
) -> Result<Message, ApplicationError> {
|
|
let plain = NotifyPlannedMailTemplatePlain {
|
|
name,
|
|
function,
|
|
event,
|
|
}
|
|
.to_string();
|
|
|
|
let html = NotifyPlannedMailTemplateHtml {
|
|
name,
|
|
function,
|
|
event,
|
|
}
|
|
.to_string();
|
|
|
|
let subject = format!(
|
|
"Brass: Einteilung bei {} am {} als {function}",
|
|
event.name,
|
|
event.start.format(DayMonthYear.into())
|
|
);
|
|
|
|
let sender_mailbox = Mailbox::new(
|
|
Some("noreply".to_string()),
|
|
Address::new("noreply", hostname)?,
|
|
);
|
|
|
|
let message = Message::builder()
|
|
.from(sender_mailbox.clone())
|
|
.reply_to(sender_mailbox)
|
|
.to(Mailbox::new(Some(name.to_string()), email.parse()?))
|
|
.subject(subject)
|
|
.multipart(
|
|
MultiPart::alternative()
|
|
.singlepart(SinglePart::plain(plain))
|
|
.singlepart(SinglePart::html(html)),
|
|
)
|
|
.unwrap();
|
|
|
|
Ok(message)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::utils::test_helper::{assert_mail_snapshot, NaiveDateTimeExt};
|
|
use brass_db::models::{Clothing, Location};
|
|
use chrono::NaiveDateTime;
|
|
use lettre::{transport::stub::StubTransport, Transport};
|
|
|
|
#[test]
|
|
fn build_mail_snapshot() {
|
|
let event = Event {
|
|
id: 1,
|
|
start: NaiveDateTime::from_ymd_and_hms(2025, 06, 01, 18, 30, 0).unwrap(),
|
|
end: NaiveDateTime::from_ymd_and_hms(2025, 06, 02, 4, 0, 0).unwrap(),
|
|
name: "Wave Gotik Treffen".to_string(),
|
|
location_id: 1,
|
|
location: Some(Location {
|
|
id: 1,
|
|
name: "agra Messe Leipzig".to_string(),
|
|
area_id: 1,
|
|
area: None,
|
|
}),
|
|
voluntary_wachhabender: false,
|
|
fuehrungsassistent_required: false,
|
|
amount_of_posten: 3,
|
|
clothing: Clothing {
|
|
id: 1,
|
|
name: "komplette PSA".to_string(),
|
|
},
|
|
canceled: false,
|
|
note: Some("Anfahrt Bereitstellungsraum über xyz...".to_string()),
|
|
};
|
|
|
|
let message = build(
|
|
"brasiwa-leipzig.de",
|
|
"Max Mustermann",
|
|
"max@example.com",
|
|
&Function::Posten,
|
|
&event,
|
|
)
|
|
.unwrap();
|
|
|
|
let sender = StubTransport::new_ok();
|
|
sender.send(&message).unwrap();
|
|
let messages = sender.messages();
|
|
let (_, sent_message) = messages.first().unwrap();
|
|
|
|
assert_mail_snapshot!(sent_message);
|
|
}
|
|
}
|