Files
Infrastruktur-Monitoring-Sy…/backend/crates/domain/src/user.rs
Dennis Nemec 83aa500f5d
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / ui (push) Has been cancelled
WP-01: domain contract and failing tests for auth and user management
Domain entities/ports, service stubs, 18 application unit tests with in-memory
fakes, API integration tests for /api/auth and /api/users, Vitest specs for the
auth store, login page and user form, Playwright auth/user-management flow.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 21:31:59 +02:00

83 lines
2.0 KiB
Rust

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Role {
Admin,
User,
}
impl Role {
pub fn as_str(self) -> &'static str {
match self {
Role::Admin => "admin",
Role::User => "user",
}
}
pub fn parse(s: &str) -> Option<Role> {
match s {
"admin" => Some(Role::Admin),
"user" => Some(Role::User),
_ => None,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct User {
pub id: Uuid,
pub email: String,
pub display_name: String,
pub password_hash: String,
pub role: Role,
pub is_active: bool,
pub created_at: DateTime<Utc>,
}
impl User {
pub fn is_admin(&self) -> bool {
self.role == Role::Admin
}
}
/// Input for creating a user; the password is still in plain text here.
#[derive(Clone, Debug)]
pub struct NewUser {
pub email: String,
pub display_name: String,
pub password: String,
pub role: Role,
}
/// Partial update; `None` keeps the current value.
#[derive(Clone, Debug, Default)]
pub struct UserUpdate {
pub display_name: Option<String>,
pub role: Option<Role>,
pub is_active: Option<bool>,
}
pub const MIN_PASSWORD_LEN: usize = 12;
pub fn validate_email(email: &str) -> Result<(), crate::DomainError> {
let ok = email.contains('@')
&& !email.starts_with('@')
&& !email.ends_with('@')
&& !email.contains(' ');
ok.then_some(())
.ok_or_else(|| crate::DomainError::Validation("invalid email".into()))
}
pub fn validate_password(password: &str) -> Result<(), crate::DomainError> {
(password.chars().count() >= MIN_PASSWORD_LEN)
.then_some(())
.ok_or_else(|| {
crate::DomainError::Validation(format!(
"password must have at least {MIN_PASSWORD_LEN} characters"
))
})
}