Adjustments to the Devices Layout
This commit is contained in:
@@ -75,6 +75,7 @@ class DeviceAttributes(BaseModel):
|
||||
networkSettings: DeviceNetworkSettings = DeviceNetworkSettings()
|
||||
serialLogLevel: int = 0
|
||||
sdLogLevel: int = 0
|
||||
mqttLogLevel: int = 0
|
||||
|
||||
|
||||
class DeviceSubInformation(BaseModel):
|
||||
@@ -151,3 +152,16 @@ class DeviceInDB(DeviceCreate):
|
||||
class DeviceListResponse(BaseModel):
|
||||
devices: List[DeviceInDB]
|
||||
total: int
|
||||
|
||||
|
||||
class DeviceUserInfo(BaseModel):
|
||||
"""User info resolved from device_users sub-collection or user_list."""
|
||||
user_id: str = ""
|
||||
display_name: str = ""
|
||||
email: str = ""
|
||||
role: str = ""
|
||||
|
||||
|
||||
class DeviceUsersResponse(BaseModel):
|
||||
users: List[DeviceUserInfo]
|
||||
total: int
|
||||
|
||||
@@ -4,6 +4,7 @@ from auth.models import TokenPayload
|
||||
from auth.dependencies import require_device_access, require_viewer
|
||||
from devices.models import (
|
||||
DeviceCreate, DeviceUpdate, DeviceInDB, DeviceListResponse,
|
||||
DeviceUsersResponse, DeviceUserInfo,
|
||||
)
|
||||
from devices import service
|
||||
|
||||
@@ -33,6 +34,16 @@ async def get_device(
|
||||
return service.get_device(device_id)
|
||||
|
||||
|
||||
@router.get("/{device_id}/users", response_model=DeviceUsersResponse)
|
||||
async def get_device_users(
|
||||
device_id: str,
|
||||
_user: TokenPayload = Depends(require_viewer),
|
||||
):
|
||||
users_data = service.get_device_users(device_id)
|
||||
users = [DeviceUserInfo(**u) for u in users_data]
|
||||
return DeviceUsersResponse(users=users, total=len(users))
|
||||
|
||||
|
||||
@router.post("", response_model=DeviceInDB, status_code=201)
|
||||
async def create_device(
|
||||
body: DeviceCreate,
|
||||
|
||||
@@ -165,6 +165,94 @@ def update_device(device_doc_id: str, data: DeviceUpdate) -> DeviceInDB:
|
||||
return _doc_to_device(updated_doc)
|
||||
|
||||
|
||||
def get_device_users(device_doc_id: str) -> list[dict]:
|
||||
"""Get users assigned to a device from the device_users sub-collection.
|
||||
|
||||
Falls back to the user_list field on the device document if the
|
||||
sub-collection is empty.
|
||||
"""
|
||||
db = get_db()
|
||||
doc_ref = db.collection(COLLECTION).document(device_doc_id)
|
||||
doc = doc_ref.get()
|
||||
if not doc.exists:
|
||||
raise NotFoundError("Device")
|
||||
|
||||
# Try sub-collection first
|
||||
sub_docs = list(doc_ref.collection("device_users").stream())
|
||||
users = []
|
||||
|
||||
if sub_docs:
|
||||
for sub_doc in sub_docs:
|
||||
sub_data = sub_doc.to_dict()
|
||||
role = sub_data.get("role", "")
|
||||
user_ref = sub_data.get("user_reference")
|
||||
|
||||
# Resolve user reference
|
||||
user_id = ""
|
||||
display_name = ""
|
||||
email = ""
|
||||
|
||||
if isinstance(user_ref, DocumentReference):
|
||||
try:
|
||||
user_doc = user_ref.get()
|
||||
if user_doc.exists:
|
||||
user_data = user_doc.to_dict()
|
||||
user_id = user_doc.id
|
||||
display_name = user_data.get("display_name", "")
|
||||
email = user_data.get("email", "")
|
||||
except Exception as e:
|
||||
print(f"[devices] Error resolving user reference: {e}")
|
||||
continue
|
||||
elif isinstance(user_ref, str):
|
||||
# String path like "users/abc123"
|
||||
try:
|
||||
ref_doc = db.document(user_ref).get()
|
||||
if ref_doc.exists:
|
||||
user_data = ref_doc.to_dict()
|
||||
user_id = ref_doc.id
|
||||
display_name = user_data.get("display_name", "")
|
||||
email = user_data.get("email", "")
|
||||
except Exception as e:
|
||||
print(f"[devices] Error resolving user path: {e}")
|
||||
continue
|
||||
|
||||
users.append({
|
||||
"user_id": user_id,
|
||||
"display_name": display_name,
|
||||
"email": email,
|
||||
"role": role,
|
||||
})
|
||||
else:
|
||||
# Fallback to user_list field
|
||||
device_data = doc.to_dict()
|
||||
user_list = device_data.get("user_list", [])
|
||||
for entry in user_list:
|
||||
try:
|
||||
if isinstance(entry, DocumentReference):
|
||||
user_doc = entry.get()
|
||||
elif isinstance(entry, str) and entry.strip():
|
||||
# Could be a path like "users/abc" or a raw doc ID
|
||||
if "/" in entry:
|
||||
user_doc = db.document(entry).get()
|
||||
else:
|
||||
user_doc = db.collection("users").document(entry).get()
|
||||
else:
|
||||
continue
|
||||
|
||||
if user_doc.exists:
|
||||
user_data = user_doc.to_dict()
|
||||
users.append({
|
||||
"user_id": user_doc.id,
|
||||
"display_name": user_data.get("display_name", ""),
|
||||
"email": user_data.get("email", ""),
|
||||
"role": "",
|
||||
})
|
||||
except Exception as e:
|
||||
print(f"[devices] Error resolving user_list entry: {e}")
|
||||
|
||||
return users
|
||||
|
||||
|
||||
def delete_device(device_doc_id: str) -> None:
|
||||
"""Delete a device document from Firestore."""
|
||||
db = get_db()
|
||||
|
||||
Reference in New Issue
Block a user