|
|
@ -18,9 +18,27 @@ use crate::{ |
|
|
}, |
|
|
}, |
|
|
db::models::{Device, DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId}, |
|
|
db::models::{Device, DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId}, |
|
|
error::Error, |
|
|
error::Error, |
|
|
|
|
|
serde_json, |
|
|
|
|
|
serde_json::json, |
|
|
CONFIG, |
|
|
CONFIG, |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/// Creates a serde_json::Map directly from JSON syntax.
|
|
|
|
|
|
/// Usage: json_map!({ "key1": value1, "key2": value2 })
|
|
|
|
|
|
#[macro_export] |
|
|
|
|
|
macro_rules! json_map { |
|
|
|
|
|
({ $($key:literal: $value:expr),* $(,)? }) => { |
|
|
|
|
|
{ |
|
|
|
|
|
#[allow(unused_mut)] |
|
|
|
|
|
let mut map = $crate::serde_json::Map::new(); |
|
|
|
|
|
$( |
|
|
|
|
|
map.insert($key.to_string(), $crate::serde_json::json!($value)); |
|
|
|
|
|
)* |
|
|
|
|
|
map |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
fn sendmail_transport() -> AsyncSendmailTransport<Tokio1Executor> { |
|
|
fn sendmail_transport() -> AsyncSendmailTransport<Tokio1Executor> { |
|
|
if let Some(command) = CONFIG.sendmail_command() { |
|
|
if let Some(command) = CONFIG.sendmail_command() { |
|
|
AsyncSendmailTransport::new_with_command(command) |
|
|
AsyncSendmailTransport::new_with_command(command) |
|
|
@ -146,6 +164,22 @@ fn get_template(template_name: &str, data: &serde_json::Value) -> Result<(String |
|
|
Ok((subject, body)) |
|
|
Ok((subject, body)) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub async fn send_template_email( |
|
|
|
|
|
address: &str, |
|
|
|
|
|
template_name: &'static str, |
|
|
|
|
|
data: serde_json::Map<String, serde_json::Value>, |
|
|
|
|
|
) -> EmptyResult { |
|
|
|
|
|
let mut obj = data; |
|
|
|
|
|
if !obj.contains_key("url") { |
|
|
|
|
|
obj.insert("url".to_string(), json!(CONFIG.domain())); |
|
|
|
|
|
} |
|
|
|
|
|
obj.insert("img_src".to_string(), json!(CONFIG._smtp_img_src())); |
|
|
|
|
|
|
|
|
|
|
|
let (subject, body_html, body_text) = get_text(template_name, serde_json::Value::Object(obj))?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_password_hint(address: &str, hint: Option<String>) -> EmptyResult { |
|
|
pub async fn send_password_hint(address: &str, hint: Option<String>) -> EmptyResult { |
|
|
let template_name = if hint.is_some() { |
|
|
let template_name = if hint.is_some() { |
|
|
"email/pw_hint_some" |
|
|
"email/pw_hint_some" |
|
|
@ -153,128 +187,85 @@ pub async fn send_password_hint(address: &str, hint: Option<String>) -> EmptyRes |
|
|
"email/pw_hint_none" |
|
|
"email/pw_hint_none" |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, template_name, json_map!({ "hint": hint })).await |
|
|
template_name, |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"hint": hint, |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_delete_account(address: &str, user_id: &UserId) -> EmptyResult { |
|
|
pub async fn send_delete_account(address: &str, user_id: &UserId) -> EmptyResult { |
|
|
let claims = generate_delete_claims(user_id.to_string()); |
|
|
let claims = generate_delete_claims(user_id.to_string()); |
|
|
let delete_token = encode_jwt(&claims); |
|
|
let delete_token = encode_jwt(&claims); |
|
|
|
|
|
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/delete_account", |
|
|
"email/delete_account", |
|
|
json!({ |
|
|
json_map!({ |
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"user_id": user_id, |
|
|
"user_id": user_id, |
|
|
"email": percent_encode(address.as_bytes(), NON_ALPHANUMERIC).to_string(), |
|
|
"email": percent_encode(address.as_bytes(), NON_ALPHANUMERIC).to_string(), |
|
|
"token": delete_token, |
|
|
"token": delete_token, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_verify_email(address: &str, user_id: &UserId) -> EmptyResult { |
|
|
pub async fn send_verify_email(address: &str, user_id: &UserId) -> EmptyResult { |
|
|
let claims = generate_verify_email_claims(user_id); |
|
|
let claims = generate_verify_email_claims(user_id); |
|
|
let verify_email_token = encode_jwt(&claims); |
|
|
let verify_email_token = encode_jwt(&claims); |
|
|
|
|
|
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/verify_email", |
|
|
"email/verify_email", |
|
|
json!({ |
|
|
json_map!({ |
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"user_id": user_id, |
|
|
"user_id": user_id, |
|
|
"email": percent_encode(address.as_bytes(), NON_ALPHANUMERIC).to_string(), |
|
|
"email": percent_encode(address.as_bytes(), NON_ALPHANUMERIC).to_string(), |
|
|
"token": verify_email_token, |
|
|
"token": verify_email_token, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_register_verify_email(email: &str, token: &str) -> EmptyResult { |
|
|
pub async fn send_register_verify_email(email: &str, token: &str) -> EmptyResult { |
|
|
let mut query = url::Url::parse("https://query.builder").unwrap(); |
|
|
let mut query = url::Url::parse("https://query.builder").unwrap(); |
|
|
query.query_pairs_mut().append_pair("email", email).append_pair("token", token); |
|
|
query.query_pairs_mut().append_pair("email", email).append_pair("token", token); |
|
|
let query_string = match query.query() { |
|
|
let Some(query_string) = query.query() else { |
|
|
None => err!("Failed to build verify URL query parameters"), |
|
|
err!("Failed to build verify URL query parameters") |
|
|
Some(query) => query, |
|
|
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
email, |
|
|
"email/register_verify_email", |
|
|
"email/register_verify_email", |
|
|
json!({ |
|
|
json_map!({ |
|
|
// `url.Url` would place the anchor `#` after the query parameters
|
|
|
// `url.Url` would place the anchor `#` after the query parameters
|
|
|
"url": format!("{}/#/finish-signup/?{query_string}", CONFIG.domain()), |
|
|
"url": format!("{}/#/finish-signup/?{query_string}", CONFIG.domain()), |
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"email": email, |
|
|
"email": email, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(email, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_welcome(address: &str) -> EmptyResult { |
|
|
pub async fn send_welcome(address: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, "email/welcome", json_map!({})).await |
|
|
"email/welcome", |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_welcome_must_verify(address: &str, user_id: &UserId) -> EmptyResult { |
|
|
pub async fn send_welcome_must_verify(address: &str, user_id: &UserId) -> EmptyResult { |
|
|
let claims = generate_verify_email_claims(user_id); |
|
|
let claims = generate_verify_email_claims(user_id); |
|
|
let verify_email_token = encode_jwt(&claims); |
|
|
let verify_email_token = encode_jwt(&claims); |
|
|
|
|
|
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/welcome_must_verify", |
|
|
"email/welcome_must_verify", |
|
|
json!({ |
|
|
json_map!({ |
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"user_id": user_id, |
|
|
"user_id": user_id, |
|
|
"token": verify_email_token, |
|
|
"token": verify_email_token, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_2fa_removed_from_org(address: &str, org_name: &str) -> EmptyResult { |
|
|
pub async fn send_2fa_removed_from_org(address: &str, org_name: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, "email/send_2fa_removed_from_org", json_map!({ "org_name": org_name })).await |
|
|
"email/send_2fa_removed_from_org", |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"org_name": org_name, |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_single_org_removed_from_org(address: &str, org_name: &str) -> EmptyResult { |
|
|
pub async fn send_single_org_removed_from_org(address: &str, org_name: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, "email/send_single_org_removed_from_org", json_map!({ "org_name": org_name })).await |
|
|
"email/send_single_org_removed_from_org", |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"org_name": org_name, |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_invite( |
|
|
pub async fn send_invite( |
|
|
@ -314,17 +305,16 @@ pub async fn send_invite( |
|
|
err!("Failed to build invite URL query parameters") |
|
|
err!("Failed to build invite URL query parameters") |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
&user.email, |
|
|
"email/send_org_invite", |
|
|
"email/send_org_invite", |
|
|
json!({ |
|
|
json_map!({ |
|
|
// `url.Url` would place the anchor `#` after the query parameters
|
|
|
// `url.Url` would place the anchor `#` after the query parameters
|
|
|
"url": format!("{}/#/accept-organization/?{query_string}", CONFIG.domain()), |
|
|
"url": format!("{}/#/accept-organization/?{query_string}", CONFIG.domain()), |
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"org_name": org_name, |
|
|
"org_name": org_name, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(&user.email, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_emergency_access_invite( |
|
|
pub async fn send_emergency_access_invite( |
|
|
@ -357,56 +347,28 @@ pub async fn send_emergency_access_invite( |
|
|
err!("Failed to build emergency invite URL query parameters") |
|
|
err!("Failed to build emergency invite URL query parameters") |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/send_emergency_access_invite", |
|
|
"email/send_emergency_access_invite", |
|
|
json!({ |
|
|
json_map!({ |
|
|
// `url.Url` would place the anchor `#` after the query parameters
|
|
|
// `url.Url` would place the anchor `#` after the query parameters
|
|
|
"url": format!("{}/#/accept-emergency/?{query_string}", CONFIG.domain()), |
|
|
"url": format!("{}/#/accept-emergency/?{query_string}", CONFIG.domain()), |
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"grantor_name": grantor_name, |
|
|
"grantor_name": grantor_name, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_emergency_access_invite_accepted(address: &str, grantee_email: &str) -> EmptyResult { |
|
|
pub async fn send_emergency_access_invite_accepted(address: &str, grantee_email: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, "email/emergency_access_invite_accepted", json_map!({ "grantee_email": grantee_email })).await |
|
|
"email/emergency_access_invite_accepted", |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"grantee_email": grantee_email, |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_emergency_access_invite_confirmed(address: &str, grantor_name: &str) -> EmptyResult { |
|
|
pub async fn send_emergency_access_invite_confirmed(address: &str, grantor_name: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, "email/emergency_access_invite_confirmed", json_map!({ "grantor_name": grantor_name })).await |
|
|
"email/emergency_access_invite_confirmed", |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"grantor_name": grantor_name, |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_emergency_access_recovery_approved(address: &str, grantor_name: &str) -> EmptyResult { |
|
|
pub async fn send_emergency_access_recovery_approved(address: &str, grantor_name: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, "email/emergency_access_recovery_approved", json_map!({ "grantor_name": grantor_name })).await |
|
|
"email/emergency_access_recovery_approved", |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"grantor_name": grantor_name, |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_emergency_access_recovery_initiated( |
|
|
pub async fn send_emergency_access_recovery_initiated( |
|
|
@ -415,18 +377,16 @@ pub async fn send_emergency_access_recovery_initiated( |
|
|
atype: &str, |
|
|
atype: &str, |
|
|
wait_time_days: &i32, |
|
|
wait_time_days: &i32, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/emergency_access_recovery_initiated", |
|
|
"email/emergency_access_recovery_initiated", |
|
|
json!({ |
|
|
json_map!({ |
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"grantee_name": grantee_name, |
|
|
"grantee_name": grantee_name, |
|
|
"atype": atype, |
|
|
"atype": atype, |
|
|
"wait_time_days": wait_time_days, |
|
|
"wait_time_days": wait_time_days, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_emergency_access_recovery_reminder( |
|
|
pub async fn send_emergency_access_recovery_reminder( |
|
|
@ -435,91 +395,65 @@ pub async fn send_emergency_access_recovery_reminder( |
|
|
atype: &str, |
|
|
atype: &str, |
|
|
days_left: &str, |
|
|
days_left: &str, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/emergency_access_recovery_reminder", |
|
|
"email/emergency_access_recovery_reminder", |
|
|
json!({ |
|
|
json_map!({ |
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"grantee_name": grantee_name, |
|
|
"grantee_name": grantee_name, |
|
|
"atype": atype, |
|
|
"atype": atype, |
|
|
"days_left": days_left, |
|
|
"days_left": days_left, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_emergency_access_recovery_rejected(address: &str, grantor_name: &str) -> EmptyResult { |
|
|
pub async fn send_emergency_access_recovery_rejected(address: &str, grantor_name: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, "email/emergency_access_recovery_rejected", json_map!({ "grantor_name": grantor_name })).await |
|
|
"email/emergency_access_recovery_rejected", |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"grantor_name": grantor_name, |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_emergency_access_recovery_timed_out(address: &str, grantee_name: &str, atype: &str) -> EmptyResult { |
|
|
pub async fn send_emergency_access_recovery_timed_out(address: &str, grantee_name: &str, atype: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/emergency_access_recovery_timed_out", |
|
|
"email/emergency_access_recovery_timed_out", |
|
|
json!({ |
|
|
json_map!({ |
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"grantee_name": grantee_name, |
|
|
"grantee_name": grantee_name, |
|
|
"atype": atype, |
|
|
"atype": atype, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_invite_accepted(new_user_email: &str, address: &str, org_name: &str) -> EmptyResult { |
|
|
pub async fn send_invite_accepted(new_user_email: &str, address: &str, org_name: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/invite_accepted", |
|
|
"email/invite_accepted", |
|
|
json!({ |
|
|
json_map!({ |
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"email": new_user_email, |
|
|
"email": new_user_email, |
|
|
"org_name": org_name, |
|
|
"org_name": org_name, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_invite_confirmed(address: &str, org_name: &str) -> EmptyResult { |
|
|
pub async fn send_invite_confirmed(address: &str, org_name: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, "email/invite_confirmed", json_map!({ "org_name": org_name })).await |
|
|
"email/invite_confirmed", |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"org_name": org_name, |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_new_device_logged_in(address: &str, ip: &str, dt: &NaiveDateTime, device: &Device) -> EmptyResult { |
|
|
pub async fn send_new_device_logged_in(address: &str, ip: &str, dt: &NaiveDateTime, device: &Device) -> EmptyResult { |
|
|
use crate::util::upcase_first; |
|
|
use crate::util::{format_naive_datetime_local, upcase_first}; |
|
|
|
|
|
|
|
|
let fmt = "%A, %B %_d, %Y at %r %Z"; |
|
|
let fmt = "%A, %B %_d, %Y at %r %Z"; |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/new_device_logged_in", |
|
|
"email/new_device_logged_in", |
|
|
json!({ |
|
|
json_map!({ |
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"ip": ip, |
|
|
"ip": ip, |
|
|
"device_name": upcase_first(&device.name), |
|
|
"device_name": upcase_first(&device.name), |
|
|
"device_type": DeviceType::from_i32(device.atype).to_string(), |
|
|
"device_type": DeviceType::from_i32(device.atype).to_string(), |
|
|
"datetime": crate::util::format_naive_datetime_local(dt, fmt), |
|
|
"datetime": format_naive_datetime_local(dt, fmt), |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_incomplete_2fa_login( |
|
|
pub async fn send_incomplete_2fa_login( |
|
|
@ -529,127 +463,78 @@ pub async fn send_incomplete_2fa_login( |
|
|
device_name: &str, |
|
|
device_name: &str, |
|
|
device_type: &str, |
|
|
device_type: &str, |
|
|
) -> EmptyResult { |
|
|
) -> EmptyResult { |
|
|
use crate::util::upcase_first; |
|
|
use crate::util::{format_naive_datetime_local, upcase_first}; |
|
|
|
|
|
|
|
|
let fmt = "%A, %B %_d, %Y at %r %Z"; |
|
|
let fmt = "%A, %B %_d, %Y at %r %Z"; |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/incomplete_2fa_login", |
|
|
"email/incomplete_2fa_login", |
|
|
json!({ |
|
|
json_map!({ |
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"ip": ip, |
|
|
"ip": ip, |
|
|
"device_name": upcase_first(device_name), |
|
|
"device_name": upcase_first(device_name), |
|
|
"device_type": device_type, |
|
|
"device_type": device_type, |
|
|
"datetime": crate::util::format_naive_datetime_local(dt, fmt), |
|
|
"datetime": format_naive_datetime_local(dt, fmt), |
|
|
"time_limit": CONFIG.incomplete_2fa_time_limit(), |
|
|
"time_limit": CONFIG.incomplete_2fa_time_limit(), |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_token(address: &str, token: &str) -> EmptyResult { |
|
|
pub async fn send_token(address: &str, token: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, "email/twofactor_email", json_map!({ "token": token })).await |
|
|
"email/twofactor_email", |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"token": token, |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_change_email(address: &str, token: &str) -> EmptyResult { |
|
|
pub async fn send_change_email(address: &str, token: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, "email/change_email", json_map!({ "token": token })).await |
|
|
"email/change_email", |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"token": token, |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_change_email_existing(address: &str, acting_address: &str) -> EmptyResult { |
|
|
pub async fn send_change_email_existing(address: &str, acting_address: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/change_email_existing", |
|
|
"email/change_email_existing", |
|
|
json!({ |
|
|
json_map!({ |
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"existing_address": address, |
|
|
"existing_address": address, |
|
|
"acting_address": acting_address, |
|
|
"acting_address": acting_address, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_change_email_invited(address: &str, acting_address: &str) -> EmptyResult { |
|
|
pub async fn send_change_email_invited(address: &str, acting_address: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/change_email_invited", |
|
|
"email/change_email_invited", |
|
|
json!({ |
|
|
json_map!({ |
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"existing_address": address, |
|
|
"existing_address": address, |
|
|
"acting_address": acting_address, |
|
|
"acting_address": acting_address, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
|
|
|
.await |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_sso_change_email(address: &str) -> EmptyResult { |
|
|
pub async fn send_sso_change_email(address: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
let url = format!("{}/#/settings/account", CONFIG.domain()); |
|
|
"email/sso_change_email", |
|
|
send_template_email(address, "email/sso_change_email", json_map!({ "url": url })).await |
|
|
json!({ |
|
|
|
|
|
"url": format!("{}/#/settings/account", CONFIG.domain()), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_test(address: &str) -> EmptyResult { |
|
|
pub async fn send_test(address: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, "email/smtp_test", json_map!({})).await |
|
|
"email/smtp_test", |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_admin_reset_password(address: &str, user_name: &str, org_name: &str) -> EmptyResult { |
|
|
pub async fn send_admin_reset_password(address: &str, user_name: &str, org_name: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email( |
|
|
|
|
|
address, |
|
|
"email/admin_reset_password", |
|
|
"email/admin_reset_password", |
|
|
json!({ |
|
|
json_map!({ |
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"user_name": user_name, |
|
|
"user_name": user_name, |
|
|
"org_name": org_name, |
|
|
"org_name": org_name, |
|
|
}), |
|
|
}), |
|
|
)?; |
|
|
) |
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
.await |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub async fn send_protected_action_token(address: &str, token: &str) -> EmptyResult { |
|
|
pub async fn send_protected_action_token(address: &str, token: &str) -> EmptyResult { |
|
|
let (subject, body_html, body_text) = get_text( |
|
|
send_template_email(address, "email/protected_action", json_map!({ "token": token })).await |
|
|
"email/protected_action", |
|
|
|
|
|
json!({ |
|
|
|
|
|
"url": CONFIG.domain(), |
|
|
|
|
|
"img_src": CONFIG._smtp_img_src(), |
|
|
|
|
|
"token": token, |
|
|
|
|
|
}), |
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async fn send_with_selected_transport(email: Message) -> EmptyResult { |
|
|
async fn send_with_selected_transport(email: Message) -> EmptyResult { |
|
|
|