from datetime import datetime from pydantic import BaseModel, Field from typing import Any # ============ User Ban ============ class BanUserRequest(BaseModel): reason: str = Field(..., min_length=1, max_length=500) banned_until: datetime | None = None # None = permanent ban class AdminResetPasswordRequest(BaseModel): new_password: str = Field(..., min_length=6, max_length=100) class AdminUserResponse(BaseModel): id: int login: str nickname: str role: str avatar_url: str | None = None telegram_id: int | None = None telegram_username: str | None = None marathons_count: int = 0 created_at: str is_banned: bool = False banned_at: str | None = None banned_until: str | None = None # None = permanent ban_reason: str | None = None class Config: from_attributes = True # ============ Admin Logs ============ class AdminLogResponse(BaseModel): id: int admin_id: int | None = None # Nullable for system actions admin_nickname: str | None = None # Nullable for system actions action: str target_type: str target_id: int details: dict | None = None ip_address: str | None = None created_at: datetime class Config: from_attributes = True class AdminLogsListResponse(BaseModel): logs: list[AdminLogResponse] total: int # ============ Broadcast ============ class BroadcastRequest(BaseModel): message: str = Field(..., min_length=1, max_length=2000) class BroadcastResponse(BaseModel): sent_count: int total_count: int # ============ Static Content ============ class StaticContentResponse(BaseModel): id: int key: str title: str content: str updated_at: datetime created_at: datetime class Config: from_attributes = True class StaticContentUpdate(BaseModel): title: str = Field(..., min_length=1, max_length=200) content: str = Field(..., min_length=1) class StaticContentCreate(BaseModel): key: str = Field(..., min_length=1, max_length=100, pattern=r"^[a-z0-9_-]+$") title: str = Field(..., min_length=1, max_length=200) content: str = Field(..., min_length=1) # ============ 2FA ============ class TwoFactorInitiateRequest(BaseModel): pass # No additional data needed class TwoFactorInitiateResponse(BaseModel): session_id: int expires_at: datetime message: str = "Code sent to Telegram" class TwoFactorVerifyRequest(BaseModel): session_id: int code: str = Field(..., min_length=6, max_length=6) class LoginResponse(BaseModel): """Login response that may require 2FA""" access_token: str | None = None token_type: str = "bearer" user: Any = None # UserPrivate requires_2fa: bool = False two_factor_session_id: int | None = None # ============ Dashboard Stats ============ class DashboardStats(BaseModel): users_count: int banned_users_count: int marathons_count: int active_marathons_count: int games_count: int total_participations: int recent_logs: list[AdminLogResponse] = []