Преглед на файлове

plan replacement and parameter fixes

proxy2core
root преди 1 месец
родител
ревизия
3dc032b2d3
променени са 15 файла, в които са добавени 213 реда и са изтрити 629 реда
  1. Двоични данни
      logica_reslevis/__pycache__/config.cpython-310.pyc
  2. Двоични данни
      logica_reslevis/__pycache__/floor.cpython-310.pyc
  3. Двоични данни
      logica_reslevis/__pycache__/tracker_zone.cpython-310.pyc
  4. Двоични данни
      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. Двоични данни
      models/__pycache__/gateway_item.cpython-310.pyc
  9. +6
    -6
      models/floor_item.py
  10. +7
    -14
      models/gateway_item.py
  11. Двоични данни
      routes/__pycache__/reslevis.cpython-310.pyc
  12. +84
    -471
      routes/reslevis.py
  13. Двоични данни
      schemas/__pycache__/reslevis.cpython-310.pyc
  14. +19
    -13
      schemas/reslevis.py
  15. +0
    -105
      security.py.ok

Двоични данни
logica_reslevis/__pycache__/config.cpython-310.pyc Целия файл


Двоични данни
logica_reslevis/__pycache__/floor.cpython-310.pyc Целия файл


Двоични данни
logica_reslevis/__pycache__/tracker_zone.cpython-310.pyc Целия файл


Двоични данни
logica_reslevis/__pycache__/zone.cpython-310.pyc Целия файл


+ 10
- 9
logica_reslevis/config.py Целия файл

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


# Percorsi dei file JSON # 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 Целия файл

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


from fastapi.encoders import jsonable_encoder 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 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 self.path = json_path


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


def add(self, item: PlanItem) -> None:
def add(self, item: FloorItem) -> None:
rows = self._read_all() rows = self._read_all()
obj = jsonable_encoder(item) obj = jsonable_encoder(item)
obj_id = _norm_str(obj.get("id")) obj_id = _norm_str(obj.get("id"))


if any(_norm_str(r.get("id")) == obj_id for r in rows): 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) rows.append(obj)
self._write_all(rows) self._write_all(rows)


def update(self, item: PlanItem) -> None:
def update(self, item: FloorItem) -> None:
rows = self._read_all() rows = self._read_all()
obj = jsonable_encoder(item) obj = jsonable_encoder(item)
obj_id = _norm_str(obj.get("id")) obj_id = _norm_str(obj.get("id"))


idx = _index_by_id(rows, obj_id) idx = _index_by_id(rows, obj_id)
if idx is None: 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 rows[idx] = obj
self._write_all(rows) self._write_all(rows)


def remove(self, plan_id: str) -> None:
def remove(self, floor_id: str) -> None:
rows = self._read_all() rows = self._read_all()
idx = _index_by_id(rows, plan_id)
idx = _index_by_id(rows, floor_id)
if idx is None: 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] del rows[idx]
self._write_all(rows) self._write_all(rows)

+ 76
- 0
logica_reslevis/tracker_zone.py Целия файл

@@ -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)


Двоични данни
models/__pycache__/gateway_item.cpython-310.pyc Целия файл


models/plan_item.py → models/floor_item.py Целия файл

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


from app_types import UNSET, Unset from app_types import UNSET, Unset


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




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


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


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


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


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

+ 7
- 14
models/gateway_item.py Целия файл

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


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


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


Двоични данни
routes/__pycache__/reslevis.cpython-310.pyc Целия файл


+ 84
- 471
routes/reslevis.py Целия файл

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


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


from logica_reslevis.gateway import GatewayJsonRepository from logica_reslevis.gateway import GatewayJsonRepository
from logica_reslevis.building import BuildingJsonRepository 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.zone import ZoneJsonRepository
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.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
from logica_reslevis.tracker_zone import TrackerZoneJsonRepository


from security import get_current_user from security import get_current_user


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


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




@router.get( @router.get(
@@ -43,61 +46,27 @@ track_repo = TrackJsonRepository()
response_model=List[GatewayItem], response_model=List[GatewayItem],
tags=["Reslevis"], tags=["Reslevis"],
dependencies=[Depends(get_current_user)], dependencies=[Depends(get_current_user)],
summary="getGateway",
) )
def getGateways(): def getGateways():
return gateway_repo.list() 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): 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): 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): 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( @router.get(
@@ -105,123 +74,55 @@ def removeGateway(gateway_id: str):
response_model=List[BuildingItem], response_model=List[BuildingItem],
tags=["Reslevis"], tags=["Reslevis"],
dependencies=[Depends(get_current_user)], dependencies=[Depends(get_current_user)],
summary="getBuilding",
) )
def getBuildings(): def getBuildings():
return building_repo.list() 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): 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): 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): 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( @router.get(
"/getPlans",
response_model=List[PlanItem],
"/getFloors",
response_model=List[FloorItem],
tags=["Reslevis"], tags=["Reslevis"],
dependencies=[Depends(get_current_user)], 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( @router.get(
@@ -229,61 +130,27 @@ def removePlan(plan_id: str):
response_model=List[ZoneItem], response_model=List[ZoneItem],
tags=["Reslevis"], tags=["Reslevis"],
dependencies=[Depends(get_current_user)], dependencies=[Depends(get_current_user)],
summary="getZone",
) )
def getZones(): def getZones():
return zone_repo.list() 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): 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): 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): 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( @router.get(
@@ -291,307 +158,53 @@ def removeZone(zone_id: str):
response_model=List[TrackerItem], response_model=List[TrackerItem],
tags=["Reslevis"], tags=["Reslevis"],
dependencies=[Depends(get_current_user)], dependencies=[Depends(get_current_user)],
summary="getTracker",
) )
def getTrackers(): def getTrackers():
return tracker_repo.list() 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): 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): 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"} 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( @router.get(
"/getAlarms",
response_model=List[AlarmItem],
"/getTrackerZones",
response_model=List[TrackerZoneItem],
tags=["Reslevis"], tags=["Reslevis"],
dependencies=[Depends(get_current_user)], 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"}



Двоични данни
schemas/__pycache__/reslevis.cpython-310.pyc Целия файл


+ 19
- 13
schemas/reslevis.py Целия файл

@@ -2,6 +2,7 @@ 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
from typing import List


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


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


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


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


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


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


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


class TrackItem(BaseModel): class TrackItem(BaseModel):
id: str
id: UUID
timestamp: Optional[str] = None timestamp: Optional[str] = None
type: Optional[str] = None type: Optional[str] = None
status: Optional[str] = None status: Optional[str] = None
@@ -99,8 +100,13 @@ class TrackItem(BaseModel):
trackerMac: Optional[str] = None trackerMac: Optional[str] = None
subject: Optional[str] = None subject: Optional[str] = None
subjectName: Optional[str] = None subjectName: Optional[str] = None
zone: Optional[str] = None
zoneName: Optional[str] = None
floor: Optional[str] = None
signal: Optional[float] = None signal: Optional[float] = None
building: Optional[UUID] = 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 Целия файл

@@ -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


Зареждане…
Отказ
Запис