feat: v1.1.8 — user-server assignment, VM/LXC ownership, smart login redirect, RBAC migrations

- Migration 20: user_servers association table (User ↔ ProxmoxServer)
- API: GET/PUT /api/users/{id}/servers — assign servers to users with workspace-conflict validation
- API: GET /api/users/{id}/server-assignments — enriched server list (assigned + compatible flags)
- Non-admin server filter: intersection of assigned_servers and workspace servers
- Migration 21: dashboard:view = false for user role (new key format)
- Migration 22: proxmox.cluster.manage → cluster:manage for admin role
- API: GET/PUT /api/{server_id}/vm/{vmid}/owner — VM/LXC owner assignment (admin-only)
- Login: smart redirect based on user permissions after authentication
- Login: returnUrl param support for post-login redirect
- Roles API: user_count field per role in GET /api/roles
- node_uptime added to server detail API response
- Remove redundant PermissionChecker from GET /users HTML route
This commit is contained in:
markmorado
2026-03-16 08:27:36 +01:00
parent c09c0c5b63
commit 57575d58ce
22 changed files with 1436 additions and 314 deletions

View File

@@ -3,7 +3,7 @@ import os
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI, Request, HTTPException, WebSocket, WebSocketDisconnect, Query
from fastapi import FastAPI, Request, HTTPException, WebSocket, WebSocketDisconnect, Query, Depends
from fastapi.responses import RedirectResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from fastapi.exception_handlers import http_exception_handler
@@ -13,6 +13,8 @@ from loguru import logger
from .config import settings
from .db import Base, engine, init_db, check_db_connection
from .auth import PermissionChecker, get_current_user
from .models import User
from .api import dashboard as dashboard_router
from .api import proxmox as proxmox_router
from .api import auth as auth_router
@@ -259,6 +261,13 @@ def create_app() -> FastAPI:
@app.exception_handler(HTTPException)
async def custom_http_exception_handler(request: Request, exc: HTTPException):
logger.warning(f"HTTP exception: {exc.status_code} - {exc.detail}")
# Redirect browser HTML page requests to /login on auth errors
if exc.status_code in (401, 403):
accept = request.headers.get("accept", "")
path = request.url.path
if "text/html" in accept and not path.startswith(("/api/", "/static/", "/settings/api/")):
from urllib.parse import quote
return RedirectResponse(url=f"/login?returnUrl={quote(path)}", status_code=302)
return await http_exception_handler(request, exc)
# Health check endpoint