Source code for app.domain.users.schemas

from datetime import datetime
from enum import StrEnum
from re import compile as re_compile
from typing import (
    Annotated,
    Self,
)
from uuid import UUID

from annotated_types import (
    MaxLen,
    MinLen,
)
from pydantic import (
    EmailStr,
    model_validator,
)

from app.lib.pretty_regex_error_msgs import RegexValidator
from app.lib.schema import (
    CamelizedBaseSchema,
    CamelizedBaseStruct,
)

__all__ = (
    "AccountRegister",
    "PasswordUpdate",
    "User",
    "UserAuth",
    "UserCreate",
    "UserRoleAdd",
    "UserRoleRevoke",
    "UserUpdate",
)


[docs] class PasswordValidator( RegexValidator, pattern=re_compile(r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&_])[A-Za-z\d@$!%*?&_]{8,}$"), error_message="The password must contain a minimum of eight characters, at least one uppercase letter, one " "lowercase letter, one number and one special character", ): """Validator for user passwords."""
[docs] class User(CamelizedBaseStruct): """User properties to use for a response.""" id: UUID name: str | None email: str is_active: bool is_superuser: bool role_name: str role_slug: str created_at: datetime updated_at: datetime
[docs] class UserCreate(CamelizedBaseSchema): """Properties required to create a new user.""" name: str | None = None email: EmailStr password: Annotated[str, MinLen(3), MaxLen(20)] is_active: bool = True is_superuser: bool = False
[docs] class UserUpdate(CamelizedBaseSchema): """Data transfer object for optional user account updates.""" name: str | None = None email: EmailStr | None = None password: Annotated[str, MinLen(3), MaxLen(20)] | None = None is_active: bool | None = None is_superuser: bool | None = None
[docs] class AccountRegister(CamelizedBaseSchema): """Information provided by a user during public registration.""" name: str | None = None email: EmailStr password: Annotated[str, PasswordValidator] confirm_password: str
[docs] @model_validator(mode="after") def check_passwords_match(self) -> Self: """Ensure the 'password' and 'confirm_password' fields match.""" if self.confirm_password != self.password: msg = "Passwords don't match" raise ValueError(msg) return self
[docs] class UserAuth(CamelizedBaseStruct, dict=True): """User model used for authentication context.""" id: UUID name: str | None email: str is_active: bool is_superuser: bool role_slug: str def __post_init__(self) -> None: self._refresh_jti = None
[docs] class PasswordUpdate(CamelizedBaseSchema): """Input data for password rotation.""" current_password: str new_password: Annotated[str, PasswordValidator]
[docs] class RoleSlug(StrEnum): """Available user role slugs.""" SUPERUSER = "superuser" FITNESS_TRAINER = "fitness-trainer"
[docs] class UserRoleAdd(CamelizedBaseSchema): """Payload for granting a specific role to a user.""" role_slug: RoleSlug
[docs] class UserRoleRevoke(UserRoleAdd): """Payload for revoking a specific role from a user."""