Parcourir la source

plan replacement and parameter fixes

proxy2core
root il y a 1 mois
Parent
révision
3dc032b2d3
15 fichiers modifiés avec 213 ajouts et 629 suppressions
  1. BIN
      logica_reslevis/__pycache__/config.cpython-310.pyc
  2. BIN
      logica_reslevis/__pycache__/floor.cpython-310.pyc
  3. BIN
      logica_reslevis/__pycache__/tracker_zone.cpython-310.pyc
  4. BIN
      logica_reslevis/__pycache__/zone.cpython-310.pyc
  5. +10
    -9
      logica_reslevis/config.py
  6. +11
    -11
      logica_reslevis/floor.py
  7. +76
    -0
      logica_reslevis/tracker_zone.py
  8. BIN
      models/__pycache__/gateway_item.cpython-310.pyc
  9. +6
    -6
      models/floor_item.py
  10. +7
    -14
      models/gateway_item.py
  11. BIN
      routes/__pycache__/reslevis.cpython-310.pyc
  12. +84
    -471
      routes/reslevis.py
  13. BIN
      schemas/__pycache__/reslevis.cpython-310.pyc
  14. +19
    -13
      schemas/reslevis.py
  15. +0
    -105
      security.py.ok

BIN
logica_reslevis/__pycache__/config.cpython-310.pyc Voir le fichier


BIN
logica_reslevis/__pycache__/floor.cpython-310.pyc Voir le fichier


BIN
logica_reslevis/__pycache__/tracker_zone.cpython-310.pyc Voir le fichier


BIN
logica_reslevis/__pycache__/zone.cpython-310.pyc Voir le fichier


+ 10
- 9
logica_reslevis/config.py Voir le fichier

@@ -14,13 +14,14 @@ DATA_DIR = Path(
)

# Percorsi dei file JSON
GATEWAY_JSON_PATH = DATA_DIR / "Gateway.json"
BUILDING_JSON_PATH = DATA_DIR / "Building.json"
PLAN_JSON_PATH = DATA_DIR / "Plan.json"
ZONE_JSON_PATH = DATA_DIR / "Zone.json"
TRACKER_JSON_PATH = DATA_DIR / "Tracker.json"
OPERATOR_JSON_PATH = DATA_DIR / "Operator.json"
SUBJECT_JSON_PATH = DATA_DIR / "Subject.json"
ALARM_JSON_PATH = DATA_DIR / "Alarm.json"
TRACK_JSON_PATH = DATA_DIR / "Track.json"
GATEWAY_JSON_PATH = DATA_DIR / "gateway_list.json"
BUILDING_JSON_PATH = DATA_DIR / "building.json"
FLOOR_JSON_PATH = DATA_DIR / "floors.json"
ZONE_JSON_PATH = DATA_DIR / "zone_list.json"
TRACKER_JSON_PATH = DATA_DIR / "tracker_conf.json"
OPERATOR_JSON_PATH = DATA_DIR / "oper_conf.json"
SUBJECT_JSON_PATH = DATA_DIR / "subject.json"
ALARM_JSON_PATH = DATA_DIR / "active_alarm.json"
TRACK_JSON_PATH = DATA_DIR / "tracks.json"
TRACKER_ZONE_JSON_PATH = DATA_DIR / "tracker_zone.json"


logica_reslevis/plan.py → logica_reslevis/floor.py Voir le fichier

@@ -3,13 +3,13 @@ from typing import List, Dict, Any, Optional

from fastapi.encoders import jsonable_encoder

from schemas.reslevis import PlanItem
from .config import PLAN_JSON_PATH
from schemas.reslevis import FloorItem
from .config import FLOOR_JSON_PATH
from .gateway import _LockedFile, _atomic_write, _norm_str, _index_by_id


class PlanJsonRepository:
def __init__(self, json_path: str = PLAN_JSON_PATH):
class FloorJsonRepository:
def __init__(self, json_path: str = FLOOR_JSON_PATH):
self.path = json_path

def _read_all(self) -> List[Dict[str, Any]]:
@@ -39,34 +39,34 @@ class PlanJsonRepository:
]
return rows

def add(self, item: PlanItem) -> None:
def add(self, item: FloorItem) -> 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"Plan con id '{obj_id}' già presente")
raise ValueError(f"Floor con id '{obj_id}' già presente")

rows.append(obj)
self._write_all(rows)

def update(self, item: PlanItem) -> None:
def update(self, item: FloorItem) -> 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"Plan con id '{obj_id}' non trovato")
raise ValueError(f"Floor con id '{obj_id}' non trovato")

rows[idx] = obj
self._write_all(rows)

def remove(self, plan_id: str) -> None:
def remove(self, floor_id: str) -> None:
rows = self._read_all()
idx = _index_by_id(rows, plan_id)
idx = _index_by_id(rows, floor_id)
if idx is None:
raise ValueError(f"Plan con id '{plan_id}' non trovato")
raise ValueError(f"Floor con id '{floor_id}' non trovato")

del rows[idx]
self._write_all(rows)

+ 76
- 0
logica_reslevis/tracker_zone.py Voir le fichier

@@ -0,0 +1,76 @@
import json
from typing import List, Dict, Any, Optional
from fastapi.encoders import jsonable_encoder

from schemas.reslevis import TrackerZoneItem
from .config import TRACKER_ZONE_JSON_PATH
from .gateway import _LockedFile, _atomic_write, _norm_str, _index_by_id


class TrackerZoneJsonRepository:
def __init__(self, json_path: str = TRACKER_ZONE_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 ("days", "time", "id", "tracker")
)
or any(
s in str(z).lower()
for z in (r.get("zoneList") or [])
)
]
return rows

def add(self, item: TrackerZoneItem) -> 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"TrackerZone con id '{obj_id}' già presente")

rows.append(obj)
self._write_all(rows)

def update(self, item: TrackerZoneItem) -> 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"TrackerZone con id '{obj_id}' non trovato")

rows[idx] = obj
self._write_all(rows)

def remove(self, tracker_zone_id: str) -> None:
rows = self._read_all()
idx = _index_by_id(rows, tracker_zone_id)
if idx is None:
raise ValueError(f"TrackerZone con id '{tracker_zone_id}' non trovato")

del rows[idx]
self._write_all(rows)


BIN
models/__pycache__/gateway_item.cpython-310.pyc Voir le fichier


models/plan_item.py → models/floor_item.py Voir le fichier

@@ -7,12 +7,12 @@ from attrs import field as _attrs_field

from app_types import UNSET, Unset

T = TypeVar("T", bound="PlanItem")
T = TypeVar("T", bound="FloorItem")


@_attrs_define
class PlanItem:
"""A plan is floor or a space of a building
class FloorItem:
"""A floor is space of a building

Attributes:
id (UUID): ID
@@ -77,7 +77,7 @@ class PlanItem:
else:
building = UUID(_building)

plan_item = cls(
floor_item = cls(
id=id,
name=name,
image=image,
@@ -85,8 +85,8 @@ class PlanItem:
building=building,
)

plan_item.additional_properties = d
return plan_item
floor_item.additional_properties = d
return floor_item

@property
def additional_keys(self) -> list[str]:

+ 7
- 14
models/gateway_item.py Voir le fichier

@@ -24,7 +24,7 @@ class GatewayItem:
position (Union[Unset, str]): Position
x (Union[Unset, float]): X
y (Union[Unset, float]): Y
zone (Union[Unset, UUID]): Zone
floor (Union[Unset, UUID]): Zone
building (Union[Unset, UUID]): Building
notes (Union[Unset, str]): Notes
"""
@@ -38,7 +38,7 @@ class GatewayItem:
position: Union[Unset, str] = UNSET
x: Union[Unset, float] = UNSET
y: Union[Unset, float] = UNSET
zone: Union[Unset, UUID] = UNSET
floor: UUID = UNSET
building: Union[Unset, UUID] = UNSET
notes: Union[Unset, str] = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
@@ -62,9 +62,7 @@ class GatewayItem:

y = self.y

zone: Union[Unset, str] = UNSET
if not isinstance(self.zone, Unset):
zone = str(self.zone)
floor = self.floor

building: Union[Unset, str] = UNSET
if not isinstance(self.building, Unset):
@@ -94,8 +92,8 @@ class GatewayItem:
field_dict["x"] = x
if y is not UNSET:
field_dict["y"] = y
if zone is not UNSET:
field_dict["zone"] = zone
if floor is not UNSET:
field_dict["floor"] = floor
if building is not UNSET:
field_dict["building"] = building
if notes is not UNSET:
@@ -124,12 +122,7 @@ class GatewayItem:

y = d.pop("y", UNSET)

_zone = d.pop("zone", UNSET)
zone: Union[Unset, UUID]
if isinstance(_zone, Unset):
zone = UNSET
else:
zone = UUID(_zone)
floor = d.pop("floor", UNSET)

_building = d.pop("building", UNSET)
building: Union[Unset, UUID]
@@ -150,7 +143,7 @@ class GatewayItem:
position=position,
x=x,
y=y,
zone=zone,
floor=floor,
building=building,
notes=notes,
)


BIN
routes/__pycache__/reslevis.cpython-310.pyc Voir le fichier


+ 84
- 471
routes/reslevis.py Voir le fichier

@@ -3,7 +3,7 @@ from typing import List

from schemas.reslevis import (
BuildingItem,
PlanItem,
FloorItem,
ZoneItem,
GatewayItem,
TrackerItem,
@@ -11,17 +11,19 @@ from schemas.reslevis import (
SubjectItem,
AlarmItem,
TrackItem,
TrackerZoneItem,
)

from logica_reslevis.gateway import GatewayJsonRepository
from logica_reslevis.building import BuildingJsonRepository
from logica_reslevis.plan import PlanJsonRepository
from logica_reslevis.floor import FloorJsonRepository
from logica_reslevis.zone import ZoneJsonRepository
from logica_reslevis.tracker import TrackerJsonRepository
from logica_reslevis.operator import OperatorJsonRepository
from logica_reslevis.subject import SubjectJsonRepository
from logica_reslevis.alarm import AlarmJsonRepository
from logica_reslevis.track import TrackJsonRepository
from logica_reslevis.tracker_zone import TrackerZoneJsonRepository

from security import get_current_user

@@ -29,13 +31,14 @@ router = APIRouter()

gateway_repo = GatewayJsonRepository()
building_repo = BuildingJsonRepository()
plan_repo = PlanJsonRepository()
floor_repo = FloorJsonRepository()
zone_repo = ZoneJsonRepository()
tracker_repo = TrackerJsonRepository()
operator_repo = OperatorJsonRepository()
subject_repo = SubjectJsonRepository()
alarm_repo = AlarmJsonRepository()
track_repo = TrackJsonRepository()
tracker_zone_repo = TrackerZoneJsonRepository()


@router.get(
@@ -43,61 +46,27 @@ track_repo = TrackJsonRepository()
response_model=List[GatewayItem],
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="getGateway",
)
def getGateways():
return gateway_repo.list()


@router.post(
"/postGateway",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="postGateway",
)
@router.post("/postGateway", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def postGateway(item: GatewayItem):
try:
gateway_repo.add(item)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=409, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")
gateway_repo.add(item)
return {"message": "OK"}


@router.put(
"/updateGateway",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="putGateway",
)
@router.put("/updateGateway", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def updateGateway(item: GatewayItem):
try:
gateway_repo.update(item)
return {"message": "OK"}
except ValueError as e:
msg = str(e)
if "non trovato" in msg:
raise HTTPException(status_code=404, detail=msg)
raise HTTPException(status_code=409, detail=msg)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.delete(
"/removeGateway/{gateway_id}",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="removeGateway",
)
gateway_repo.update(item)
return {"message": "OK"}


@router.delete("/removeGateway/{gateway_id}", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def removeGateway(gateway_id: str):
try:
gateway_repo.remove(gateway_id)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")
gateway_repo.remove(gateway_id)
return {"message": "OK"}


@router.get(
@@ -105,123 +74,55 @@ def removeGateway(gateway_id: str):
response_model=List[BuildingItem],
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="getBuilding",
)
def getBuildings():
return building_repo.list()


@router.post(
"/postBuilding",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="postBuilding",
)
@router.post("/postBuilding", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def postBuilding(item: BuildingItem):
try:
building_repo.add(item)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=409, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")
building_repo.add(item)
return {"message": "OK"}


@router.put(
"/updateBuilding",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="putBuilding",
)
@router.put("/updateBuilding", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def updateBuilding(item: BuildingItem):
try:
building_repo.update(item)
return {"message": "OK"}
except ValueError as e:
msg = str(e)
if "non trovato" in msg:
raise HTTPException(status_code=404, detail=msg)
raise HTTPException(status_code=409, detail=msg)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.delete(
"/removeBuilding/{building_id}",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="removeBuilding",
)
building_repo.update(item)
return {"message": "OK"}


@router.delete("/removeBuilding/{building_id}", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def removeBuilding(building_id: str):
try:
building_repo.remove(building_id)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")
building_repo.remove(building_id)
return {"message": "OK"}


@router.get(
"/getPlans",
response_model=List[PlanItem],
"/getFloors",
response_model=List[FloorItem],
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="getPlan",
)
def getPlans():
return plan_repo.list()
def getFloors():
return floor_repo.list()


@router.post(
"/postPlan",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="postPlan",
)
def postPlan(item: PlanItem):
try:
plan_repo.add(item)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=409, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.put(
"/updatePlan",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="putPlan",
)
def updatePlan(item: PlanItem):
try:
plan_repo.update(item)
return {"message": "OK"}
except ValueError as e:
msg = str(e)
if "non trovato" in msg:
raise HTTPException(status_code=404, detail=msg)
raise HTTPException(status_code=409, detail=msg)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.delete(
"/removePlan/{plan_id}",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="removePlan",
)
def removePlan(plan_id: str):
try:
plan_repo.remove(plan_id)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")
@router.post("/postFloor", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def postFloor(item: FloorItem):
floor_repo.add(item)
return {"message": "OK"}


@router.put("/updateFloor", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def updateFloor(item: FloorItem):
floor_repo.update(item)
return {"message": "OK"}


@router.delete("/removeFloor/{floor_id}", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def removeFloor(floor_id: str):
floor_repo.remove(floor_id)
return {"message": "OK"}


@router.get(
@@ -229,61 +130,27 @@ def removePlan(plan_id: str):
response_model=List[ZoneItem],
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="getZone",
)
def getZones():
return zone_repo.list()


@router.post(
"/postZone",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="postZone",
)
@router.post("/postZone", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def postZone(item: ZoneItem):
try:
zone_repo.add(item)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=409, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")
zone_repo.add(item)
return {"message": "OK"}


@router.put(
"/updateZone",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="putZone",
)
@router.put("/updateZone", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def updateZone(item: ZoneItem):
try:
zone_repo.update(item)
return {"message": "OK"}
except ValueError as e:
msg = str(e)
if "non trovato" in msg:
raise HTTPException(status_code=404, detail=msg)
raise HTTPException(status_code=409, detail=msg)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.delete(
"/removeZone/{zone_id}",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="removeZone",
)
zone_repo.update(item)
return {"message": "OK"}


@router.delete("/removeZone/{zone_id}", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def removeZone(zone_id: str):
try:
zone_repo.remove(zone_id)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")
zone_repo.remove(zone_id)
return {"message": "OK"}


@router.get(
@@ -291,307 +158,53 @@ def removeZone(zone_id: str):
response_model=List[TrackerItem],
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="getTracker",
)
def getTrackers():
return tracker_repo.list()


@router.post(
"/postTracker",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="postTracker",
)
@router.post("/postTracker", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def postTracker(item: TrackerItem):
try:
tracker_repo.add(item)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=409, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")
tracker_repo.add(item)
return {"message": "OK"}


@router.put(
"/updateTracker",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="putTracker",
)
@router.put("/updateTracker", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def updateTracker(item: TrackerItem):
try:
tracker_repo.update(item)
return {"message": "OK"}
except ValueError as e:
msg = str(e)
if "non trovato" in msg:
raise HTTPException(status_code=404, detail=msg)
raise HTTPException(status_code=409, detail=msg)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.delete(
"/removeTracker/{tracker_id}",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="removeTracker",
)
def removeTracker(tracker_id: str):
try:
tracker_repo.remove(tracker_id)
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")
tracker_repo.update(item)
return {"message": "OK"}


@router.get(
"/getOperators",
response_model=List[OperatorItem],
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="getOperator",
)
def getOperators():
return operator_repo.list()


@router.post(
"/postOperator",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="postOperator",
)
def postOperator(item: OperatorItem):
try:
operator_repo.add(item)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=409, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.put(
"/updateOperator",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="putOperator",
)
def updateOperator(item: OperatorItem):
try:
operator_repo.update(item)
return {"message": "OK"}
except ValueError as e:
msg = str(e)
if "non trovato" in msg:
raise HTTPException(status_code=404, detail=msg)
raise HTTPException(status_code=409, detail=msg)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.delete(
"/removeOperator/{operator_id}",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="removeOperator",
)
def removeOperator(operator_id: str):
try:
operator_repo.remove(operator_id)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.get(
"/getSubjects",
response_model=List[SubjectItem],
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="getSubject",
)
def getSubjects():
return subject_repo.list()


@router.post(
"/postSubject",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="postSubject",
)
def postSubject(item: SubjectItem):
try:
subject_repo.add(item)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=409, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.put(
"/updateSubject",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="putSubject",
)
def updateSubject(item: SubjectItem):
try:
subject_repo.update(item)
return {"message": "OK"}
except ValueError as e:
msg = str(e)
if "non trovato" in msg:
raise HTTPException(status_code=404, detail=msg)
raise HTTPException(status_code=409, detail=msg)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.delete(
"/removeSubject/{subject_id}",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="removeSubject",
)
def removeSubject(subject_id: str):
try:
subject_repo.remove(subject_id)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")
@router.delete("/removeTracker/{tracker_id}", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def removeTracker(tracker_id: str):
tracker_repo.remove(tracker_id)
return {"message": "OK"}


@router.get(
"/getAlarms",
response_model=List[AlarmItem],
"/getTrackerZones",
response_model=List[TrackerZoneItem],
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="getAlarm",
)
def getAlarms():
return alarm_repo.list()
def getTrackerZones():
return tracker_zone_repo.list()


@router.post(
"/postAlarm",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="postAlarm",
)
def postAlarm(item: AlarmItem):
try:
alarm_repo.add(item)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=409, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.put(
"/updateAlarm",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="putAlarm",
)
def updateAlarm(item: AlarmItem):
try:
alarm_repo.update(item)
return {"message": "OK"}
except ValueError as e:
msg = str(e)
if "non trovato" in msg:
raise HTTPException(status_code=404, detail=msg)
raise HTTPException(status_code=409, detail=msg)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.delete(
"/removeAlarm/{alarm_id}",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="removeAlarm",
)
def removeAlarm(alarm_id: str):
try:
alarm_repo.remove(alarm_id)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")
@router.post("/postTrackerZone", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def postTrackerZone(item: TrackerZoneItem):
tracker_zone_repo.add(item)
return {"message": "OK"}


@router.get(
"/getTracks",
response_model=List[TrackItem],
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="getTrack",
)
def getTracks():
return track_repo.list()
@router.put("/updateTrackerZone", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def updateTrackerZone(item: TrackerZoneItem):
tracker_zone_repo.update(item)
return {"message": "OK"}


@router.post(
"/postTrack",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="postTrack",
)
def postTrack(item: TrackItem):
try:
track_repo.add(item)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=409, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.put(
"/updateTrack",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="putTrack",
)
def updateTrack(item: TrackItem):
try:
track_repo.update(item)
return {"message": "OK"}
except ValueError as e:
msg = str(e)
if "non trovato" in msg:
raise HTTPException(status_code=404, detail=msg)
raise HTTPException(status_code=409, detail=msg)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")


@router.delete(
"/removeTrack/{track_id}",
tags=["Reslevis"],
dependencies=[Depends(get_current_user)],
summary="removeTrack",
)
def removeTrack(track_id: str):
try:
track_repo.remove(track_id)
return {"message": "OK"}
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Errore interno: {e}")
@router.delete("/removeTrackerZone/{tracker_zone_id}", tags=["Reslevis"], dependencies=[Depends(get_current_user)])
def removeTrackerZone(tracker_zone_id: str):
tracker_zone_repo.remove(tracker_zone_id)
return {"message": "OK"}


BIN
schemas/__pycache__/reslevis.cpython-310.pyc Voir le fichier


+ 19
- 13
schemas/reslevis.py Voir le fichier

@@ -2,6 +2,7 @@ from pydantic import BaseModel
from typing import Optional
from uuid import UUID
from typing import Optional, Union
from typing import List

class BuildingItem(BaseModel):
id: UUID
@@ -11,7 +12,7 @@ class BuildingItem(BaseModel):
latitude: Optional[float] = None
longitude: Optional[float] = None

class PlanItem(BaseModel):
class FloorItem(BaseModel):
id: UUID
name: str
image: Optional[str] = None
@@ -21,12 +22,12 @@ class PlanItem(BaseModel):
class ZoneItem(BaseModel):
id: UUID
name: str
groups: Optional[str] = None
plan: Optional[UUID] = None
groups: List[UUID]
floor: Optional[UUID] = None
building: Optional[UUID] = None

class GatewayItem(BaseModel):
id: str
id: UUID
name: str
mac: Optional[str] = None
status: Optional[Union[str, bool]] = None
@@ -36,8 +37,8 @@ class GatewayItem(BaseModel):
x: Optional[float] = None
y: Optional[float] = None
notes: Optional[str] = None
zone: Optional[str] = None
building: Optional[str] = None
floor: Optional[UUID] = None
building: Optional[UUID] = None

class TrackerItem(BaseModel):
id: UUID
@@ -49,11 +50,11 @@ class TrackerItem(BaseModel):
notes: Optional[str] = None
x: Optional[float] = None
y: Optional[float] = None
zone: Optional[UUID] = None
floor: Optional[UUID] = None
building: Optional[UUID] = None

class OperatorItem(BaseModel):
id: str
id: UUID
name: str
phone: Optional[str] = None
zones: Optional[str] = None
@@ -62,7 +63,7 @@ class OperatorItem(BaseModel):
building: Optional[UUID] = None

class SubjectItem(BaseModel):
id: str
id: UUID
name: str
role: Optional[str] = None
phone: Optional[str] = None
@@ -72,7 +73,7 @@ class SubjectItem(BaseModel):
building: Optional[UUID] = None

class AlarmItem(BaseModel):
id: str
id: UUID
timestamp: Optional[str] = None
type: Optional[str] = None
status: Optional[str] = None
@@ -89,7 +90,7 @@ class AlarmItem(BaseModel):
building: Optional[UUID] = None

class TrackItem(BaseModel):
id: str
id: UUID
timestamp: Optional[str] = None
type: Optional[str] = None
status: Optional[str] = None
@@ -99,8 +100,13 @@ class TrackItem(BaseModel):
trackerMac: Optional[str] = None
subject: Optional[str] = None
subjectName: Optional[str] = None
zone: Optional[str] = None
zoneName: Optional[str] = None
floor: Optional[str] = None
signal: Optional[float] = None
building: Optional[UUID] = None

class TrackerZoneItem(BaseModel):
id: UUID
zoneList: List[UUID]
tracker: UUID
days: Optional[str] = None
time: Optional[str] = None

+ 0
- 105
security.py.ok Voir le fichier

@@ -1,105 +0,0 @@
# security.py
from typing import Dict, Any, List, Optional
import os
import logging
import httpx
import config_env
from jose import jwt, JWTError
from fastapi import HTTPException, status, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials

logger = logging.getLogger("security")

# === CONFIG ===
#KEYCLOAK_ISSUER = os.getenv(
# "KEYCLOAK_ISSUER",
# "https://10.251.0.30:10002/realms/API.Server.local",
#"https://192.168.1.3:10002/realms/API.Server.local",
#)
#KEYCLOAK_JWKS_URL = os.getenv(
# "KEYCLOAK_JWKS_URL",
# "https://10.251.0.30:10002/realms/API.Server.local/protocol/openid-connect/certs",
#"https://192.168.1.3:10002/realms/API.Server.local/protocol/openid-connect/certs",
#)

KEYCLOAK_ISSUER = config_env.KEYCLOAK_ISSUER
KEYCLOAK_JWKS_URL = config_env.KEYCLOAK_JWKS_URL

KEYCLOAK_AUDIENCE = os.getenv("KEYCLOAK_AUDIENCE", "Fastapi")

ALGORITHMS = ["RS256", "RS384", "RS512", "PS256", "PS384", "PS512"]

# Per test con certificato self-signed. In prod: metti verify="/path/CA.crt"
_http = httpx.AsyncClient(timeout=5.0, verify=False)

_cached_jwks: Optional[Dict[str, Any]] = None

# NON chiamarla 'security' per evitare conflitti col nome del modulo.
http_bearer = HTTPBearer(auto_error=True)


async def _get_jwks() -> Dict[str, Any]:
global _cached_jwks
if _cached_jwks is None:
logger.info(f"Fetching JWKS from: {KEYCLOAK_JWKS_URL}")
resp = await _http.get(KEYCLOAK_JWKS_URL)
resp.raise_for_status()
_cached_jwks = resp.json()
return _cached_jwks


async def _get_key(token: str) -> Dict[str, Any]:
headers = jwt.get_unverified_header(token)
kid = headers.get("kid")
jwks = await _get_jwks()
for key in jwks.get("keys", []):
if key.get("kid") == kid:
return key
# chiave ruotata? invalida la cache e riprova
global _cached_jwks
_cached_jwks = None
jwks = await _get_jwks()
for key in jwks.get("keys", []):
if key.get("kid") == kid:
return key
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Signing key not found")


async def verify_token(token: str) -> Dict[str, Any]:
try:
key = await _get_key(token)
claims = jwt.decode(
token,
key,
algorithms=ALGORITHMS,
audience=KEYCLOAK_AUDIENCE,
issuer=KEYCLOAK_ISSUER,
options={"verify_aud": True, "verify_iss": True},
)
return claims
except JWTError as e:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(e))


async def get_current_user(
credentials: HTTPAuthorizationCredentials = Depends(http_bearer),
) -> Dict[str, Any]:
token = credentials.credentials
return await verify_token(token)


def require_roles(*roles: str):
async def checker(claims: Dict[str, Any] = Depends(get_current_user)) -> Dict[str, Any]:
# ruoli realm
realm_roles: List[str] = (claims.get("realm_access") or {}).get("roles", []) or []
# ruoli client
client_roles: List[str] = []
for v in (claims.get("resource_access") or {}).values():
client_roles += v.get("roles", [])
have = set(realm_roles + client_roles)
missing = [r for r in roles if r not in have]
if missing:
raise HTTPException(status_code=403, detail=f"Missing roles: {missing}")
return claims
return checker


Chargement…
Annuler
Enregistrer