65 lines
1.8 KiB
Rust
65 lines
1.8 KiB
Rust
use axum::Form;
|
|
use itertools::Itertools;
|
|
use validator::{Validate, ValidationError};
|
|
|
|
use crate::{
|
|
auth::{HashedBytes, Token},
|
|
prelude::*,
|
|
};
|
|
|
|
#[derive(Deserialize, Debug, Validate)]
|
|
pub struct Params {
|
|
#[validate(length(min = 3, max = 10))]
|
|
username: String,
|
|
#[validate(email)]
|
|
email: String,
|
|
#[validate(length(min = 6), custom(function = "validate_password"))]
|
|
password: String,
|
|
}
|
|
|
|
fn validate_password(password: &str) -> Result<(), ValidationError> {
|
|
let mut has_lower = false;
|
|
let mut has_upper = false;
|
|
let mut has_number = false;
|
|
let mut has_special = false;
|
|
for char in password.chars() {
|
|
if char.is_lowercase() {
|
|
has_lower = true;
|
|
} else if char.is_uppercase() {
|
|
has_upper = true;
|
|
} else if char.is_ascii_digit() {
|
|
has_number = true;
|
|
} else {
|
|
has_special = true;
|
|
}
|
|
}
|
|
let msg = [has_lower, has_upper, has_number, has_special]
|
|
.into_iter()
|
|
.zip(["No lower", "No upper", "No numbers", "No special"])
|
|
.filter_map(|(param, msg)| (!param).then_some(msg))
|
|
.format(" ")
|
|
.to_string();
|
|
if !msg.is_empty() {
|
|
return Err(ValidationError::new("invalid_password").with_message(msg.into()));
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn register(
|
|
State(pool): State<Pool>,
|
|
Form(params): Form<Params>,
|
|
) -> GeneralResult<Json<Token>> {
|
|
params.validate()?;
|
|
|
|
let password = HashedBytes::hash_bytes(params.password.as_bytes()).as_bytes();
|
|
let id = db::users::create_user(¶ms.username, ¶ms.email, &password, &pool)
|
|
.await
|
|
.handle_internal("Error creating the user")?
|
|
.handle(
|
|
StatusCode::BAD_REQUEST,
|
|
"The username or the email are taken",
|
|
)?;
|
|
|
|
Claims::new(id).encode().map(Json)
|
|
}
|