"""Nexus — Pydantic Request/Response Models Shared schemas for API validation, replacing raw `dict` parameters. """ from typing import Optional, List from pydantic import BaseModel, Field # ── Setting ── class SettingUpdatePayload(BaseModel): value: str = Field(..., min_length=0) # ── Agent ── class AgentHeartbeat(BaseModel): server_id: int is_online: bool = True system_info: Optional[dict] = None agent_version: Optional[str] = None class AgentExec(BaseModel): command: str = Field(..., min_length=1) timeout: int = Field(30, ge=1, le=300) sudo: bool = False # ── Server ── class ServerCreate(BaseModel): name: str = Field(..., min_length=1, max_length=100) domain: str = Field(..., min_length=1, max_length=255) port: int = Field(22, ge=1, le=65535) username: str = Field("root", max_length=100) auth_method: str = Field("key", pattern="^(key|password)$") password: Optional[str] = None ssh_key_path: Optional[str] = None ssh_key_private: Optional[str] = None ssh_key_public: Optional[str] = None agent_port: int = Field(8601, ge=1, le=65535) agent_api_key: Optional[str] = None description: Optional[str] = None target_path: Optional[str] = None category: Optional[str] = None platform_id: Optional[int] = None node_id: Optional[int] = None protocols: Optional[list] = None extra_attrs: Optional[dict] = None class ServerUpdate(BaseModel): name: Optional[str] = Field(None, min_length=1, max_length=100) domain: Optional[str] = Field(None, min_length=1, max_length=255) port: Optional[int] = Field(None, ge=1, le=65535) username: Optional[str] = None auth_method: Optional[str] = Field(None, pattern="^(key|password)$") password: Optional[str] = None ssh_key_path: Optional[str] = None ssh_key_private: Optional[str] = None ssh_key_public: Optional[str] = None agent_port: Optional[int] = Field(None, ge=1, le=65535) agent_api_key: Optional[str] = None description: Optional[str] = None target_path: Optional[str] = None category: Optional[str] = None platform_id: Optional[int] = None node_id: Optional[int] = None protocols: Optional[list] = None extra_attrs: Optional[dict] = None connectivity: Optional[str] = None class ServerPush(BaseModel): server_ids: List[int] = Field(..., min_length=1) source_path: str = Field(..., min_length=1) sync_mode: str = Field("incremental", pattern="^(incremental|full|overwrite|checksum)$") batch_size: int = Field(50, ge=1, le=200) concurrency: int = Field(10, ge=1, le=50) class ServerCheck(BaseModel): server_ids: List[int] = Field(..., min_length=1) # ── Sync ── class SyncFiles(BaseModel): server_ids: List[int] = Field(..., min_length=1) source_path: str = Field(..., min_length=1) target_path: Optional[str] = None sync_mode: str = Field("incremental", pattern="^(incremental|full|overwrite|checksum)$") batch_size: int = Field(50, ge=1, le=200) concurrency: int = Field(10, ge=1, le=50) class SyncCommands(BaseModel): server_ids: List[int] = Field(..., min_length=1) commands: List[str] = Field(..., min_length=1) timeout: int = Field(60, ge=1, le=600) concurrency: int = Field(10, ge=1, le=50) class SyncConfig(BaseModel): server_ids: List[int] = Field(..., min_length=1) config: dict = Field(..., min_length=1) concurrency: int = Field(10, ge=1, le=50) class SyncSftp(BaseModel): server_id: int operation: str = Field("put", pattern="^(put|get)$") local_path: str = Field(..., min_length=1) remote_path: str = Field(..., min_length=1) class SyncBrowse(BaseModel): server_id: int path: str = Field("/", min_length=1) # ── Script ── class ScriptCreate(BaseModel): name: str = Field(..., min_length=1, max_length=100) category: str = Field("ops", pattern="^(ops|deploy|check|cleanup)$") content: str = Field(..., min_length=1) description: Optional[str] = None created_by: Optional[str] = None class ScriptUpdate(BaseModel): name: Optional[str] = Field(None, min_length=1, max_length=100) category: Optional[str] = Field(None, pattern="^(ops|deploy|check|cleanup)$") content: Optional[str] = None description: Optional[str] = None class ScriptExecute(BaseModel): script_id: Optional[int] = None command: str = Field(..., min_length=1) server_ids: List[int] = Field(..., min_length=1) timeout: int = Field(60, ge=1, le=600) # ── DB Credential ── class DbCredentialCreate(BaseModel): name: str = Field(..., min_length=1, max_length=100) db_type: str = Field("mysql", pattern="^(mysql|postgresql|mariadb|mongodb|redis)$") host: str = Field(..., min_length=1) port: int = Field(3306, ge=1, le=65535) username: str = Field(..., min_length=1) password: str = Field(..., min_length=1) database: Optional[str] = None # ── Schedule ── class ScheduleCreate(BaseModel): name: str = Field(..., min_length=1, max_length=100) source_path: str = Field(..., min_length=1) server_ids: str = Field(..., min_length=3) # JSON array string cron_expr: str = Field(..., min_length=9, max_length=100) enabled: bool = True class ScheduleUpdate(BaseModel): name: Optional[str] = Field(None, min_length=1, max_length=100) source_path: Optional[str] = None server_ids: Optional[str] = None cron_expr: Optional[str] = None enabled: Optional[bool] = None # ── Preset ── class PresetCreate(BaseModel): name: str = Field(..., min_length=1, max_length=100) encrypted_pw: str = Field(..., min_length=1) # ── Platform / Node ── class PlatformCreate(BaseModel): name: str = Field(..., min_length=1, max_length=100) category: str = Field(..., min_length=1, max_length=50) type: str = Field(..., min_length=1, max_length=50) default_protocols: Optional[list] = None charset: str = "utf-8" class PlatformUpdate(BaseModel): name: Optional[str] = Field(None, min_length=1, max_length=100) category: Optional[str] = None type: Optional[str] = None default_protocols: Optional[list] = None charset: Optional[str] = None class NodeCreate(BaseModel): name: str = Field(..., min_length=1, max_length=100) parent_id: Optional[int] = None sort_order: int = 0 class NodeUpdate(BaseModel): name: Optional[str] = Field(None, min_length=1, max_length=100) parent_id: Optional[int] = None sort_order: Optional[int] = None # ── Pagination ── class PaginatedResponse(BaseModel): items: list total: int page: int per_page: int pages: int