"""Role management routes.""" from __future__ import annotations import uuid from fastapi import APIRouter, Depends, HTTPException, Response, status from fastapi.responses import JSONResponse from sqlalchemy.ext.asyncio import AsyncSession from app.core.db import get_db from app.deps import get_current_user, require_admin from app.schemas.role import RoleCreate, RoleUpdate from app.services.role_service import role_service router = APIRouter(prefix="/api/v1/roles", tags=["roles"]) @router.get("") async def list_roles( db: AsyncSession = Depends(get_db), current_user: dict = Depends(get_current_user), ): """List roles for the current tenant.""" tenant_id = uuid.UUID(current_user["tenant_id"]) roles = await role_service.list_roles(db, tenant_id) return {"items": roles} @router.post("") async def create_role( body: RoleCreate, db: AsyncSession = Depends(get_db), current_user: dict = Depends(require_admin), ): """Create a custom role (admin only).""" tenant_id = uuid.UUID(current_user["tenant_id"]) role = await role_service.create_role( db, tenant_id, body.name, body.permissions, body.field_permissions, ) return JSONResponse( status_code=status.HTTP_201_CREATED, content={ "id": str(role.id), "name": role.name, "permissions": role.permissions, "field_permissions": role.field_permissions, }, ) @router.patch("/{role_id}") async def update_role( role_id: str, body: RoleUpdate, db: AsyncSession = Depends(get_db), current_user: dict = Depends(require_admin), ): """Update a role (admin only).""" tenant_id = uuid.UUID(current_user["tenant_id"]) try: rid = uuid.UUID(role_id) except ValueError: raise HTTPException( 400, detail={"detail": "Invalid role_id", "code": "invalid_id"} ) from None role = await role_service.update_role( db, tenant_id, rid, body.name, body.permissions, body.field_permissions, ) if role is None: raise HTTPException(404, detail={"detail": "Role not found", "code": "not_found"}) return { "id": str(role.id), "name": role.name, "permissions": role.permissions, "field_permissions": role.field_permissions, } @router.delete("/{role_id}") async def delete_role( role_id: str, db: AsyncSession = Depends(get_db), current_user: dict = Depends(require_admin), ): """Delete a role (admin only).""" tenant_id = uuid.UUID(current_user["tenant_id"]) try: rid = uuid.UUID(role_id) except ValueError: raise HTTPException( 400, detail={"detail": "Invalid role_id", "code": "invalid_id"} ) from None success = await role_service.delete_role(db, tenant_id, rid) if not success: raise HTTPException(404, detail={"detail": "Role not found", "code": "not_found"}) return Response(status_code=status.HTTP_204_NO_CONTENT)