-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: build issue to specify chrono for wasm (#208)
- Loading branch information
1 parent
dcf3fac
commit 6f68acd
Showing
13 changed files
with
337 additions
and
17 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "types" | ||
version = "0.1.0" | ||
edition = "2021" | ||
authors = ["Esteban Borai <[email protected]>"] | ||
|
||
[lib] | ||
name = "townhall_types" | ||
path = "src/lib.rs" | ||
|
||
[dependencies] | ||
chrono = { workspace = true, features = ["serde", "wasmbind"] } | ||
pxid = { workspace = true } | ||
regex = { workspace = true } | ||
serde = { workspace = true, features = ["derive"] } | ||
serde_json = { workspace = true } | ||
thiserror = { workspace = true } | ||
tracing = { workspace = true } | ||
url = { workspace = true } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod user; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
use std::borrow::Cow; | ||
use std::fmt::{self, Display}; | ||
use std::str::FromStr; | ||
|
||
use regex::Regex; | ||
use serde::{Deserialize, Serialize}; | ||
use thiserror::Error; | ||
|
||
/// A regexp that represents a valid email identifier | ||
/// | ||
/// Refer: https://i.stack.imgur.com/YI6KR.png | ||
pub const EMAIL_IDENTIFIER_REGEXP: &str = r#"(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*)"#; | ||
|
||
/// A regexp that represents a valid email domain | ||
/// | ||
/// Refer: https://i.stack.imgur.com/YI6KR.png | ||
pub const EMAIL_DOMAIN_REGEXP: &str = r"(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])"; | ||
|
||
#[derive(Clone, Debug, Error, PartialEq, Eq)] | ||
pub enum EmailError { | ||
#[error("The provided email domain \"{0}\" on email \"{1}\" is not valid")] | ||
InvalidDomain(String, String), | ||
#[error("The provided email identifier \"{0}\" on email \"{1}\" is not valid")] | ||
InvalidIdentifier(String, String), | ||
#[error("The provided email is not a valid email: {0}")] | ||
ParseError(String), | ||
} | ||
|
||
/// Email value | ||
/// | ||
/// # Validation | ||
/// | ||
/// Email validation is achieved using Regular Expressions and certain rules. | ||
/// Refer: https://stackoverflow.com/questions/201323/how-can-i-validate-an-email-address-using-a-regular-expression | ||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] | ||
pub struct Email(pub(crate) Cow<'static, str>); | ||
|
||
impl Display for Email { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(f, "{}", self.0) | ||
} | ||
} | ||
|
||
impl FromStr for Email { | ||
type Err = EmailError; | ||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
if s.is_empty() { | ||
return Err(EmailError::ParseError(s.to_string())); | ||
} | ||
|
||
if s.contains(' ') { | ||
return Err(EmailError::ParseError(s.to_string())); | ||
} | ||
|
||
let lowercase_email = s.to_lowercase(); | ||
let parts = lowercase_email.split('@').collect::<Vec<&str>>(); | ||
|
||
if parts.len() > 2 { | ||
return Err(EmailError::ParseError(s.to_string())); | ||
} | ||
|
||
if let (Some(ident), Some(domain)) = (parts.first(), parts.get(1)) { | ||
let ident_regex = Regex::new(EMAIL_IDENTIFIER_REGEXP).unwrap(); | ||
let domain_regex = Regex::new(EMAIL_DOMAIN_REGEXP).unwrap(); | ||
|
||
if !ident_regex.is_match(ident) { | ||
return Err(EmailError::InvalidIdentifier( | ||
ident.to_string(), | ||
s.to_string(), | ||
)); | ||
} | ||
|
||
if !domain_regex.is_match(domain) { | ||
return Err(EmailError::InvalidDomain(domain.to_string(), s.to_string())); | ||
} | ||
|
||
let cow = Cow::from(lowercase_email); | ||
|
||
return Ok(Self(cow)); | ||
} | ||
|
||
Err(EmailError::ParseError(s.to_string())) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::borrow::Cow; | ||
use std::str::FromStr; | ||
|
||
use super::Email; | ||
|
||
#[test] | ||
fn creates_email_from_str() { | ||
let email = "[email protected]"; | ||
let have = Email::from_str(email).unwrap(); | ||
let want = Email(Cow::from(email)); | ||
|
||
assert_eq!(have, want); | ||
} | ||
|
||
#[test] | ||
fn checks_for_lowercase_emails() { | ||
let email = "[email protected]"; | ||
let have = Email::from_str(email).unwrap(); | ||
let want = Email(Cow::from("[email protected]")); | ||
|
||
assert_eq!(have, want); | ||
} | ||
|
||
#[test] | ||
fn checks_for_valid_emails() { | ||
let emails = vec![ | ||
"[email protected]", | ||
"[email protected]", | ||
"[email protected]", | ||
"[email protected]", | ||
"[email protected]", | ||
"email@[123.123.123.123]", | ||
"[email protected]", | ||
"[email protected]", | ||
"[email protected]", | ||
"[email protected]", | ||
"[email protected]", | ||
"[email protected]", | ||
"[email protected]", | ||
]; | ||
|
||
for email in emails { | ||
assert!(Email::from_str(email).is_ok(), "email: {email}"); | ||
} | ||
} | ||
|
||
#[test] | ||
fn checks_for_invalid_emails() { | ||
let emails = vec![ | ||
"plainaddress", | ||
"#@%^%#$@#$@#.com", | ||
"@example.com", | ||
"Joe Smith <[email protected]>", | ||
"email.example.com", | ||
"email@[email protected]", | ||
"あいうえお@example.com", | ||
"[email protected] (Joe Smith)", | ||
"email@example", | ||
"[email protected]", | ||
]; | ||
|
||
for email in emails { | ||
let result = Email::from_str(email); | ||
|
||
assert!(result.is_err(), "email: {email}"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
mod email; | ||
mod user; | ||
mod username; | ||
|
||
pub use email::*; | ||
pub use user::*; | ||
pub use username::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use chrono::{DateTime, Utc}; | ||
use pxid::Pxid; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use super::email::Email; | ||
use super::username::Username; | ||
|
||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] | ||
pub struct User { | ||
pub id: Pxid, | ||
pub name: String, | ||
pub surname: String, | ||
pub username: Username, | ||
pub email: Email, | ||
pub avatar_id: Option<Pxid>, | ||
pub created_at: DateTime<Utc>, | ||
pub updated_at: DateTime<Utc>, | ||
pub deleted_at: Option<DateTime<Utc>>, | ||
} |
Oops, something went wrong.