myc_core/domain/dtos/
email.rs

1use mycelium_base::utils::errors::{invalid_arg_err, MappedErrors};
2use regex::Regex;
3use serde::{Deserialize, Serialize};
4use utoipa::ToSchema;
5
6#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, ToSchema)]
7#[serde(rename_all = "camelCase")]
8pub struct Email {
9    pub username: String,
10    pub domain: String,
11}
12
13impl Email {
14    pub fn from_string(email: String) -> Result<Email, MappedErrors> {
15        let re = Regex::new(
16            r"^([a-zA-Z0-9_\-+]([a-zA-Z0-9_\-+.]*[a-zA-Z0-9_+])?)@([a-zA-Z0-9.-]+\.[a-zA-Z]{1,})"
17        ).unwrap();
18
19        let cap = match re.captures(email.as_str()) {
20            None => {
21                return invalid_arg_err(format!(
22                    "Invalid Email format: {:?}",
23                    email.to_owned()
24                ))
25                .as_error();
26            }
27            Some(res) => res,
28        };
29
30        let username = match cap.get(1) {
31            None => {
32                return invalid_arg_err("Invalid Email username.".to_string())
33                    .as_error();
34            }
35            Some(val) => val.as_str().to_string(),
36        };
37
38        let domain = match cap.get(3) {
39            None => {
40                return invalid_arg_err("Invalid Email domain.".to_string())
41                    .as_error();
42            }
43            Some(val) => val.as_str().to_string(),
44        };
45
46        Ok(Email { username, domain })
47    }
48
49    pub fn email(&self) -> String {
50        format!(
51            "{}@{}",
52            self.username.to_lowercase(),
53            self.domain.to_lowercase()
54        )
55    }
56
57    /// Get redacted email
58    ///
59    /// Return only the first and last letters o the email.username and the
60    /// domain
61    ///
62    pub fn redacted_email(&self) -> String {
63        let binding = self.username.to_lowercase();
64        let username = binding.chars();
65        let domain = self.domain.to_lowercase();
66
67        let username_redacted = format!(
68            "{}{}{}",
69            username.to_owned().next().unwrap(),
70            "*".repeat(3),
71            username.last().unwrap()
72        );
73
74        format!("{}@{}", username_redacted, domain)
75    }
76}
77
78impl ToString for Email {
79    fn to_string(&self) -> String {
80        self.email()
81    }
82}
83
84// ? --------------------------------------------------------------------------
85// ? TESTS
86// ? --------------------------------------------------------------------------
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn test_parse_email_works() {
94        let email_string = "sgelias@outlook.com".to_string();
95
96        let email = Email::from_string(email_string.to_owned()).unwrap();
97
98        assert_eq!(email.username, "sgelias".to_string());
99        assert_eq!(email.domain, "outlook.com".to_string());
100    }
101
102    #[test]
103    fn test_get_email_works() {
104        for (is_valid, email_string) in vec![
105            (true, "mycelium-default-users@biotrop.com.br".to_string()),
106            (true, "myceliumDefaultUsers@biotrop.com.br".to_string()),
107            (true, "mycelium-default-users@biotrop.com".to_string()),
108            (true, "myceliumDefaultUsers@biotrop.com".to_string()),
109            (false, "mycelium-default-users@biotrop".to_string()),
110            (false, "myceliumDefaultUsers@biotrop".to_string()),
111        ] {
112            let email = Email::from_string(email_string.to_owned());
113            println!("{:?}", email);
114
115            if is_valid {
116                assert_eq!(email.unwrap().email(), email_string.to_lowercase());
117            } else {
118                assert!(email.is_err());
119            }
120        }
121    }
122}