myc_core/domain/dtos/
email.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use mycelium_base::utils::errors::{invalid_arg_err, MappedErrors};
use regex::Regex;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct Email {
    pub username: String,
    pub domain: String,
}

impl Email {
    pub fn from_string(email: String) -> Result<Email, MappedErrors> {
        let re = Regex::new(
            r"^([a-zA-Z0-9_\-+]([a-zA-Z0-9_\-+.]*[a-zA-Z0-9_+])?)@([a-zA-Z0-9.-]+\.[a-zA-Z]{1,})"
        ).unwrap();

        let cap = match re.captures(email.as_str()) {
            None => {
                return invalid_arg_err(format!(
                    "Invalid Email format: {:?}",
                    email.to_owned()
                ))
                .as_error();
            }
            Some(res) => res,
        };

        let username = match cap.get(1) {
            None => {
                return invalid_arg_err("Invalid Email username.".to_string())
                    .as_error();
            }
            Some(val) => val.as_str().to_string(),
        };

        let domain = match cap.get(3) {
            None => {
                return invalid_arg_err("Invalid Email domain.".to_string())
                    .as_error();
            }
            Some(val) => val.as_str().to_string(),
        };

        Ok(Email { username, domain })
    }

    pub fn email(&self) -> String {
        format!(
            "{}@{}",
            self.username.to_lowercase(),
            self.domain.to_lowercase()
        )
    }

    /// Get redacted email
    ///
    /// Return only the first and last letters o the email.username and the
    /// domain
    ///
    pub fn redacted_email(&self) -> String {
        let binding = self.username.to_lowercase();
        let username = binding.chars();
        let domain = self.domain.to_lowercase();

        let username_redacted = format!(
            "{}{}{}",
            username.to_owned().next().unwrap(),
            "*".repeat(3),
            username.last().unwrap()
        );

        format!("{}@{}", username_redacted, domain)
    }
}

impl ToString for Email {
    fn to_string(&self) -> String {
        self.email()
    }
}

// ? --------------------------------------------------------------------------
// ? TESTS
// ? --------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_email_works() {
        let email_string = "sgelias@outlook.com".to_string();

        let email = Email::from_string(email_string.to_owned()).unwrap();

        assert_eq!(email.username, "sgelias".to_string());
        assert_eq!(email.domain, "outlook.com".to_string());
    }

    #[test]
    fn test_get_email_works() {
        for (is_valid, email_string) in vec![
            (true, "mycelium-default-users@biotrop.com.br".to_string()),
            (true, "myceliumDefaultUsers@biotrop.com.br".to_string()),
            (true, "mycelium-default-users@biotrop.com".to_string()),
            (true, "myceliumDefaultUsers@biotrop.com".to_string()),
            (false, "mycelium-default-users@biotrop".to_string()),
            (false, "myceliumDefaultUsers@biotrop".to_string()),
        ] {
            let email = Email::from_string(email_string.to_owned());
            println!("{:?}", email);

            if is_valid {
                assert_eq!(email.unwrap().email(), email_string.to_lowercase());
            } else {
                assert!(email.is_err());
            }
        }
    }
}