Adds the `Page[T]` envelope `{items, total, page, page_size}` documented in
D-016, the matching `PageQuery` for `?page=&page_size=` parsing (default 50,
max 200), and `parse_page_query()` helper for blueprints.
DTOs:
- `UserRead` / `UserCreate` / `UserUpdate` (sprint 2). `UserRead` never
exposes `local_password_hash`. `UserCreate` validates email via
pydantic-email-validator and pins password to 8..128 chars.
- `EngagementMemberRead` / `EngagementMemberCreate`. `role` is a free-form
string ≤ 40 chars (D-017), defaulting to `"member"`.
- `AuditLogEntry` for the upcoming audit viewer.
28 lines
711 B
Python
28 lines
711 B
Python
"""Engagement membership DTOs (sprint 2).
|
|
|
|
`role` is a free-form label per D-017 — not a permission gate. Application-
|
|
level RBAC stays the responsibility of the F11 `group` membership; per-
|
|
engagement role is informational (e.g. "lead", "shadow", "binôme A").
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from uuid import UUID
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
|
|
class EngagementMemberRead(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
engagement_id: UUID
|
|
user_id: UUID
|
|
role: str
|
|
added_at: datetime
|
|
|
|
|
|
class EngagementMemberCreate(BaseModel):
|
|
user_id: UUID
|
|
role: str = Field(default="member", min_length=1, max_length=40)
|