Skip to content

Commit

Permalink
fix: build issue to specify chrono for wasm (#208)
Browse files Browse the repository at this point in the history
  • Loading branch information
EstebanBorai authored Jul 16, 2024
1 parent dcf3fac commit 6f68acd
Show file tree
Hide file tree
Showing 13 changed files with 337 additions and 17 deletions.
16 changes: 15 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"crates/migration",
"crates/server",
"crates/test",
"crates/types",
"crates/web"
]
default-members = ["crates/cli"]
Expand All @@ -19,7 +20,7 @@ async-graphql-axum = "7.0.5"
async-trait = "0.1.80"
axum = "0.7.5"
base64 = "0.22.1"
chrono = "0.4.38"
chrono = { version = "0.4.38", default-features = false }
dotenv = "0.15.0"
fake = "2.9.2"
graphql_client = "0.14.0"
Expand All @@ -30,6 +31,8 @@ leptos_meta = "0.6"
leptos_router = "0.6"
pxid = { version = "0.5", features = ["async-graphql"] }
rand = "0.8.5"
regex = "1.9.3"
reqwest = "0.11"
rust-argon2 = "2.1.0"
rust-s3 = { version = "0.33.0", features = ["tokio-rustls-tls", "fail-on-err"], default-features = false }
sea-orm = "0.12"
Expand Down
6 changes: 3 additions & 3 deletions crates/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ name = "townhall_client"
path = "src/lib.rs"

[dependencies]
chrono = { workspace = true }
chrono = { workspace = true, features = ["js-sys", "wasmbind"] }
graphql_client = { workspace = true, features = ["reqwest"] }
pxid = { workspace = true, features = ["serde"] }
reqwest = { version = "0.11", features = ["blocking", "json"] }
reqwest = { workspace = true, features = ["blocking", "json"] }
serde = { workspace = true }

core = { path = "../core" }
types = { path = "../types" }
2 changes: 1 addition & 1 deletion crates/client/src/modules/auth/user_register/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use graphql_client::GraphQLQuery;
use pxid::Pxid;
use reqwest::Client;

use townhall::user::model::Email;
use townhall_types::user::Email;
use user_register::{UserRegisterUserRegisterError, UserRegisterUserRegisterUser};

pub use crate::auth::user_register::user_register::UserRegisterInput;
Expand Down
16 changes: 7 additions & 9 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,23 @@ name = "townhall"
path = "src/lib.rs"

[dependencies]
chrono = { version = "0.4.26", features = ["serde"] }
rand = "0.8.5"
regex = "1.9.3"
serde = { version = "1.0.188", features = ["derive"] }
serde_json = "1.0.104"
tracing = "0.1.37"

# Workspace Dependencies
async-trait = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
jsonwebtoken = { workspace = true }
lazy_static = { workspace = true }
sea-orm = { workspace = true, features = [ "sqlx-postgres", "runtime-tokio-rustls", "macros", "with-chrono", "mock" ] }
rand = { workspace = true }
regex = { workspace = true }
rust-argon2 = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
pxid = { workspace = true }
url = { workspace = true }

# Local Dependencies
entity = { path = "../entity" }

[dev-dependencies]
tokio = { version = "1.33.0", features = ["rt", "macros"] }
tokio = { workspace = true, features = ["rt", "macros"] }
2 changes: 1 addition & 1 deletion crates/server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ async-graphql-axum = { workspace = true }
async-trait = { workspace = true }
axum = { workspace = true }
base64 = { workspace = true }
chrono = { workspace = true }
chrono = "0.4.38"
dotenv = { workspace = true }
jsonwebtoken = { workspace = true }
pxid = { workspace = true, features = ["async-graphql", "serde"] }
Expand Down
2 changes: 1 addition & 1 deletion crates/test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ path = "src/lib.rs"
[dependencies]
anyhow = { workspace = true }
async-graphql = { workspace = true }
chrono = { workspace = true }
chrono = "0.4.38"
dotenv = { workspace = true }
fake = { workspace = true }
pxid = { workspace = true }
Expand Down
19 changes: 19 additions & 0 deletions crates/types/Cargo.toml
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 }
1 change: 1 addition & 0 deletions crates/types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod user;
156 changes: 156 additions & 0 deletions crates/types/src/user/email.rs
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}");
}
}
}
7 changes: 7 additions & 0 deletions crates/types/src/user/mod.rs
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::*;
19 changes: 19 additions & 0 deletions crates/types/src/user/user.rs
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>>,
}
Loading

0 comments on commit 6f68acd

Please sign in to comment.