Added Roles and Permissions. Some minor UI fixes
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from fastapi import APIRouter, Depends, Query, WebSocket, WebSocketDisconnect
|
||||
from typing import Optional
|
||||
from auth.models import TokenPayload
|
||||
from auth.dependencies import require_device_access, require_viewer
|
||||
from auth.dependencies import require_permission
|
||||
from mqtt.models import (
|
||||
MqttCommandRequest, CommandSendResponse, MqttStatusResponse,
|
||||
DeviceMqttStatus, LogListResponse, HeartbeatListResponse,
|
||||
@@ -16,7 +16,7 @@ router = APIRouter(prefix="/api/mqtt", tags=["mqtt"])
|
||||
|
||||
@router.get("/status", response_model=MqttStatusResponse)
|
||||
async def get_all_device_status(
|
||||
_user: TokenPayload = Depends(require_viewer),
|
||||
_user: TokenPayload = Depends(require_permission("mqtt", "view")),
|
||||
):
|
||||
heartbeats = await db.get_latest_heartbeats()
|
||||
now = datetime.now(timezone.utc)
|
||||
@@ -47,7 +47,7 @@ async def get_all_device_status(
|
||||
async def send_command(
|
||||
device_serial: str,
|
||||
body: MqttCommandRequest,
|
||||
_user: TokenPayload = Depends(require_device_access),
|
||||
_user: TokenPayload = Depends(require_permission("mqtt", "view")),
|
||||
):
|
||||
command_id = await db.insert_command(
|
||||
device_serial=device_serial,
|
||||
@@ -84,7 +84,7 @@ async def get_device_logs(
|
||||
search: Optional[str] = Query(None),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
offset: int = Query(0, ge=0),
|
||||
_user: TokenPayload = Depends(require_viewer),
|
||||
_user: TokenPayload = Depends(require_permission("mqtt", "view")),
|
||||
):
|
||||
logs, total = await db.get_logs(
|
||||
device_serial, level=level, search=search,
|
||||
@@ -98,7 +98,7 @@ async def get_device_heartbeats(
|
||||
device_serial: str,
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
offset: int = Query(0, ge=0),
|
||||
_user: TokenPayload = Depends(require_viewer),
|
||||
_user: TokenPayload = Depends(require_permission("mqtt", "view")),
|
||||
):
|
||||
heartbeats, total = await db.get_heartbeats(
|
||||
device_serial, limit=limit, offset=offset,
|
||||
@@ -111,7 +111,7 @@ async def get_device_commands(
|
||||
device_serial: str,
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
offset: int = Query(0, ge=0),
|
||||
_user: TokenPayload = Depends(require_viewer),
|
||||
_user: TokenPayload = Depends(require_permission("mqtt", "view")),
|
||||
):
|
||||
commands, total = await db.get_commands(
|
||||
device_serial, limit=limit, offset=offset,
|
||||
@@ -129,12 +129,28 @@ async def mqtt_websocket(websocket: WebSocket):
|
||||
|
||||
try:
|
||||
from auth.utils import decode_access_token
|
||||
from shared.firebase import get_db
|
||||
payload = decode_access_token(token)
|
||||
role = payload.get("role", "")
|
||||
allowed = {"superadmin", "device_manager", "viewer"}
|
||||
if role not in allowed:
|
||||
await websocket.close(code=4003, reason="Insufficient permissions")
|
||||
return
|
||||
|
||||
# sysadmin and admin always have MQTT access
|
||||
if role not in ("sysadmin", "admin"):
|
||||
# Check MQTT permission for editor/user
|
||||
user_sub = payload.get("sub", "")
|
||||
db_inst = get_db()
|
||||
if db_inst:
|
||||
doc = db_inst.collection("admin_users").document(user_sub).get()
|
||||
if doc.exists:
|
||||
perms = doc.to_dict().get("permissions", {})
|
||||
if not perms.get("mqtt", False):
|
||||
await websocket.close(code=4003, reason="MQTT access denied")
|
||||
return
|
||||
else:
|
||||
await websocket.close(code=4003, reason="User not found")
|
||||
return
|
||||
else:
|
||||
await websocket.close(code=4003, reason="Service unavailable")
|
||||
return
|
||||
except Exception:
|
||||
await websocket.close(code=4001, reason="Invalid token")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user