Spaces:
Running
Running
| """DTOs for ``/admin/users/*`` β admin management of DB-backed reader accounts. | |
| These shape the wire for the admin UI that creates/lists/disables/deletes the | |
| low-privilege ``reader`` accounts stored in ``app_users`` (see | |
| :mod:`src.lib.auth.user_store`). Password hashes are NEVER returned β the list | |
| DTO carries only safe-to-display fields. | |
| All DTOs inherit :class:`ApiModel` so the wire is camelCase (CONTRACT.md Β§1). | |
| """ | |
| from __future__ import annotations | |
| from pydantic import Field | |
| from .common import ApiModel | |
| class AppUserDTO(ApiModel): | |
| """One DB-backed account, projected for the admin list/management UI. | |
| No ``passwordHash`` field by design β the hash never leaves the server. | |
| """ | |
| username: str | |
| role: str | |
| display_name: str | None = None | |
| disabled: bool | |
| created_at: str | None = None | |
| class AppUserListResponse(ApiModel): | |
| """``GET /admin/users`` envelope.""" | |
| items: list[AppUserDTO] | |
| class CreateAppUserRequest(ApiModel): | |
| """``POST /admin/users`` body. | |
| Creates a ``reader`` account (the role is forced server-side β this body | |
| intentionally has no ``role`` field so an admin can't mint another admin | |
| through the DB). ``password`` is validated for a sane minimum length in the | |
| router; ``displayName`` is optional and cosmetic. | |
| """ | |
| username: str = Field( | |
| min_length=1, | |
| max_length=64, | |
| pattern=r"^[A-Za-z0-9._-]+$", | |
| ) | |
| password: str = Field(min_length=8, max_length=256) | |
| display_name: str | None = Field(default=None, max_length=128) | |
| class UpdateAppUserRequest(ApiModel): | |
| """``PATCH /admin/users/{username}`` body. | |
| Both fields optional: set ``disabled`` to enable/suspend the account, set | |
| ``password`` to reset it (re-hashed server-side). Sending neither is a | |
| no-op 200 with the current row. | |
| """ | |
| disabled: bool | None = None | |
| password: str | None = Field(default=None, max_length=256) | |