Added admin panel.
This commit is contained in:
265
backend/app/schemas/admin.py
Normal file
265
backend/app/schemas/admin.py
Normal file
@ -0,0 +1,265 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import Optional, Literal
|
||||
from enum import Enum
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Audit Log Schemas
|
||||
# ============================================================
|
||||
|
||||
class AuditLogAction(str, Enum):
|
||||
DATA_WIPE = "DATA_WIPE"
|
||||
DATA_SEED = "DATA_SEED"
|
||||
SIMULATION_START = "SIMULATION_START"
|
||||
SIMULATION_STOP = "SIMULATION_STOP"
|
||||
USER_STATUS_CHANGE = "USER_STATUS_CHANGE"
|
||||
USER_BALANCE_ADJUST = "USER_BALANCE_ADJUST"
|
||||
USER_ADMIN_GRANT = "USER_ADMIN_GRANT"
|
||||
USER_ADMIN_REVOKE = "USER_ADMIN_REVOKE"
|
||||
USER_UPDATE = "USER_UPDATE"
|
||||
SETTINGS_UPDATE = "SETTINGS_UPDATE"
|
||||
EVENT_CREATE = "EVENT_CREATE"
|
||||
EVENT_UPDATE = "EVENT_UPDATE"
|
||||
EVENT_DELETE = "EVENT_DELETE"
|
||||
|
||||
|
||||
class AuditLogResponse(BaseModel):
|
||||
id: int
|
||||
admin_id: int
|
||||
admin_username: str
|
||||
action: str
|
||||
target_type: Optional[str] = None
|
||||
target_id: Optional[int] = None
|
||||
description: str
|
||||
details: Optional[str] = None
|
||||
ip_address: Optional[str] = None
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class AuditLogListResponse(BaseModel):
|
||||
logs: list[AuditLogResponse]
|
||||
total: int
|
||||
page: int
|
||||
page_size: int
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Data Wiper Schemas
|
||||
# ============================================================
|
||||
|
||||
class WipePreviewResponse(BaseModel):
|
||||
"""Preview of what will be deleted in a wipe operation."""
|
||||
users_count: int
|
||||
wallets_count: int
|
||||
transactions_count: int
|
||||
bets_count: int
|
||||
spread_bets_count: int
|
||||
events_count: int
|
||||
event_comments_count: int
|
||||
match_comments_count: int
|
||||
admin_settings_preserved: bool = True
|
||||
admin_users_preserved: bool = True
|
||||
can_wipe: bool = True
|
||||
cooldown_remaining_seconds: int = 0
|
||||
last_wipe_at: Optional[datetime] = None
|
||||
|
||||
|
||||
class WipeRequest(BaseModel):
|
||||
"""Request to execute a data wipe."""
|
||||
confirmation_phrase: str = Field(..., description="Must be exactly 'CONFIRM WIPE'")
|
||||
preserve_admin_users: bool = Field(default=True, description="Keep admin users and their wallets")
|
||||
preserve_events: bool = Field(default=False, description="Keep sport events but delete bets")
|
||||
|
||||
|
||||
class WipeResponse(BaseModel):
|
||||
"""Response after a successful wipe operation."""
|
||||
success: bool
|
||||
message: str
|
||||
deleted_counts: dict[str, int]
|
||||
preserved_counts: dict[str, int]
|
||||
executed_at: datetime
|
||||
executed_by: str
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Data Seeder Schemas
|
||||
# ============================================================
|
||||
|
||||
class SeedRequest(BaseModel):
|
||||
"""Request to seed the database with test data."""
|
||||
num_users: int = Field(default=10, ge=1, le=100, description="Number of users to create")
|
||||
num_events: int = Field(default=5, ge=0, le=50, description="Number of sport events to create")
|
||||
num_bets_per_event: int = Field(default=3, ge=0, le=20, description="Average bets per event")
|
||||
starting_balance: Decimal = Field(default=Decimal("1000.00"), ge=Decimal("100"), le=Decimal("10000"))
|
||||
create_admin: bool = Field(default=True, description="Create a test admin user")
|
||||
|
||||
|
||||
class SeedResponse(BaseModel):
|
||||
"""Response after seeding the database."""
|
||||
success: bool
|
||||
message: str
|
||||
created_counts: dict[str, int]
|
||||
test_admin: Optional[dict] = None # Contains username/password if admin created
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Simulation Schemas
|
||||
# ============================================================
|
||||
|
||||
class SimulationConfig(BaseModel):
|
||||
"""Configuration for activity simulation."""
|
||||
delay_seconds: float = Field(default=2.0, ge=0.5, le=30.0, description="Delay between actions")
|
||||
actions_per_iteration: int = Field(default=3, ge=1, le=10, description="Actions per iteration")
|
||||
create_users: bool = Field(default=True, description="Allow creating new users")
|
||||
create_bets: bool = Field(default=True, description="Allow creating bets")
|
||||
take_bets: bool = Field(default=True, description="Allow taking/matching bets")
|
||||
add_comments: bool = Field(default=True, description="Allow adding comments")
|
||||
cancel_bets: bool = Field(default=True, description="Allow cancelling bets")
|
||||
|
||||
|
||||
class SimulationStatusResponse(BaseModel):
|
||||
"""Response with current simulation status."""
|
||||
is_running: bool
|
||||
started_at: Optional[datetime] = None
|
||||
started_by: Optional[str] = None
|
||||
iterations_completed: int = 0
|
||||
config: Optional[SimulationConfig] = None
|
||||
last_activity: Optional[str] = None
|
||||
|
||||
|
||||
class SimulationStartRequest(BaseModel):
|
||||
"""Request to start simulation."""
|
||||
config: Optional[SimulationConfig] = None
|
||||
|
||||
|
||||
class SimulationStartResponse(BaseModel):
|
||||
"""Response after starting simulation."""
|
||||
success: bool
|
||||
message: str
|
||||
status: SimulationStatusResponse
|
||||
|
||||
|
||||
class SimulationStopResponse(BaseModel):
|
||||
"""Response after stopping simulation."""
|
||||
success: bool
|
||||
message: str
|
||||
total_iterations: int
|
||||
ran_for_seconds: float
|
||||
|
||||
|
||||
# ============================================================
|
||||
# User Management Schemas
|
||||
# ============================================================
|
||||
|
||||
class AdminUserListItem(BaseModel):
|
||||
"""User item in admin user list."""
|
||||
id: int
|
||||
email: str
|
||||
username: str
|
||||
display_name: Optional[str] = None
|
||||
is_admin: bool
|
||||
status: str
|
||||
balance: Decimal
|
||||
escrow: Decimal
|
||||
total_bets: int
|
||||
wins: int
|
||||
losses: int
|
||||
win_rate: float
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class AdminUserListResponse(BaseModel):
|
||||
"""Paginated list of users."""
|
||||
users: list[AdminUserListItem]
|
||||
total: int
|
||||
page: int
|
||||
page_size: int
|
||||
|
||||
|
||||
class AdminUserDetailResponse(BaseModel):
|
||||
"""Detailed user info for admin."""
|
||||
id: int
|
||||
email: str
|
||||
username: str
|
||||
display_name: Optional[str] = None
|
||||
avatar_url: Optional[str] = None
|
||||
bio: Optional[str] = None
|
||||
is_admin: bool
|
||||
status: str
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
# Wallet info
|
||||
balance: Decimal
|
||||
escrow: Decimal
|
||||
# Stats
|
||||
total_bets: int
|
||||
wins: int
|
||||
losses: int
|
||||
win_rate: float
|
||||
# Counts
|
||||
open_bets_count: int
|
||||
matched_bets_count: int
|
||||
transaction_count: int
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class AdminUserUpdateRequest(BaseModel):
|
||||
"""Request to update user details."""
|
||||
display_name: Optional[str] = None
|
||||
email: Optional[str] = None
|
||||
is_admin: Optional[bool] = None
|
||||
|
||||
|
||||
class AdminUserStatusRequest(BaseModel):
|
||||
"""Request to change user status."""
|
||||
status: Literal["active", "suspended"]
|
||||
reason: Optional[str] = None
|
||||
|
||||
|
||||
class AdminBalanceAdjustRequest(BaseModel):
|
||||
"""Request to adjust user balance."""
|
||||
amount: Decimal = Field(..., description="Positive to add, negative to subtract")
|
||||
reason: str = Field(..., min_length=5, max_length=500, description="Reason for adjustment")
|
||||
|
||||
|
||||
class AdminBalanceAdjustResponse(BaseModel):
|
||||
"""Response after balance adjustment."""
|
||||
success: bool
|
||||
user_id: int
|
||||
username: str
|
||||
previous_balance: Decimal
|
||||
adjustment: Decimal
|
||||
new_balance: Decimal
|
||||
reason: str
|
||||
transaction_id: int
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Admin Dashboard Stats
|
||||
# ============================================================
|
||||
|
||||
class AdminDashboardStats(BaseModel):
|
||||
"""Dashboard statistics for admin panel."""
|
||||
total_users: int
|
||||
active_users: int
|
||||
suspended_users: int
|
||||
admin_users: int
|
||||
total_events: int
|
||||
upcoming_events: int
|
||||
live_events: int
|
||||
total_bets: int
|
||||
open_bets: int
|
||||
matched_bets: int
|
||||
total_volume: Decimal
|
||||
escrow_locked: Decimal
|
||||
simulation_running: bool
|
||||
@ -42,6 +42,7 @@ class UserResponse(BaseModel):
|
||||
losses: int
|
||||
win_rate: float
|
||||
status: UserStatus
|
||||
is_admin: bool = False
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
Reference in New Issue
Block a user