# models/schema/admin.py """ Admin-specific Pydantic schemas for API validation and responses. This module provides schemas for: - Admin audit logs - Admin notifications - Platform settings - Platform alerts - Bulk operations - System health checks """ from datetime import datetime from typing import Any from pydantic import BaseModel, Field, field_validator # ============================================================================ # ADMIN AUDIT LOG SCHEMAS # ============================================================================ class AdminAuditLogResponse(BaseModel): """Response model for admin audit logs.""" id: int admin_user_id: int admin_username: str | None = None action: str target_type: str target_id: str details: dict[str, Any] | None = None ip_address: str | None = None user_agent: str | None = None request_id: str | None = None created_at: datetime model_config = {"from_attributes": True} class AdminAuditLogFilters(BaseModel): """Filters for querying audit logs.""" admin_user_id: int | None = None action: str | None = None target_type: str | None = None date_from: datetime | None = None date_to: datetime | None = None skip: int = Field(0, ge=0) limit: int = Field(100, ge=1, le=1000) class AdminAuditLogListResponse(BaseModel): """Paginated list of audit logs.""" logs: list[AdminAuditLogResponse] total: int skip: int limit: int # ============================================================================ # ADMIN NOTIFICATION SCHEMAS # ============================================================================ class AdminNotificationCreate(BaseModel): """Create admin notification.""" type: str = Field(..., max_length=50, description="Notification type") priority: str = Field(default="normal", description="Priority level") title: str = Field(..., max_length=200) message: str = Field(..., description="Notification message") action_required: bool = Field(default=False) action_url: str | None = Field(None, max_length=500) metadata: dict[str, Any] | None = None @field_validator("priority") @classmethod def validate_priority(cls, v): allowed = ["low", "normal", "high", "critical"] if v not in allowed: raise ValueError(f"Priority must be one of: {', '.join(allowed)}") return v class AdminNotificationResponse(BaseModel): """Admin notification response.""" id: int type: str priority: str title: str message: str is_read: bool read_at: datetime | None = None read_by_user_id: int | None = None action_required: bool action_url: str | None = None metadata: dict[str, Any] | None = None created_at: datetime model_config = {"from_attributes": True} class AdminNotificationUpdate(BaseModel): """Mark notification as read.""" is_read: bool = True class AdminNotificationListResponse(BaseModel): """Paginated list of notifications.""" notifications: list[AdminNotificationResponse] total: int unread_count: int skip: int limit: int # ============================================================================ # ADMIN SETTINGS SCHEMAS # ============================================================================ class AdminSettingCreate(BaseModel): """Create or update admin setting.""" key: str = Field(..., max_length=100, description="Unique setting key") value: str = Field(..., description="Setting value") value_type: str = Field(default="string", description="Data type") category: str | None = Field(None, max_length=50) description: str | None = None is_encrypted: bool = Field(default=False) is_public: bool = Field(default=False, description="Can be exposed to frontend") @field_validator("value_type") @classmethod def validate_value_type(cls, v): allowed = ["string", "integer", "boolean", "json", "float"] if v not in allowed: raise ValueError(f"Value type must be one of: {', '.join(allowed)}") return v @field_validator("key") @classmethod def validate_key_format(cls, v): # Setting keys should be lowercase with underscores if not v.replace("_", "").isalnum(): raise ValueError( "Setting key must contain only letters, numbers, and underscores" ) return v.lower() class AdminSettingResponse(BaseModel): """Admin setting response.""" id: int key: str value: str value_type: str category: str | None = None description: str | None = None is_encrypted: bool is_public: bool last_modified_by_user_id: int | None = None updated_at: datetime model_config = {"from_attributes": True} class AdminSettingUpdate(BaseModel): """Update admin setting value.""" value: str description: str | None = None class AdminSettingListResponse(BaseModel): """List of settings by category.""" settings: list[AdminSettingResponse] total: int category: str | None = None # ============================================================================ # PLATFORM ALERT SCHEMAS # ============================================================================ class PlatformAlertCreate(BaseModel): """Create platform alert.""" alert_type: str = Field(..., max_length=50) severity: str = Field(..., description="Alert severity") title: str = Field(..., max_length=200) description: str | None = None affected_vendors: list[int] | None = None affected_systems: list[str] | None = None auto_generated: bool = Field(default=True) @field_validator("severity") @classmethod def validate_severity(cls, v): allowed = ["info", "warning", "error", "critical"] if v not in allowed: raise ValueError(f"Severity must be one of: {', '.join(allowed)}") return v @field_validator("alert_type") @classmethod def validate_alert_type(cls, v): allowed = [ "security", "performance", "capacity", "integration", "database", "system", ] if v not in allowed: raise ValueError(f"Alert type must be one of: {', '.join(allowed)}") return v class PlatformAlertResponse(BaseModel): """Platform alert response.""" id: int alert_type: str severity: str title: str description: str | None = None affected_vendors: list[int] | None = None affected_systems: list[str] | None = None is_resolved: bool resolved_at: datetime | None = None resolved_by_user_id: int | None = None resolution_notes: str | None = None auto_generated: bool occurrence_count: int first_occurred_at: datetime last_occurred_at: datetime created_at: datetime model_config = {"from_attributes": True} class PlatformAlertResolve(BaseModel): """Resolve platform alert.""" is_resolved: bool = True resolution_notes: str | None = None class PlatformAlertListResponse(BaseModel): """Paginated list of platform alerts.""" alerts: list[PlatformAlertResponse] total: int active_count: int critical_count: int skip: int limit: int # ============================================================================ # BULK OPERATION SCHEMAS # ============================================================================ class BulkVendorAction(BaseModel): """Bulk actions on vendors.""" vendor_ids: list[int] = Field(..., min_length=1, max_length=100) action: str = Field(..., description="Action to perform") confirm: bool = Field(default=False, description="Required for destructive actions") reason: str | None = Field(None, description="Reason for bulk action") @field_validator("action") @classmethod def validate_action(cls, v): allowed = ["activate", "deactivate", "verify", "unverify", "delete"] if v not in allowed: raise ValueError(f"Action must be one of: {', '.join(allowed)}") return v class BulkVendorActionResponse(BaseModel): """Response for bulk vendor actions.""" successful: list[int] failed: dict[int, str] # vendor_id -> error_message total_processed: int action_performed: str message: str class BulkUserAction(BaseModel): """Bulk actions on users.""" user_ids: list[int] = Field(..., min_length=1, max_length=100) action: str = Field(..., description="Action to perform") confirm: bool = Field(default=False) reason: str | None = None @field_validator("action") @classmethod def validate_action(cls, v): allowed = ["activate", "deactivate", "delete"] if v not in allowed: raise ValueError(f"Action must be one of: {', '.join(allowed)}") return v class BulkUserActionResponse(BaseModel): """Response for bulk user actions.""" successful: list[int] failed: dict[int, str] total_processed: int action_performed: str message: str # ============================================================================ # ADMIN DASHBOARD SCHEMAS # ============================================================================ class AdminDashboardStats(BaseModel): """Comprehensive admin dashboard statistics.""" platform: dict[str, Any] users: dict[str, Any] vendors: dict[str, Any] products: dict[str, Any] orders: dict[str, Any] imports: dict[str, Any] recent_vendors: list[dict[str, Any]] recent_imports: list[dict[str, Any]] unread_notifications: int active_alerts: int critical_alerts: int # ============================================================================ # SYSTEM HEALTH SCHEMAS # ============================================================================ class ComponentHealthStatus(BaseModel): """Health status for a system component.""" status: str # healthy, degraded, unhealthy response_time_ms: float | None = None error_message: str | None = None last_checked: datetime details: dict[str, Any] | None = None class SystemHealthResponse(BaseModel): """System health check response.""" overall_status: str # healthy, degraded, critical database: ComponentHealthStatus redis: ComponentHealthStatus celery: ComponentHealthStatus storage: ComponentHealthStatus api_response_time_ms: float uptime_seconds: int timestamp: datetime # ============================================================================ # ADMIN SESSION SCHEMAS # ============================================================================ class AdminSessionResponse(BaseModel): """Admin session information.""" id: int admin_user_id: int admin_username: str | None = None ip_address: str user_agent: str | None = None login_at: datetime last_activity_at: datetime logout_at: datetime | None = None is_active: bool logout_reason: str | None = None model_config = {"from_attributes": True} class AdminSessionListResponse(BaseModel): """List of admin sessions.""" sessions: list[AdminSessionResponse] total: int active_count: int