| @@ -26,4 +26,5 @@ ALARM_JSON_PATH = DATA_DIR / "active_alarm.json" | |||||
| TRACK_JSON_PATH = DATA_DIR / "tracks.json" | TRACK_JSON_PATH = DATA_DIR / "tracks.json" | ||||
| TRACKER_ZONE_JSON_PATH = DATA_DIR / "tracker_zone.json" | TRACKER_ZONE_JSON_PATH = DATA_DIR / "tracker_zone.json" | ||||
| SETTING_JSON_PATH = DATA_DIR / "settings.json" | SETTING_JSON_PATH = DATA_DIR / "settings.json" | ||||
| GUI_CONFIG_JSON_PATH = DATA_DIR / "gui_config.json" | |||||
| @@ -0,0 +1,72 @@ | |||||
| import json | |||||
| from typing import List, Dict, Any, Optional | |||||
| from fastapi.encoders import jsonable_encoder | |||||
| from schemas.reslevis import GuiConfigItem | |||||
| from .config import GUI_CONFIG_JSON_PATH | |||||
| from .gateway import _LockedFile, _atomic_write, _norm_str, _index_by_id | |||||
| class GuiConfigJsonRepository: | |||||
| def __init__(self, json_path: str = GUI_CONFIG_JSON_PATH): | |||||
| self.path = json_path | |||||
| def _read_all(self) -> List[Dict[str, Any]]: | |||||
| with _LockedFile(self.path, "r") as fp: | |||||
| try: | |||||
| fp.seek(0) | |||||
| data = fp.read().strip() | |||||
| return json.loads(data) if data else [] | |||||
| except json.JSONDecodeError: | |||||
| return [] | |||||
| def _write_all(self, rows: List[Dict[str, Any]]) -> None: | |||||
| payload = json.dumps(rows, ensure_ascii=False, indent=2) | |||||
| _atomic_write(self.path, payload) | |||||
| def list(self, search_string: Optional[str] = None) -> List[Dict[str, Any]]: | |||||
| rows = self._read_all() | |||||
| if search_string: | |||||
| s = search_string.lower() | |||||
| rows = [ | |||||
| r | |||||
| for r in rows | |||||
| if any( | |||||
| isinstance(r.get(k), str) and s in (r.get(k) or "").lower() | |||||
| for k in ("id", "name", "role") | |||||
| ) | |||||
| ] | |||||
| return rows | |||||
| def add(self, item: GuiConfigItem) -> None: | |||||
| rows = self._read_all() | |||||
| obj = jsonable_encoder(item) | |||||
| obj_id = _norm_str(obj.get("id")) | |||||
| if any(_norm_str(r.get("id")) == obj_id for r in rows): | |||||
| raise ValueError(f"GuiConfig con id '{obj_id}' già presente") | |||||
| rows.append(obj) | |||||
| self._write_all(rows) | |||||
| def update(self, item: GuiConfigItem) -> None: | |||||
| rows = self._read_all() | |||||
| obj = jsonable_encoder(item) | |||||
| obj_id = _norm_str(obj.get("id")) | |||||
| idx = _index_by_id(rows, obj_id) | |||||
| if idx is None: | |||||
| raise ValueError(f"GuiConfig con id '{obj_id}' non trovato") | |||||
| rows[idx] = obj | |||||
| self._write_all(rows) | |||||
| def remove(self, gui_config_id: str) -> None: | |||||
| rows = self._read_all() | |||||
| idx = _index_by_id(rows, gui_config_id) | |||||
| if idx is None: | |||||
| raise ValueError(f"GuiConfig con id '{gui_config_id}' non trovato") | |||||
| del rows[idx] | |||||
| self._write_all(rows) | |||||
| @@ -23,6 +23,7 @@ from schemas.reslevis import ( | |||||
| TrackHistoryItem, | TrackHistoryItem, | ||||
| TrackerZoneItem, | TrackerZoneItem, | ||||
| SettingItem, | SettingItem, | ||||
| GuiConfigItem, | |||||
| ) | ) | ||||
| from logica_reslevis.gateway import GatewayJsonRepository | from logica_reslevis.gateway import GatewayJsonRepository | ||||
| @@ -33,6 +34,7 @@ from logica_reslevis.zone_area_definition import ZoneAreaDefinitionJsonRepositor | |||||
| from logica_reslevis.tracker import TrackerJsonRepository | from logica_reslevis.tracker import TrackerJsonRepository | ||||
| from logica_reslevis.operator import OperatorJsonRepository | from logica_reslevis.operator import OperatorJsonRepository | ||||
| from logica_reslevis.setting import SettingJsonRepository | from logica_reslevis.setting import SettingJsonRepository | ||||
| from logica_reslevis.gui_config import GuiConfigJsonRepository | |||||
| from logica_reslevis.subject import SubjectJsonRepository | from logica_reslevis.subject import SubjectJsonRepository | ||||
| from logica_reslevis.alarm import AlarmJsonRepository | from logica_reslevis.alarm import AlarmJsonRepository | ||||
| from logica_reslevis.track import TrackJsonRepository | from logica_reslevis.track import TrackJsonRepository | ||||
| @@ -87,6 +89,7 @@ alarm_repo = AlarmJsonRepository() | |||||
| track_repo = TrackJsonRepository() | track_repo = TrackJsonRepository() | ||||
| tracker_zone_repo = TrackerZoneJsonRepository() | tracker_zone_repo = TrackerZoneJsonRepository() | ||||
| setting_repo = SettingJsonRepository() | setting_repo = SettingJsonRepository() | ||||
| gui_config_repo = GuiConfigJsonRepository() | |||||
| def _none_if_empty(v): | def _none_if_empty(v): | ||||
| return None if v in ("", None, 0, "0") else v | return None if v in ("", None, 0, "0") else v | ||||
| @@ -591,3 +594,31 @@ def updateSetting(item: SettingItem): | |||||
| def removeSetting(setting_id: str): | def removeSetting(setting_id: str): | ||||
| setting_repo.remove(setting_id) | setting_repo.remove(setting_id) | ||||
| return {"message": "OK"} | return {"message": "OK"} | ||||
| @router.get( | |||||
| "/getGuiConfigs", | |||||
| response_model=List[GuiConfigItem], | |||||
| tags=["Reslevis"], | |||||
| dependencies=[Depends(get_current_user)], | |||||
| ) | |||||
| def getGuiConfigs(): | |||||
| return gui_config_repo.list() | |||||
| @router.post("/postGuiConfig", tags=["Reslevis"], dependencies=[Depends(get_current_user)]) | |||||
| def postGuiConfig(item: GuiConfigItem): | |||||
| gui_config_repo.add(item) | |||||
| return {"message": "OK"} | |||||
| @router.put("/updateGuiConfig", tags=["Reslevis"], dependencies=[Depends(get_current_user)]) | |||||
| def updateGuiConfig(item: GuiConfigItem): | |||||
| gui_config_repo.update(item) | |||||
| return {"message": "OK"} | |||||
| @router.delete("/removeGuiConfig/{gui_config_id}", tags=["Reslevis"], dependencies=[Depends(get_current_user)]) | |||||
| def removeGuiConfig(gui_config_id: str): | |||||
| gui_config_repo.remove(gui_config_id) | |||||
| return {"message": "OK"} | |||||
| @@ -1,7 +1,7 @@ | |||||
| from pydantic import BaseModel | from pydantic import BaseModel | ||||
| from typing import Optional | from typing import Optional | ||||
| from uuid import UUID | from uuid import UUID | ||||
| from typing import Optional, Union | |||||
| from typing import Optional, Union, Literal | |||||
| from typing import List | from typing import List | ||||
| from typing import Tuple | from typing import Tuple | ||||
| @@ -82,6 +82,13 @@ class SettingItem(BaseModel): | |||||
| debugFields: Optional[List[str]] = None | debugFields: Optional[List[str]] = None | ||||
| language: str | language: str | ||||
| class GuiConfigItem(BaseModel): | |||||
| id: str | |||||
| name: Optional[str] = None | |||||
| role: Optional[Literal["developer", "administrator", "user"]] = None | |||||
| debug: Optional[bool] = None | |||||
| class OperatorItem(BaseModel): | class OperatorItem(BaseModel): | ||||
| id: UUID | id: UUID | ||||
| name: str | name: str | ||||