use crate::{RolesDetailItemDto, RolesDetailQueryDto}; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use surrealdb::sql::Thing; use utoipa::ToSchema; use validator::Validate; use crate::UsersSchema; // Import UsersSchema lazy_static! { static ref PASSWORD_REGEX: regex::Regex = regex::Regex::new(r"^[A-Za-z\d@$!%*?&]{8,}$").unwrap(); } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct ExperienceDto { pub id: String, pub company: String, pub position: String, pub duration: String, pub period: String, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct EducationDto { pub id: String, pub institution: String, pub degree: String, pub field: String, pub period: String, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct UsersActiveInactiveRequestDto { pub is_active: bool, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct UsersSetNewPasswordRequestDto { pub password: String, pub old_password: String, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct UsersCreateRequestDto { #[validate( length(min = 1, message = "Email cannot be empty"), email(message = "Email not valid") )] pub email: String, #[validate(length( min = 8, message = "Password must have at least 8 characters" ))] #[validate(regex( path = "*PASSWORD_REGEX", message = "Password must include uppercase, lowercase, number, and special character" ))] pub password: String, #[validate(length(min = 2, message = "Fullname at least have 2 character"))] pub fullname: String, #[validate(length( min = 10, message = "Phone number at least have 10 character" ))] pub phone_number: String, pub is_active: bool, pub role_id: String, pub avatar: Option, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct UsersUpdateRequestDto { #[validate( length(min = 1, message = "Email cannot be empty"), email(message = "Email not valid") )] #[serde(skip_serializing_if = "Option::is_none")] pub email: Option, #[validate(length( min = 8, message = "Password must have at least 8 characters" ))] #[serde(skip_serializing_if = "Option::is_none")] pub password: Option, #[validate(length(min = 2, message = "Fullname at least have 2 character"))] #[serde(skip_serializing_if = "Option::is_none")] pub fullname: Option, #[validate(length(min = 2, message = "Legal name at least have 2 character"))] #[serde(skip_serializing_if = "Option::is_none")] pub legal_name: Option, #[validate(length( min = 10, message = "Phone number at least have 10 character" ))] #[serde(skip_serializing_if = "Option::is_none")] pub phone_number: Option, #[serde(skip_serializing_if = "Option::is_none")] pub phone_for_verification: Option, #[serde(skip_serializing_if = "Option::is_none")] pub is_active: Option, #[validate(length(min = 1, message = "Gender is required"))] #[serde(skip_serializing_if = "Option::is_none")] pub gender: Option, #[validate(length(min = 1, message = "Birthdate is required"))] #[serde(skip_serializing_if = "Option::is_none")] pub birthdate: Option, #[serde(skip_serializing_if = "Option::is_none")] pub domicile: Option, #[validate(length(min = 50, message = "Bio must be at least 50 characters"))] #[serde(skip_serializing_if = "Option::is_none")] pub bio: Option, #[serde(skip_serializing_if = "Option::is_none")] pub last_education: Option, #[validate(url(message = "Invalid LinkedIn URL"))] #[serde(skip_serializing_if = "Option::is_none")] pub linkedin_url: Option, #[validate(url(message = "Invalid GitHub URL"))] #[serde(skip_serializing_if = "Option::is_none")] pub github_url: Option, #[validate(url(message = "Invalid CV URL"))] #[serde(skip_serializing_if = "Option::is_none")] pub cv_url: Option, #[validate(url(message = "Invalid portfolio URL"))] #[serde(skip_serializing_if = "Option::is_none")] pub portfolio_url: Option, #[validate(url(message = "Invalid website URL"))] #[serde(skip_serializing_if = "Option::is_none")] pub website_url: Option, #[validate(url(message = "Invalid Twitter URL"))] #[serde(skip_serializing_if = "Option::is_none")] pub twitter_url: Option, #[validate(length(min = 1, message = "Avatar is required"))] #[serde(skip_serializing_if = "Option::is_none")] pub avatar: Option, #[serde(skip_serializing_if = "Option::is_none")] pub role_id: Option, #[serde(skip_serializing_if = "Option::is_none")] pub location: Option, #[serde(skip_serializing_if = "Option::is_none")] pub skills: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub experience: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub education: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub career_status: Option, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct UsersDetailItemDto { pub id: String, pub role: RolesDetailItemDto, pub fullname: String, pub legal_name: Option, pub email: String, pub avatar: Option, pub phone_number: String, pub phone_for_verification: Option, pub is_active: bool, pub gender: Option, pub birthdate: Option, pub domicile: Option, pub bio: Option, pub last_education: Option, pub linkedin_url: Option, pub github_url: Option, pub cv_url: Option, pub portfolio_url: Option, pub website_url: Option, pub twitter_url: Option, pub location: Option, pub skills: Option>, pub experience: Option>, pub education: Option>, pub career_status: Option, pub created_at: String, pub updated_at: String, } impl UsersDetailItemDto { pub fn from(dto: &UsersDetailQueryDto) -> Self { // Reverted to taking a reference Self { id: dto.id.id.to_raw().clone(), role: RolesDetailItemDto::from(&dto.role), fullname: dto.fullname.clone(), legal_name: dto.legal_name.clone(), email: dto.email.clone(), avatar: dto.avatar.clone(), phone_number: dto.phone_number.clone(), // Corrected from dto.phone.clone() phone_for_verification: dto.phone_for_verification.clone(), is_active: dto.is_active, gender: dto.gender.clone(), birthdate: dto.birthdate.clone(), domicile: dto.domicile.clone(), bio: dto.bio.clone(), last_education: dto.last_education.clone(), linkedin_url: dto.linkedin_url.clone(), github_url: dto.github_url.clone(), cv_url: dto.cv_url.clone(), portfolio_url: dto.portfolio_url.clone(), website_url: dto.website_url.clone(), twitter_url: dto.twitter_url.clone(), location: dto.location.clone(), skills: dto.skills.clone(), experience: dto.experience.clone(), education: dto.education.clone(), career_status: dto.career_status.clone(), created_at: dto.created_at.clone(), updated_at: dto.updated_at.clone(), } } pub fn from_schema(schema: &UsersSchema) -> Self { Self { id: schema.id.id.to_raw(), role: RolesDetailItemDto::default(), // Placeholder, role needs to be fetched fullname: schema.fullname.clone(), legal_name: schema.legal_name.clone(), email: schema.email.clone(), avatar: schema.avatar.clone(), phone_number: schema.phone_number.clone(), phone_for_verification: schema.phone_for_verification.clone(), is_active: schema.is_active, gender: schema.gender.clone(), birthdate: schema.birthdate.clone(), domicile: schema.domicile.clone(), bio: schema.bio.clone(), last_education: schema.last_education.clone(), linkedin_url: schema.linkedin_url.clone(), github_url: schema.github_url.clone(), cv_url: schema.cv_url.clone(), portfolio_url: schema.portfolio_url.clone(), website_url: schema.website_url.clone(), twitter_url: schema.twitter_url.clone(), location: schema.location.clone(), skills: schema.skills.clone(), experience: schema.experience.clone(), education: schema.education.clone(), career_status: schema.career_status.clone(), created_at: schema.created_at.clone(), updated_at: schema.updated_at.clone(), } } } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct UsersListItemDto { pub id: String, pub role: String, pub fullname: String, pub email: String, pub avatar: Option, pub phone_number: String, pub is_active: bool, pub created_at: String, pub updated_at: String, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct UsersListQueryDto { pub id: Thing, pub role: RolesDetailQueryDto, pub fullname: String, pub email: String, // Corrected from pub pub email: String, pub avatar: Option, pub phone_number: String, pub is_active: bool, pub created_at: String, pub updated_at: String, } impl UsersListQueryDto { pub fn from(self) -> UsersListItemDto { UsersListItemDto { id: self.id.id.to_raw(), role: self.role.name.clone(), fullname: self.fullname.clone(), email: self.email.clone(), avatar: self.avatar.clone(), phone_number: self.phone_number.clone(), is_active: self.is_active, created_at: self.created_at.clone(), updated_at: self.updated_at.clone(), } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct UsersDetailQueryDto { pub id: Thing, pub fullname: String, pub legal_name: Option, pub email: String, pub avatar: Option, pub phone_number: String, pub phone_for_verification: Option, pub is_active: bool, pub is_deleted: bool, pub gender: Option, pub birthdate: Option, pub domicile: Option, pub bio: Option, pub last_education: Option, pub linkedin_url: Option, pub github_url: Option, pub cv_url: Option, pub portfolio_url: Option, pub website_url: Option, pub twitter_url: Option, pub location: Option, pub skills: Option>, pub experience: Option>, pub education: Option>, pub career_status: Option, pub password: String, pub role: RolesDetailQueryDto, pub created_at: String, pub updated_at: String, pub mentor_id: Option, } impl UsersDetailQueryDto { pub fn from(&self) -> Self { Self { id: self.id.clone(), role: self.role.clone(), fullname: self.fullname.clone(), legal_name: self.legal_name.clone(), email: self.email.clone(), avatar: self.avatar.clone(), phone_number: self.phone_number.clone(), phone_for_verification: self.phone_for_verification.clone(), is_active: self.is_active, mentor_id: self.mentor_id.clone(), gender: self.gender.clone(), domicile: self.domicile.clone(), bio: self.bio.clone(), last_education: self.last_education.clone(), linkedin_url: self.linkedin_url.clone(), github_url: self.github_url.clone(), cv_url: self.cv_url.clone(), portfolio_url: self.portfolio_url.clone(), website_url: self.website_url.clone(), twitter_url: self.twitter_url.clone(), location: self.location.clone(), skills: self.skills.clone(), experience: self.experience.clone(), education: self.education.clone(), career_status: self.career_status.clone(), is_deleted: self.is_deleted, password: self.password.clone(), birthdate: self.birthdate.clone(), created_at: self.created_at.clone(), updated_at: self.updated_at.clone(), } } } impl From<&UsersDetailItemDto> for UsersDetailQueryDto { fn from(dto: &UsersDetailItemDto) -> Self { Self { id: crate::make_thing(&imphnen_libs::ResourceEnum::Users.to_string(), &dto.id), fullname: dto.fullname.clone(), legal_name: dto.legal_name.clone(), email: dto.email.clone(), avatar: dto.avatar.clone(), phone_number: dto.phone_number.clone(), phone_for_verification: dto.phone_for_verification.clone(), is_active: dto.is_active, is_deleted: false, gender: dto.gender.clone(), birthdate: dto.birthdate.clone(), domicile: dto.domicile.clone(), bio: dto.bio.clone(), last_education: dto.last_education.clone(), linkedin_url: dto.linkedin_url.clone(), github_url: dto.github_url.clone(), cv_url: dto.cv_url.clone(), portfolio_url: dto.portfolio_url.clone(), website_url: dto.website_url.clone(), twitter_url: dto.twitter_url.clone(), location: dto.location.clone(), skills: dto.skills.clone(), experience: dto.experience.clone(), education: dto.education.clone(), career_status: dto.career_status.clone(), password: String::new(), role: RolesDetailQueryDto::default(), created_at: dto.created_at.clone(), updated_at: dto.updated_at.clone(), mentor_id: None, } } }