185 lines
4.7 KiB
Python
185 lines
4.7 KiB
Python
"""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
|
|
|