myc_core/domain/dtos/
email.rs1use base64::{engine::general_purpose, Engine};
2use mycelium_base::utils::errors::{invalid_arg_err, MappedErrors};
3use regex::Regex;
4use serde::{Deserialize, Serialize};
5use utoipa::ToSchema;
6
7#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, ToSchema)]
8#[serde(rename_all = "camelCase")]
9pub struct Email {
10 pub username: String,
11 pub domain: String,
12}
13
14impl Email {
15 pub fn from_string(email: String) -> Result<Email, MappedErrors> {
16 let re = Regex::new(
17 r"^([a-zA-Z0-9_\-+]([a-zA-Z0-9_\-+.]*[a-zA-Z0-9_+])?)@([a-zA-Z0-9.-]+\.[a-zA-Z]{1,})"
18 ).unwrap();
19
20 let cap = match re.captures(email.as_str()) {
21 None => {
22 return invalid_arg_err(format!(
23 "Invalid Email format: {:?}",
24 email.to_owned()
25 ))
26 .as_error();
27 }
28 Some(res) => res,
29 };
30
31 let username = match cap.get(1) {
32 None => {
33 return invalid_arg_err("Invalid Email username.".to_string())
34 .as_error();
35 }
36 Some(val) => val.as_str().to_string(),
37 };
38
39 let domain = match cap.get(3) {
40 None => {
41 return invalid_arg_err("Invalid Email domain.".to_string())
42 .as_error();
43 }
44 Some(val) => val.as_str().to_string(),
45 };
46
47 Ok(Email { username, domain })
48 }
49
50 pub fn email(&self) -> String {
51 format!(
52 "{}@{}",
53 self.username.to_lowercase(),
54 self.domain.to_lowercase()
55 )
56 }
57
58 pub fn redacted_email(&self) -> String {
64 Self::redact_email(&self.email())
65 }
66
67 pub fn encoded_email(&self) -> String {
72 general_purpose::STANDARD.encode(self.email().as_bytes())
73 }
74
75 pub fn redact_email(email: &str) -> String {
80 let email = match Email::from_string(email.to_string()) {
81 Ok(email) => email,
82 Err(e) => {
83 tracing::warn!("Invalid Email format: {:?}", e);
84 return email.to_owned();
85 }
86 };
87
88 let binding = email.username.to_lowercase();
89 let username = binding.chars();
90 let domain = email.domain.to_lowercase();
91
92 let username_redacted = format!(
93 "{}{}{}",
94 username.to_owned().next().unwrap(),
95 "*".repeat(3),
96 username.last().unwrap()
97 );
98
99 format!("{}@{}", username_redacted, domain)
100 }
101}
102
103impl ToString for Email {
104 fn to_string(&self) -> String {
105 self.email()
106 }
107}
108
109#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn test_parse_email_works() {
119 let email_string = "sgelias@outlook.com".to_string();
120
121 let email = Email::from_string(email_string.to_owned()).unwrap();
122
123 assert_eq!(email.username, "sgelias".to_string());
124 assert_eq!(email.domain, "outlook.com".to_string());
125 }
126
127 #[test]
128 fn test_get_email_works() {
129 for (is_valid, email_string) in vec![
130 (true, "mycelium-default-users@biotrop.com.br".to_string()),
131 (true, "myceliumDefaultUsers@biotrop.com.br".to_string()),
132 (true, "mycelium-default-users@biotrop.com".to_string()),
133 (true, "myceliumDefaultUsers@biotrop.com".to_string()),
134 (false, "mycelium-default-users@biotrop".to_string()),
135 (false, "myceliumDefaultUsers@biotrop".to_string()),
136 ] {
137 let email = Email::from_string(email_string.to_owned());
138
139 if is_valid {
140 assert_eq!(email.unwrap().email(), email_string.to_lowercase());
141 } else {
142 assert!(email.is_err());
143 }
144 }
145 }
146}