104 lines
4.5 KiB
Python
104 lines
4.5 KiB
Python
from typing import Optional, TYPE_CHECKING, List
|
||
if TYPE_CHECKING:
|
||
from .areas import Area
|
||
from .room_functions import RoomFunction
|
||
from .inventory import Inventory
|
||
from .users import User
|
||
|
||
from sqlalchemy import ForeignKey, Identity, Integer, Unicode
|
||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||
|
||
from . import db
|
||
|
||
class Room(db.Model):
|
||
__tablename__ = 'Rooms'
|
||
|
||
id: Mapped[int] = mapped_column("ID", Integer, Identity(start=1, increment=1), primary_key=True)
|
||
name: Mapped[Optional[str]] = mapped_column("Room", Unicode(255), nullable=True)
|
||
area_id: Mapped[Optional[int]] = mapped_column("Area", Integer, ForeignKey("Areas.ID"))
|
||
function_id: Mapped[Optional[int]] = mapped_column("Function", Integer, ForeignKey("Room Functions.ID"))
|
||
|
||
area: Mapped[Optional['Area']] = relationship('Area', back_populates='rooms')
|
||
room_function: Mapped[Optional['RoomFunction']] = relationship('RoomFunction', back_populates='rooms')
|
||
inventory: Mapped[List['Inventory']] = relationship('Inventory', back_populates='location')
|
||
users: Mapped[List['User']] = relationship('User', back_populates='location')
|
||
|
||
def __init__(self, name: Optional[str] = None, area_id: Optional[int] = None, function_id: Optional[int] = None):
|
||
self.name = name
|
||
self.area_id = area_id
|
||
self.function_id = function_id
|
||
|
||
def __repr__(self):
|
||
return f"<Room(id={self.id}, room={repr(self.name)}, area_id={self.area_id}, function_id={self.function_id})>"
|
||
|
||
@property
|
||
def full_name(self):
|
||
name = self.name or ""
|
||
func = self.room_function.description if self.room_function else ""
|
||
return f"{name} - {func}".strip(" -")
|
||
|
||
def serialize(self):
|
||
return {
|
||
'id': self.id,
|
||
'name': self.name,
|
||
'area_id': self.area_id,
|
||
'function_id': self.function_id
|
||
}
|
||
|
||
@classmethod
|
||
def sync_from_state(cls, submitted_rooms: list[dict], section_map: dict, function_map: dict, section_fallbacks: list, function_fallbacks: list):
|
||
"""
|
||
Syncs the Rooms table with the submitted room list.
|
||
Resolves foreign keys using section_map and function_map.
|
||
"""
|
||
|
||
def resolve_id(raw_id, fallback_list, id_map, label):
|
||
try:
|
||
resolved = int(raw_id)
|
||
if resolved >= 0:
|
||
if resolved in id_map.values():
|
||
return resolved
|
||
raise ValueError(f"ID {resolved} not found in {label}.")
|
||
except Exception:
|
||
pass
|
||
|
||
index = abs(resolved + 1)
|
||
try:
|
||
entry = fallback_list[index]
|
||
key = entry.get("name") if isinstance(entry, dict) else str(entry).strip()
|
||
final_id = id_map.get(key)
|
||
if final_id is None:
|
||
raise ValueError(f"ID for {key} not found in {label}.")
|
||
return final_id
|
||
except Exception as e:
|
||
raise ValueError(f"Failed to resolve {label} ID: {e}") from e
|
||
|
||
existing_query = db.session.query(cls)
|
||
existing = {room.name: room for room in existing_query.all()}
|
||
|
||
submitted = {
|
||
str(room.get("name", "")).strip(): room
|
||
for room in submitted_rooms
|
||
if isinstance(room, dict) and str(room.get("name", "")).strip()
|
||
}
|
||
|
||
existing_names = set(existing.keys())
|
||
submitted_names = set(submitted.keys())
|
||
|
||
print(f"Existing rooms: {existing_names}")
|
||
print(f"Submitted rooms: {submitted_names}")
|
||
print(f"Rooms to add: {submitted_names - existing_names}")
|
||
print(f"Rooms to remove: {existing_names - submitted_names}")
|
||
|
||
for name in submitted_names - existing_names:
|
||
room_data = submitted[name]
|
||
area_id = resolve_id(room_data.get("section_id", -1), section_fallbacks, section_map, "section") if room_data.get("section_id") is not None else None
|
||
function_id = resolve_id(room_data.get("function_id", -1), function_fallbacks, function_map, "function") if room_data.get("function_id") is not None else None
|
||
new_room = cls(name=name, area_id=area_id, function_id=function_id)
|
||
db.session.add(new_room)
|
||
print(f"➕ Adding room: {new_room}")
|
||
|
||
for name in existing_names - submitted_names:
|
||
room_to_remove = existing[name]
|
||
db.session.delete(room_to_remove)
|
||
print(f"🗑️ Removing room: {room_to_remove}")
|