use crate::value_objects::{Email, PasswordHash, UserId, Username}; #[derive(Clone, Debug, Default)] pub enum UserRole { #[default] Standard, Admin, } impl UserRole { pub fn as_str(&self) -> &'static str { match self { Self::Standard => "standard", Self::Admin => "admin", } } } #[derive(Debug, Clone)] pub struct ProfileField { pub name: String, pub value: String, } #[derive(Clone, Debug, Default)] pub struct UserProfile { pub display_name: Option, pub bio: Option, pub avatar_path: Option, pub banner_path: Option, pub also_known_as: Option, pub profile_fields: Vec, } impl UserProfile { pub const MAX_CUSTOM_FIELDS: usize = 4; pub fn validate_custom_fields( fields: &[ProfileField], ) -> Result<(), crate::errors::DomainError> { if fields.len() > Self::MAX_CUSTOM_FIELDS { Err(crate::errors::DomainError::ValidationError( "Maximum 4 profile fields allowed".into(), )) } else { Ok(()) } } } #[derive(Clone, Debug)] pub struct User { id: UserId, email: Email, username: Username, password_hash: PasswordHash, role: UserRole, profile: UserProfile, } impl User { pub fn new( email: Email, username: Username, password_hash: PasswordHash, role: UserRole, ) -> Self { Self { id: UserId::generate(), email, username, password_hash, role, profile: UserProfile::default(), } } pub fn from_persistence( id: UserId, email: Email, username: Username, password_hash: PasswordHash, role: UserRole, profile: UserProfile, ) -> Self { Self { id, email, username, password_hash, role, profile, } } pub fn update_password(&mut self, new_hash: PasswordHash) { self.password_hash = new_hash; } pub fn update_profile(&mut self, profile: UserProfile) { self.profile = profile; } pub fn email(&self) -> &Email { &self.email } pub fn username(&self) -> &Username { &self.username } pub fn id(&self) -> &UserId { &self.id } pub fn password_hash(&self) -> &PasswordHash { &self.password_hash } pub fn role(&self) -> &UserRole { &self.role } pub fn display_name(&self) -> Option<&str> { self.profile.display_name.as_deref() } pub fn bio(&self) -> Option<&str> { self.profile.bio.as_deref() } pub fn avatar_path(&self) -> Option<&str> { self.profile.avatar_path.as_deref() } pub fn banner_path(&self) -> Option<&str> { self.profile.banner_path.as_deref() } pub fn also_known_as(&self) -> Option<&str> { self.profile.also_known_as.as_deref() } pub fn profile_fields(&self) -> &[ProfileField] { &self.profile.profile_fields } } #[derive(Clone, Debug)] pub struct UserSummary { pub user_id: UserId, email: Email, username: Username, display_name: Option, pub total_movies: i64, pub avg_rating: Option, pub avatar_path: Option, } impl UserSummary { pub fn new( user_id: UserId, email: Email, username: Username, display_name: Option, total_movies: i64, avg_rating: Option, avatar_path: Option, ) -> Self { Self { user_id, email, username, display_name, total_movies, avg_rating, avatar_path, } } pub fn email(&self) -> &str { self.email.value() } pub fn username(&self) -> &str { self.username.value() } pub fn display_name(&self) -> Option<&str> { self.display_name.as_deref() } }