feat: Add local system override with 24h timeout support
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import secrets
|
||||
from typing import Optional
|
||||
from fastapi import APIRouter, HTTPException, Depends, Query
|
||||
from pydantic import BaseModel
|
||||
from app.models import CommandPayload
|
||||
from app.internal import firestore as fstore
|
||||
from app.internal.mqtt_handler import mqtt_handler
|
||||
@@ -126,10 +127,13 @@ async def assign_system(
|
||||
if not system:
|
||||
raise HTTPException(404, f"System '{system_id}' not found.")
|
||||
|
||||
# Include hardware preset in the push so the edge node applies it when
|
||||
# generating the OP25 config. Strip it from the system doc first so it
|
||||
# doesn't collide with SystemConfig field validation on the node side.
|
||||
push_payload = {**system, "hardware_preset": hardware_preset}
|
||||
# Include hardware preset, node type, and enforce timeout in the push
|
||||
push_payload = {
|
||||
**system,
|
||||
"hardware_preset": hardware_preset,
|
||||
"node_type": node.get("node_type", "fixed"),
|
||||
"enforce_override_timeout": node.get("enforce_override_timeout", True),
|
||||
}
|
||||
if ppm_override is not None:
|
||||
push_payload["ppm_override"] = ppm_override
|
||||
mqtt_handler.push_config(node_id, push_payload)
|
||||
@@ -145,3 +149,89 @@ async def assign_system(
|
||||
await fstore.doc_update("nodes", node_id, node_updates)
|
||||
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
class NodeUpdateBody(BaseModel):
|
||||
node_type: Optional[str] = None
|
||||
enforce_override_timeout: Optional[bool] = None
|
||||
|
||||
|
||||
@router.patch("/{node_id}")
|
||||
async def update_node(
|
||||
node_id: str,
|
||||
body: NodeUpdateBody,
|
||||
_: dict = Depends(require_admin_token),
|
||||
):
|
||||
node = await fstore.doc_get("nodes", node_id)
|
||||
if not node:
|
||||
raise HTTPException(404, f"Node '{node_id}' not found.")
|
||||
|
||||
updates = body.model_dump(exclude_unset=True)
|
||||
if not updates:
|
||||
return {"ok": True}
|
||||
|
||||
await fstore.doc_update("nodes", node_id, updates)
|
||||
|
||||
# Re-push config to apply new node settings locally
|
||||
updated_node = await fstore.doc_get("nodes", node_id)
|
||||
assigned_system_id = updated_node.get("assigned_system_id")
|
||||
if assigned_system_id:
|
||||
system = await fstore.doc_get("systems", assigned_system_id)
|
||||
if system:
|
||||
push_payload = {
|
||||
**system,
|
||||
"hardware_preset": updated_node.get("hardware_preset", "rtl-sdr-v3"),
|
||||
"node_type": updated_node.get("node_type", "fixed"),
|
||||
"enforce_override_timeout": updated_node.get("enforce_override_timeout", True),
|
||||
}
|
||||
if updated_node.get("ppm_override") is not None:
|
||||
push_payload["ppm_override"] = updated_node["ppm_override"]
|
||||
mqtt_handler.push_config(node_id, push_payload)
|
||||
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
class AckOverrideBody(BaseModel):
|
||||
timeout_minutes: int = 1440
|
||||
|
||||
|
||||
@router.post("/{node_id}/override/ack")
|
||||
async def ack_override(
|
||||
node_id: str,
|
||||
body: AckOverrideBody,
|
||||
_: dict = Depends(require_service_key_or_admin),
|
||||
):
|
||||
node = await fstore.doc_get("nodes", node_id)
|
||||
if not node:
|
||||
raise HTTPException(404, f"Node '{node_id}' not found.")
|
||||
|
||||
from datetime import datetime, timezone, timedelta
|
||||
new_timeout = datetime.now(timezone.utc) + timedelta(minutes=body.timeout_minutes)
|
||||
|
||||
await fstore.doc_update("nodes", node_id, {
|
||||
"override_timeout_at": new_timeout.isoformat()
|
||||
})
|
||||
return {"ok": True, "override_timeout_at": new_timeout.isoformat()}
|
||||
|
||||
|
||||
@router.post("/{node_id}/override/reset")
|
||||
async def reset_override(
|
||||
node_id: str,
|
||||
_: dict = Depends(require_service_key_or_admin),
|
||||
):
|
||||
node = await fstore.doc_get("nodes", node_id)
|
||||
if not node:
|
||||
raise HTTPException(404, f"Node '{node_id}' not found.")
|
||||
|
||||
assigned_system_id = node.get("assigned_system_id")
|
||||
if assigned_system_id:
|
||||
system = await fstore.doc_get("systems", assigned_system_id)
|
||||
if system:
|
||||
mqtt_handler.push_config(node_id, system)
|
||||
|
||||
await fstore.doc_update("nodes", node_id, {
|
||||
"is_overridden": False,
|
||||
"override_system_id": None,
|
||||
"override_timeout_at": None,
|
||||
})
|
||||
return {"ok": True}
|
||||
|
||||
Reference in New Issue
Block a user