first implementation
This commit is contained in:
parent
1eb4641ed9
commit
a56a4c076a
14 changed files with 898 additions and 729 deletions
185
backend/schemas.py
Normal file
185
backend/schemas.py
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
"""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
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue