"""Pydantic schemas for admin panel endpoints.""" from datetime import datetime from typing import Optional from uuid import UUID from pydantic import BaseModel, Field # --- Dashboard --- class DashboardMetrics(BaseModel): total_users: int active_subscriptions: int paid_accounts: int total_trees: int class ActivityEntry(BaseModel): id: UUID user_email: Optional[str] = None action: str resource_type: str resource_id: Optional[UUID] = None details: Optional[dict] = None ip_address: Optional[str] = None created_at: datetime class Config: from_attributes = True # --- Audit Logs --- class AuditLogEntry(BaseModel): id: UUID user_id: UUID user_email: Optional[str] = None action: str resource_type: str resource_id: Optional[UUID] = None details: Optional[dict] = None ip_address: Optional[str] = None created_at: datetime class Config: from_attributes = True class AuditLogListResponse(BaseModel): items: list[AuditLogEntry] total: int page: int per_page: int # --- Plan Limits --- class PlanLimitResponse(BaseModel): plan: str max_trees: Optional[int] = None max_sessions_per_month: Optional[int] = None max_users: Optional[int] = None custom_branding: bool = False priority_support: bool = False export_formats: list = [] class Config: from_attributes = True class PlanLimitUpdate(BaseModel): plan: str max_trees: Optional[int] = None max_sessions_per_month: Optional[int] = None max_users: Optional[int] = None custom_branding: bool = False priority_support: bool = False export_formats: list = Field(default_factory=lambda: ["markdown", "text"]) class AccountOverrideCreate(BaseModel): account_display_code: str = Field(..., description="Account display code to look up") override_max_trees: Optional[int] = None override_max_sessions_per_month: Optional[int] = None override_max_users: Optional[int] = None note: Optional[str] = None class AccountOverrideUpdate(BaseModel): override_max_trees: Optional[int] = None override_max_sessions_per_month: Optional[int] = None override_max_users: Optional[int] = None note: Optional[str] = None class AccountOverrideResponse(BaseModel): id: UUID account_id: UUID account_name: Optional[str] = None account_display_code: Optional[str] = None override_max_trees: Optional[int] = None override_max_sessions_per_month: Optional[int] = None override_max_users: Optional[int] = None note: Optional[str] = None created_at: datetime updated_at: datetime class Config: from_attributes = True # --- Feature Flags --- class FeatureFlagCreate(BaseModel): flag_key: str = Field(..., max_length=100) display_name: str = Field(..., max_length=255) description: Optional[str] = None class FeatureFlagUpdate(BaseModel): display_name: Optional[str] = None description: Optional[str] = None class PlanDefaultEntry(BaseModel): plan: str enabled: bool class FeatureFlagResponse(BaseModel): id: UUID flag_key: str display_name: str description: Optional[str] = None plan_defaults: list[PlanDefaultEntry] = [] created_at: datetime class Config: from_attributes = True class PlanDefaultUpdate(BaseModel): plan: str flag_id: UUID enabled: bool class AccountFeatureOverrideCreate(BaseModel): account_display_code: str flag_id: UUID enabled: bool note: Optional[str] = None class AccountFeatureOverrideResponse(BaseModel): id: UUID account_id: UUID account_display_code: Optional[str] = None flag_id: UUID flag_key: Optional[str] = None flag_display_name: Optional[str] = None enabled: bool note: Optional[str] = None created_at: datetime class Config: from_attributes = True # --- Platform Settings --- class SettingsResponse(BaseModel): settings: dict class SettingsUpdate(BaseModel): settings: dict = Field(..., description="Key-value pairs to update") # --- Global Categories --- class GlobalCategoryCreate(BaseModel): name: str = Field(..., min_length=1, max_length=100) slug: str = Field(..., min_length=1, max_length=100) description: Optional[str] = None class GlobalCategoryUpdate(BaseModel): name: Optional[str] = Field(None, max_length=100) slug: Optional[str] = Field(None, max_length=100) description: Optional[str] = None class GlobalCategoryResponse(BaseModel): id: UUID name: str slug: str description: Optional[str] = None account_id: Optional[UUID] = None tree_count: int = 0 class Config: from_attributes = True # --- Move User --- class MoveUserAccount(BaseModel): display_code: str = Field(..., description="Target account display code")