use chrono::prelude::*;
use serde::ser::Serialize;
use serde_json::{to_value, Value};
use super::models::*;
#[derive(Debug, Serialize, Default)]
pub struct Message {
pub options: Options,
pub description: Option<String>,
pub campaign_id: Option<String>,
pub metadata: Option<Value>,
pub substitution_data: Option<Value>,
pub recipients: Recipients,
pub(crate) content: Content,
}
impl Message {
pub fn new<T: Into<EmailAddress>>(sender_address: T) -> Self {
let mut message = Message::default();
message.content.from = sender_address.into();
message
}
pub fn with_options(
sender_address: EmailAddress,
options: Options,
) -> Self {
let mut message = Message::default();
message.options = options;
message.content.from = sender_address;
message
}
pub fn recipient_list(&mut self, list_name: &str) -> &mut Self {
self.recipients = Recipients::ListName(list_name.into());
self
}
pub fn add_recipient<T: Into<Recipient>>(
&mut self,
recipient: T,
) -> &mut Self {
let recipient: Recipient = recipient.into();
match self.recipients {
Recipients::ListName(_) => {
self.recipients = Recipients::LocalList(vec![recipient])
}
Recipients::LocalList(ref mut list) => {
list.retain(|ref rec| {
rec.address.email.as_str()
!= recipient.address.email.as_str()
});
list.push(recipient);
}
}
self
}
pub fn subject<T: Into<String>>(&mut self, subject: T) -> &mut Self {
self.content.subject = subject.into();
self
}
pub fn options<T: Into<Options>>(&mut self, options: T) -> &mut Self {
self.options = options.into();
self
}
pub fn html<T: Into<String>>(&mut self, html: T) -> &mut Self {
self.content.html = Some(html.into());
self
}
pub fn text<T: Into<String>>(&mut self, text: T) -> &mut Self {
self.content.text = Some(text.into());
self
}
pub fn campaign_id<T: Into<String>>(
&mut self,
campaign_id: T,
) -> &mut Self {
self.campaign_id = Some(campaign_id.into());
self
}
pub fn template_id<T: Into<String>>(
&mut self,
template_id: T,
) -> &mut Self {
self.content.template_id = Some(template_id.into());
self
}
pub fn substitution_data<T: Serialize>(&mut self, data: T) -> &mut Self {
self.substitution_data =
Some(to_value(data).expect("Data cannot be searized"));
self
}
pub fn metadata<T: Serialize>(&mut self, data: T) -> &mut Self {
self.metadata = Some(to_value(data).expect("Data cannot be searized"));
self
}
pub fn add_attachment<T: Into<Attachment>>(
&mut self,
attachment: T,
) -> &mut Self {
self.content.attachments.push(attachment.into());
self
}
}
#[derive(Debug, Serialize, PartialEq, Default)]
pub struct Options {
pub open_tracking: bool,
pub click_tracking: bool,
pub transactional: bool,
pub sandbox: bool,
pub inline_css: bool,
pub start_time: Option<DateTime<Utc>>,
}
#[derive(Debug, Serialize, Default)]
pub struct Attachment {
name: String,
#[serde(rename = "type")]
file_type: String,
data: String,
}
impl<'a> From<&'a Attachment> for Attachment {
fn from(attachment: &'a Attachment) -> Self {
Attachment {
name: attachment.name.to_owned(),
file_type: attachment.file_type.to_owned(),
data: attachment.data.to_owned(),
}
}
}
impl Attachment {
pub fn from_data<T: Into<String>>(name: T, file_type: T, data: T) -> Self {
Attachment {
name: name.into(),
file_type: file_type.into(),
data: data.into(),
}
}
}
#[derive(Debug, Serialize, Default)]
pub(crate) struct Content {
pub from: EmailAddress,
pub subject: String,
pub tags: Option<Vec<String>>,
pub text: Option<String>,
pub html: Option<String>,
pub template_id: Option<String>,
pub attachments: Vec<Attachment>,
}
#[cfg(test)]
mod test {
use super::*;
use serde_json::to_value;
#[derive(Debug, Serialize)]
struct Substitute {
pub any_field: String,
}
#[test]
fn create_message() {
let mut email: Message =
Message::new(EmailAddress::new("test@test.com", "name"));
email.add_recipient("tech@hgill.io");
email.recipient_list("my_list");
let json_value: Value = to_value(&email).unwrap();
assert_eq!(
"test@test.com",
json_value["content"]["from"]["email"].as_str().unwrap()
);
assert_eq!(
"name",
json_value["content"]["from"]["name"].as_str().unwrap()
);
assert_eq!(
"test@test.com",
json_value["content"]["from"]["email"].as_str().unwrap()
);
assert!(!json_value["options"]["sandbox"].as_bool().unwrap());
assert!(!json_value["options"]["click_tracking"].as_bool().unwrap());
assert!(!json_value["options"]["open_tracking"].as_bool().unwrap());
assert!(!json_value["options"]["transactional"].as_bool().unwrap());
}
#[test]
fn create_message_with_options() {
let email: Message = Message::with_options(
"test@test.com".into(),
Options {
open_tracking: true,
click_tracking: true,
transactional: true,
sandbox: true,
inline_css: false,
start_time: Some(Utc.ymd(2014, 7, 8).and_hms(9, 10, 11)),
},
);
let json_value = to_value(email).unwrap();
assert_eq!(
"test@test.com",
json_value["content"]["from"]["email"].as_str().unwrap()
);
assert_eq!("test@test.com", json_value["content"]["from"]["email"]);
assert!(json_value["options"]["sandbox"].as_bool().unwrap());
assert!(json_value["options"]["click_tracking"].as_bool().unwrap());
assert!(json_value["options"]["open_tracking"].as_bool().unwrap());
assert!(json_value["options"]["transactional"].as_bool().unwrap());
assert!(!json_value["options"]["inline_css"].as_bool().unwrap());
assert_eq!("2014-07-08T09:10:11Z", json_value["options"]["start_time"]);
}
#[test]
fn create_message_with_substitute_data() {
let mut email: Message = Message::default();
let data = Substitute {
any_field: "any_value".into(),
};
email.add_recipient(Recipient {
address: "name@domain.com".into(),
substitution_data: Some(to_value(data).unwrap()),
});
let json_value = to_value(email).unwrap();
assert_eq!(
json_value["recipients"][0]["address"]["email"],
"name@domain.com"
);
}
#[test]
fn test_message_recipient_duplication() {
let mut message = Message::default();
let recipient: Recipient = "email@domain.com".into();
let recipient1: Recipient = "email@domain.com".into();
message.add_recipient(recipient);
match message.recipients {
Recipients::LocalList(ref list) => {
assert_eq!(list.get(0), Some(&recipient1));
}
_ => assert!(false),
};
message.add_recipient(Recipient {
address: "email@domain.com".into(),
substitution_data: Some(
to_value(Substitute {
any_field: "any_value".into(),
})
.unwrap(),
),
});
match message.recipients {
Recipients::LocalList(ref list) => {
assert_eq!(list.len(), 1);
}
_ => assert!(false),
};
let json_value = to_value(&message).unwrap();
assert_eq!(
json_value["recipients"][0]["substitution_data"]["any_field"],
"any_value"
);
message.recipient_list("mylist");
let json_value = to_value(&message).unwrap();
assert_eq!(json_value["recipients"]["list_id"], "mylist");
}
#[test]
fn create_options() {
let options = Options::default();
assert_eq!(false, options.click_tracking);
assert_eq!(false, options.open_tracking);
assert_eq!(false, options.sandbox);
assert_eq!(false, options.transactional);
}
}