from fastapi import APIRouter, HTTPException from pydantic import BaseModel from modules.config_manager import ConfigManager from routers.ws import broadcast router = APIRouter(prefix="/api/admin", tags=["admin"]) # Will be set from main.py config: ConfigManager = None # type: ignore def init(cfg: ConfigManager) -> None: global config config = cfg # ── Pydantic models ───────────────────────────────────────── class DisplaySettings(BaseModel): resolution: str | None = None rotation_interval_seconds: int | None = None transition: str | None = None theme: str | None = None active_views: list[str] | None = None class OdooSettings(BaseModel): url: str | None = None database: str | None = None username: str | None = None password: str | None = None exclude_company_ids: list[int] | None = None class RefreshSettings(BaseModel): odoo_minutes: int | None = None network_minutes: int | None = None ping_seconds: int | None = None class NodeModel(BaseModel): name: str ip: str username: str | None = None password: str | None = None public_url: str | None = None icon: str = "device" type: str | None = None parent: str | None = None connections: list[str] = [] # ── Settings endpoints ────────────────────────────────────── @router.get("/settings") async def get_settings(): return config.get_settings() @router.put("/settings/display") async def update_display(body: DisplaySettings): values = body.model_dump(exclude_none=True) result = config.update_settings("display", values) await broadcast("config_changed", {"section": "display"}) return result @router.put("/settings/odoo") async def update_odoo(body: OdooSettings): values = body.model_dump(exclude_none=True) result = config.update_settings("odoo", values) await broadcast("config_changed", {"section": "odoo"}) return result @router.put("/settings/refresh") async def update_refresh(body: RefreshSettings): values = body.model_dump(exclude_none=True) result = config.update_settings("refresh", values) await broadcast("config_changed", {"section": "refresh"}) return result # ── Node endpoints ────────────────────────────────────────── @router.get("/nodes") async def get_nodes(): return config.get_nodes() @router.post("/nodes", status_code=201) async def add_node(body: NodeModel): nodes = config.get_nodes() for n in nodes: if n["ip"] == body.ip: raise HTTPException(400, f"Node with IP {body.ip} already exists") nodes.append(body.model_dump(exclude_none=True)) config.save_nodes(nodes) await broadcast("config_changed", {"section": "nodes"}) return body.model_dump(exclude_none=True) @router.put("/nodes") async def replace_nodes(body: list[NodeModel]): nodes = [n.model_dump(exclude_none=True) for n in body] config.save_nodes(nodes) await broadcast("config_changed", {"section": "nodes"}) return nodes @router.delete("/nodes/{ip}") async def delete_node(ip: str): nodes = config.get_nodes() original_len = len(nodes) nodes = [n for n in nodes if n.get("ip") != ip] if len(nodes) == original_len: raise HTTPException(404, f"Node with IP {ip} not found") config.save_nodes(nodes) await broadcast("config_changed", {"section": "nodes"}) return {"deleted": ip}