import re from typing import Optional from pydantic import EmailStr, Field, field_validator from app.core.data_types import UUID7Field from app.core.exceptions import UnprocessableEntity from .base import BaseSchema from .organization_schema import OrganizationWithMapsetSchema from .role_schema import RoleSchema class UserSchema(BaseSchema): id: UUID7Field name: str email: EmailStr profile_picture: Optional[str] = None username: str position: Optional[str] = None role: RoleSchema | None employee_id: Optional[str] = None organization: OrganizationWithMapsetSchema is_active: bool = True class UserCreateSchema(BaseSchema): name: str = Field(..., min_length=4, max_length=100) email: EmailStr profile_picture: Optional[str] = Field(None) username: str = Field(None, min_length=3, max_length=30, pattern=r"^[a-zA-Z0-9_]+$") password: str = Field(..., min_length=8, max_length=128) position: Optional[str] = Field(None) role_id: UUID7Field employee_id: Optional[str] = None organization_id: UUID7Field is_active: bool = True @field_validator("password") @classmethod def validate_password(cls, value): if value is None: return value has_letter = any(c.isalpha() for c in value) has_digit = any(c.isdigit() for c in value) has_special = any(c in "@$!%*#?&" for c in value) if not (has_letter and has_digit and has_special): raise UnprocessableEntity( "Password must be at least 8 characters long and contain at least one letter, one number, and one special character" ) return value @field_validator("username") @classmethod def validate_username(cls, value): if value is None: return value if not re.match(r"^[a-zA-Z0-9_]+$", value): raise UnprocessableEntity("Username can only contain letters, numbers, and underscores") return value @field_validator("email") @classmethod def validate_email_domain(cls, value): if value is None: return value # Validasi tambahan untuk domain email jika diperlukan value.split("@")[1] valid_domains = ["gmail.com", "yahoo.com", "hotmail.com", "company.com"] # Sesuaikan dengan kebutuhan # Hapus validasi ini jika tidak diperlukan atau sesuaikan dengan kebutuhan # if domain not in valid_domains: # raise UnprocessableEntity(f'Domain email tidak valid. Domain yang diizinkan: {", ".join(valid_domains)}') return value class UserUpdateSchema(BaseSchema): name: Optional[str] = Field(None, min_length=2, max_length=100) email: Optional[EmailStr] = None profile_picture: Optional[str] = Field(None, max_length=255) username: Optional[str] = Field(None, min_length=3, max_length=30, pattern=r"^[a-zA-Z0-9_]+$") password: Optional[str] = Field(None, min_length=8, max_length=128) position: Optional[str] = Field(None) role_id: Optional[UUID7Field] = Field(None) employee_id: Optional[str] = Field(None, max_length=50) organization_id: Optional[UUID7Field] = Field(None) is_active: Optional[bool] = None @field_validator("password") @classmethod def validate_password(cls, value): if value is None: return value has_letter = any(c.isalpha() for c in value) has_digit = any(c.isdigit() for c in value) has_special = any(c in "@$!%*#?&" for c in value) if not (has_letter and has_digit and has_special): raise UnprocessableEntity( "Password must be at least 8 characters long and contain at least one letter, one number, and one special character" ) return value @field_validator("username") @classmethod def validate_username(cls, value): if value is None: return value if not re.match(r"^[a-zA-Z0-9_]+$", value): raise UnprocessableEntity("Username can only contain letters, numbers, and underscores") return value @field_validator("email") @classmethod def validate_email_domain(cls, value): if value is None: return value # Validasi tambahan untuk domain email jika diperlukan value.split("@")[1] valid_domains = ["gmail.com", "yahoo.com", "hotmail.com", "company.com"] # Sesuaikan dengan kebutuhan # Hapus validasi ini jika tidak diperlukan atau sesuaikan dengan kebutuhan # if domain not in valid_domains: # raise UnprocessableEntity(f'Domain email tidak valid. Domain yang diizinkan: {", ".join(valid_domains)}') return value