"""Shared HTTP request and error contracts.""" from typing import Any, Optional from pydantic import BaseModel, ConfigDict, Field class StrictRequest(BaseModel): model_config = ConfigDict(extra="forbid") class ErrorResponse(BaseModel): detail: str COMMON_ERROR_RESPONSES: dict[int, dict[str, Any]] = { 400: {"model": ErrorResponse, "description": "Invalid request"}, 401: {"model": ErrorResponse, "description": "Authentication required"}, 403: {"model": ErrorResponse, "description": "Permission denied"}, 404: {"model": ErrorResponse, "description": "Resource not found"}, 409: {"model": ErrorResponse, "description": "Request conflict"}, 429: {"model": ErrorResponse, "description": "Rate limit exceeded"}, 500: {"model": ErrorResponse, "description": "Unexpected server error"}, 502: {"model": ErrorResponse, "description": "Upstream service error"}, 503: {"model": ErrorResponse, "description": "Service unavailable"}, } class SignupRequest(StrictRequest): invite_code: str = Field(min_length=1, max_length=256) username: str = Field(min_length=1, max_length=100) password: str = Field(min_length=1, max_length=1024) email: Optional[str] = Field(default=None, max_length=320) class ForgotPasswordRequest(StrictRequest): identifier: Optional[str] = Field(default=None, max_length=320) username: Optional[str] = Field(default=None, max_length=100) email: Optional[str] = Field(default=None, max_length=320) class PasswordResetRequest(StrictRequest): token: str = Field(min_length=1, max_length=512) new_password: str = Field(min_length=1, max_length=1024) class ProfileEmailUpdateRequest(StrictRequest): email: Optional[str] = Field(default=None, max_length=320) class ChangePasswordRequest(StrictRequest): current_password: str = Field(min_length=1, max_length=1024) new_password: str = Field(min_length=1, max_length=1024) def request_data(payload: BaseModel | dict[str, Any]) -> dict[str, Any]: """Keep direct service-level tests compatible while FastAPI validates HTTP input.""" return payload if isinstance(payload, dict) else payload.model_dump()