feat: add Workspace feature — scoped server groups with user access and sidebar selector
This commit is contained in:
@@ -32,8 +32,36 @@ async def backups_page(
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
from ...i18n import t
|
||||
from ...api.workspaces import get_workspace_server_ids
|
||||
from ...auth import get_current_user_optional
|
||||
|
||||
lang = request.cookies.get("language", "ru")
|
||||
servers = db.query(ProxmoxServer).filter(ProxmoxServer.is_online.is_(True)).all()
|
||||
|
||||
# Workspace filtering (best-effort, page may be loaded unauthenticated)
|
||||
server_ids = None
|
||||
try:
|
||||
token = request.cookies.get("access_token") or (
|
||||
request.headers.get("Authorization", "").removeprefix("Bearer ").strip() or None
|
||||
)
|
||||
if token:
|
||||
from ...auth import decode_access_token
|
||||
from ...models import User as UserModel
|
||||
payload = decode_access_token(token)
|
||||
username = payload.get("sub")
|
||||
if username:
|
||||
user_obj = db.query(UserModel).filter(
|
||||
UserModel.username == username, UserModel.is_active == True
|
||||
).first()
|
||||
if user_obj:
|
||||
server_ids = get_workspace_server_ids(request, db, user_obj)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
servers_q = db.query(ProxmoxServer).filter(ProxmoxServer.is_online.is_(True))
|
||||
if server_ids is not None:
|
||||
servers_q = servers_q.filter(ProxmoxServer.id.in_(server_ids))
|
||||
servers = servers_q.all()
|
||||
|
||||
context = {
|
||||
"request": request,
|
||||
"page_title": t("nav_backups", lang),
|
||||
@@ -57,7 +85,7 @@ def get_storages(
|
||||
raise HTTPException(status_code=404, detail="Server not found")
|
||||
try:
|
||||
client = _get_proxmox_client(server)
|
||||
storages = client.get_storages()
|
||||
storages = client.get_cluster_storages()
|
||||
return JSONResponse(content={"storages": storages})
|
||||
except Exception as e:
|
||||
logger.error(f"Error listing storages for server {server_id}: {e}")
|
||||
|
||||
@@ -84,11 +84,17 @@ def instance_detail_page(request: Request, server_id: int, vmid: int, type: str
|
||||
|
||||
@router.get("/api/servers", response_model=List[ProxmoxServerResponse])
|
||||
def list_proxmox_servers(
|
||||
db: Session = Depends(get_db),
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(PermissionChecker("proxmox.view"))
|
||||
):
|
||||
"""Получить список всех Proxmox серверов"""
|
||||
servers = db.query(ProxmoxServer).all()
|
||||
"""Получить список всех Proxmox серверов (фильтруется по активному workspace)"""
|
||||
from ...api.workspaces import get_workspace_server_ids
|
||||
server_ids = get_workspace_server_ids(request, db, current_user)
|
||||
query = db.query(ProxmoxServer)
|
||||
if server_ids is not None:
|
||||
query = query.filter(ProxmoxServer.id.in_(server_ids))
|
||||
servers = query.all()
|
||||
return servers
|
||||
|
||||
|
||||
@@ -705,7 +711,7 @@ def get_storages(
|
||||
if not client.is_connected():
|
||||
raise HTTPException(status_code=503, detail="Failed to connect to Proxmox server")
|
||||
|
||||
storages = client.get_storages(node)
|
||||
storages = client.get_node_storages(node)
|
||||
|
||||
# Фильтрация по типу контента если указано
|
||||
if content_type and storages:
|
||||
|
||||
@@ -77,6 +77,7 @@ def sync_vms_now(
|
||||
|
||||
@router.get("/api/virtual-machines")
|
||||
def get_all_virtual_machines(
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(PermissionChecker("vms.view"))
|
||||
):
|
||||
@@ -88,9 +89,16 @@ def get_all_virtual_machines(
|
||||
Для пользователей с ролью 'user' возвращаются только их собственные инстансы.
|
||||
"""
|
||||
from ...models import VMInstance
|
||||
|
||||
# Get servers for name lookup
|
||||
servers = db.query(ProxmoxServer).all()
|
||||
from ...api.workspaces import get_workspace_server_ids
|
||||
|
||||
# Workspace filtering
|
||||
workspace_server_ids = get_workspace_server_ids(request, db, current_user)
|
||||
|
||||
# Get servers for name lookup (filtered by workspace)
|
||||
servers_q = db.query(ProxmoxServer)
|
||||
if workspace_server_ids is not None:
|
||||
servers_q = servers_q.filter(ProxmoxServer.id.in_(workspace_server_ids))
|
||||
servers = servers_q.all()
|
||||
server_map = {s.id: s for s in servers}
|
||||
|
||||
# Pre-load IPAM allocations for IP lookup
|
||||
@@ -121,6 +129,10 @@ def get_all_virtual_machines(
|
||||
VMInstance.deleted_at.is_(None),
|
||||
VMInstance.is_template == False
|
||||
)
|
||||
|
||||
# Workspace filter: only show VMs from servers in the active workspace
|
||||
if workspace_server_ids is not None:
|
||||
query = query.filter(VMInstance.server_id.in_(workspace_server_ids))
|
||||
|
||||
# VPS-style user isolation: users with 'user' role see only their own instances
|
||||
# Check if user has 'vms.view' but not 'vms.view:all' (or is user role)
|
||||
|
||||
Reference in New Issue
Block a user