"""Pydantic schemas for API request/response models.""" from datetime import datetime from typing import Generic, TypeVar from pydantic import BaseModel, EmailStr # ============================================================================= # Auth Schemas # ============================================================================= class UserCredentials(BaseModel): """Base model for user email/password.""" email: EmailStr password: str UserCreate = UserCredentials UserLogin = UserCredentials class UserResponse(BaseModel): """Response model for authenticated user info.""" id: int email: str roles: list[str] permissions: list[str] class TokenResponse(BaseModel): """Response model for token-based auth (unused but kept for API completeness).""" access_token: str token_type: str user: UserResponse class RegisterWithInvite(BaseModel): """Request model for registration with invite.""" email: EmailStr password: str invite_identifier: str # ============================================================================= # Counter Schemas # ============================================================================= class CounterValue(BaseModel): """Response model for counter value.""" value: int # ============================================================================= # Sum Schemas # ============================================================================= class SumRequest(BaseModel): """Request model for sum calculation.""" a: float b: float class SumResponse(BaseModel): """Response model for sum calculation.""" a: float b: float result: float # ============================================================================= # Audit Schemas # ============================================================================= class CounterRecordResponse(BaseModel): """Response model for a counter audit record.""" id: int user_email: str value_before: int value_after: int created_at: datetime class SumRecordResponse(BaseModel): """Response model for a sum audit record.""" id: int user_email: str a: float b: float result: float created_at: datetime # ============================================================================= # Pagination (Generic) # ============================================================================= RecordT = TypeVar("RecordT", bound=BaseModel) class PaginatedResponse(BaseModel, Generic[RecordT]): """Generic paginated response wrapper.""" records: list[RecordT] total: int page: int per_page: int total_pages: int PaginatedCounterRecords = PaginatedResponse[CounterRecordResponse] PaginatedSumRecords = PaginatedResponse[SumRecordResponse] # ============================================================================= # Profile Schemas # ============================================================================= class ProfileResponse(BaseModel): """Response model for profile data.""" contact_email: str | None telegram: str | None signal: str | None nostr_npub: str | None godfather_email: str | None = None class ProfileUpdate(BaseModel): """Request model for updating profile.""" contact_email: str | None = None telegram: str | None = None signal: str | None = None nostr_npub: str | None = None # ============================================================================= # Invite Schemas # ============================================================================= class InviteCheckResponse(BaseModel): """Response for invite check endpoint.""" valid: bool status: str | None = None error: str | None = None class InviteCreate(BaseModel): """Request model for creating an invite.""" godfather_id: int class InviteResponse(BaseModel): """Response model for invite data (admin view).""" id: int identifier: str godfather_id: int godfather_email: str status: str used_by_id: int | None used_by_email: str | None created_at: datetime spent_at: datetime | None revoked_at: datetime | None class UserInviteResponse(BaseModel): """Response model for a user's invite (simpler than admin view).""" id: int identifier: str status: str used_by_email: str | None created_at: datetime spent_at: datetime | None PaginatedInviteRecords = PaginatedResponse[InviteResponse] # ============================================================================= # Admin Schemas # ============================================================================= class AdminUserResponse(BaseModel): """Minimal user info for admin dropdowns.""" id: int email: str