"""Permissions endpoints - ServiceManagerWeb""" from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, delete from typing import Dict import uuid from app.core.database import get_db from app.api.deps import get_current_user from app.models.user import User, UserRole from app.models.permission import TenantPermission, DEFAULT_PERMISSIONS, CLIENT_PERMISSIONS router = APIRouter() @router.get("/my") async def get_my_permissions( db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ) -> Dict[str, bool]: """Obtener permisos efectivos del usuario actual.""" if current_user.role.is_global: # Staff interno — devolver permisos del rol por defecto role_defaults = DEFAULT_PERMISSIONS.get(current_user.role.value, {}) return role_defaults # Buscar overrides individuales primero result = await db.execute( select(TenantPermission).where( TenantPermission.tenant_id == current_user.tenant_id, TenantPermission.user_id == current_user.id, ) ) user_overrides = {p.permission: p.granted for p in result.scalars().all()} # Buscar defaults del rol result = await db.execute( select(TenantPermission).where( TenantPermission.tenant_id == current_user.tenant_id, TenantPermission.user_id == None, TenantPermission.role == current_user.role.value, ) ) role_defaults = {p.permission: p.granted for p in result.scalars().all()} # Merge: override individual > default del rol > system default system_defaults = DEFAULT_PERMISSIONS.get(current_user.role.value, {}) effective = {**system_defaults, **role_defaults, **user_overrides} return effective @router.get("/user/{user_id}") async def get_user_permissions( user_id: uuid.UUID, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ) -> Dict[str, bool]: """Obtener permisos efectivos de un usuario específico.""" if current_user.role not in (UserRole.ADMIN, UserRole.SUPPORT_MANAGER, UserRole.CLIENT_ADMIN): raise HTTPException(status_code=403, detail="Sin permisos") target = await db.get(User, user_id) if not target: raise HTTPException(status_code=404, detail="Usuario no encontrado") # Buscar overrides individuales result = await db.execute( select(TenantPermission).where( TenantPermission.user_id == user_id, ) ) user_overrides = {p.permission: p.granted for p in result.scalars().all()} # Buscar defaults del rol en el tenant result = await db.execute( select(TenantPermission).where( TenantPermission.tenant_id == target.tenant_id, TenantPermission.user_id == None, TenantPermission.role == target.role.value, ) ) role_defaults = {p.permission: p.granted for p in result.scalars().all()} system_defaults = DEFAULT_PERMISSIONS.get(target.role.value, {}) effective = {**system_defaults, **role_defaults, **user_overrides} return effective @router.put("/user/{user_id}") async def update_user_permissions( user_id: uuid.UUID, data: Dict[str, bool], db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): """ Actualizar permisos individuales de un usuario. Solo ADMIN, SUPPORT_MANAGER o CLIENT_ADMIN pueden hacerlo. """ if current_user.role not in (UserRole.ADMIN, UserRole.SUPPORT_MANAGER, UserRole.CLIENT_ADMIN): raise HTTPException(status_code=403, detail="Sin permisos") target = await db.get(User, user_id) if not target: raise HTTPException(status_code=404, detail="Usuario no encontrado") # Borrar overrides existentes del usuario await db.execute( delete(TenantPermission).where( TenantPermission.user_id == user_id, ) ) # Insertar nuevos overrides from datetime import datetime now = datetime.utcnow() for permission, granted in data.items(): db.add(TenantPermission( id=uuid.uuid4(), tenant_id=target.tenant_id, user_id=user_id, role=target.role.value, permission=permission, granted=granted, created_at=now, updated_at=now, )) await db.commit() return {"message": "Permisos actualizados"}