from pydantic import BaseModel, Field from typing import Optional, List, Any, Dict from datetime import datetime # --- Auth Schemas --- class LoginRequest(BaseModel): email: str password: str class TokenResponse(BaseModel): access_token: str token_type: str = "bearer" user: Dict[str, Any] class UserResponse(BaseModel): id: int email: str full_name: Optional[str] role: str is_active: bool created_at: datetime model_config = {"from_attributes": True} # --- Client Schemas --- class RegistrationCodeCreate(BaseModel): client_name_hint: Optional[str] = None expires_in_hours: int = 48 class RegistrationCodeResponse(BaseModel): id: int code: str expires_at: datetime client_name_hint: Optional[str] client_id: Optional[int] = None class ClientRegisterRequest(BaseModel): registration_code: str name: str hostname: str os_info: Optional[str] = None agent_version: str = "1.0.0" class ClientRegisterResponse(BaseModel): client_code: str device_id: str device_token: str name: str server_time: datetime class ClientHeartbeatRequest(BaseModel): status: str = "ONLINE" # ONLINE, OFFLINE, SYNCING, ERROR agent_version: Optional[str] = None ip_address: Optional[str] = None class ClientUpdateRequest(BaseModel): alias: Optional[str] = None storage_quota_bytes: Optional[int] = None class ClientResponse(BaseModel): id: int client_code: str name: str alias: Optional[str] hostname: Optional[str] os_info: Optional[str] ip_address: Optional[str] agent_version: str status: str storage_used_bytes: int storage_quota_bytes: int last_seen_at: Optional[datetime] last_backup_at: Optional[datetime] is_active: bool created_at: datetime model_config = {"from_attributes": True} # --- Backup Job Schemas --- class JobCreate(BaseModel): client_id: int name: str source_path: str file_patterns: str = "*.bak,*.mdf" schedule_cron: str = "0 2 * * *" keep_daily: int = 7 keep_weekly: int = 4 keep_monthly: int = 12 min_stable_time_seconds: int = 60 class JobUpdate(BaseModel): name: Optional[str] = None source_path: Optional[str] = None file_patterns: Optional[str] = None schedule_cron: Optional[str] = None is_active: Optional[bool] = None keep_daily: Optional[int] = None keep_weekly: Optional[int] = None keep_monthly: Optional[int] = None min_stable_time_seconds: Optional[int] = None class JobResponse(BaseModel): id: int job_code: str client_id: int name: str source_path: str file_patterns: str schedule_cron: str is_active: bool keep_daily: int keep_weekly: int keep_monthly: int min_stable_time_seconds: int status: str last_run_at: Optional[datetime] next_run_at: Optional[datetime] created_at: datetime model_config = {"from_attributes": True} # --- Upload Session & Chunk Schemas --- class UploadSessionInitRequest(BaseModel): filename: str file_size: int sha256: str chunk_size: int = 4 * 1024 * 1024 job_id: Optional[int] = None class UploadSessionInitResponse(BaseModel): session_code: str filename: str file_size: int chunk_size: int total_chunks: int received_chunks: List[int] status: str class UploadSessionStatusResponse(BaseModel): session_code: str filename: str file_size: int chunk_size: int total_chunks: int received_chunks: List[int] missing_chunks: List[int] status: str progress_percent: float class ChunkUploadResponse(BaseModel): chunk_index: int is_received: bool total_received: int total_chunks: int progress_percent: float class UploadSessionCompleteResponse(BaseModel): session_code: str filename: str relative_path: str file_size: int sha256: str status: str completed_at: datetime # --- Backup File Schemas --- class BackupFileResponse(BaseModel): id: int client_id: int job_id: Optional[int] session_id: Optional[int] filename: str relative_path: str file_size: int sha256: str retention_tag: str is_active: bool created_at: datetime model_config = {"from_attributes": True} # --- Event Log Schemas --- class EventLogResponse(BaseModel): id: int timestamp: datetime event_type: str severity: str client_id: Optional[int] job_id: Optional[int] user_email: Optional[str] ip_address: Optional[str] message: str details_json: Optional[str] model_config = {"from_attributes": True} # --- Dashboard & Storage Stats --- class StorageStatsResponse(BaseModel): total_bytes: int used_bytes: int free_bytes: int usage_percent: float storage_root: str class DashboardStatsResponse(BaseModel): total_clients: int online_clients: int offline_clients: int total_jobs: int backups_today_count: int backups_today_success: int backups_today_failed: int active_uploads_count: int storage: StorageStatsResponse # --- System Settings Schemas --- class SystemSettingsResponse(BaseModel): storage_root: str global_quota_gb: int default_client_quota_gb: int default_keep_daily: int default_keep_weekly: int default_keep_monthly: int class SystemSettingsUpdate(BaseModel): storage_root: Optional[str] = None global_quota_gb: Optional[int] = None default_client_quota_gb: Optional[int] = None default_keep_daily: Optional[int] = None default_keep_weekly: Optional[int] = None default_keep_monthly: Optional[int] = None class AgentJobRegister(BaseModel): name: str source_path: str file_patterns: str = "*.bak,*.mdf" schedule_cron: str = "daily" keep_daily: int = 7 keep_weekly: int = 4 keep_monthly: int = 12 min_stable_time_seconds: int = 60