from fastapi import APIRouter, Depends, HTTPException, status, Query from sqlalchemy.ext.asyncio import AsyncSession import logging from database import get_session, User from core.dependencies import get_current_user, require_role from services.api_key import ApiKeyService, api_key_to_response from schemas.api_key import ( ApiKeyCreate, ApiKeyCreatedResponse, ApiKeyResponse, ApiKeyList, ) logger = logging.getLogger(__name__) router = APIRouter(prefix="/api-keys", tags=["API Keys Management"]) @router.post( "", response_model=ApiKeyCreatedResponse, status_code=status.HTTP_201_CREATED, dependencies=[Depends(require_role("admin", "super_admin"))], ) async def create_api_key( data: ApiKeyCreate, session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = ApiKeyService(session) api_key_obj, api_key_plain = await service.create_api_key( name=data.name, description=data.description, created_by=user.email, user_id=user.id, expires_in_days=data.expires_in_days, rate_limit_per_minute=data.rate_limit_per_minute, allowed_endpoints=data.allowed_endpoints, ) logger.info(f" Clé API créée par {user.email}: {data.name}") response_data = api_key_to_response(api_key_obj) response_data["api_key"] = api_key_plain return ApiKeyCreatedResponse(**response_data) @router.get("", response_model=ApiKeyList) async def list_api_keys( include_revoked: bool = Query(False, description="Inclure les clés révoquées"), session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = ApiKeyService(session) user_id = None if user.role in ["admin", "super_admin"] else user.id keys = await service.list_api_keys(include_revoked=include_revoked, user_id=user_id) items = [ApiKeyResponse(**api_key_to_response(k)) for k in keys] return ApiKeyList(total=len(items), items=items) @router.get("/{key_id}", response_model=ApiKeyResponse) async def get_api_key( key_id: str, session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): """Récupérer une clé API par son ID""" service = ApiKeyService(session) api_key_obj = await service.get_by_id(key_id) if not api_key_obj: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Clé API {key_id} introuvable", ) if user.role not in ["admin", "super_admin"]: if api_key_obj.user_id != user.id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Accès refusé à cette clé", ) return ApiKeyResponse(**api_key_to_response(api_key_obj)) @router.delete("/{key_id}", status_code=status.HTTP_200_OK) async def revoke_api_key( key_id: str, session: AsyncSession = Depends(get_session), user: User = Depends(get_current_user), ): service = ApiKeyService(session) api_key_obj = await service.get_by_id(key_id) if not api_key_obj: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Clé API {key_id} introuvable", ) if user.role not in ["admin", "super_admin"]: if api_key_obj.user_id != user.id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Accès refusé à cette clé", ) success = await service.revoke_api_key(key_id) if not success: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Erreur lors de la révocation", ) logger.info(f" Clé API révoquée par {user.email}: {api_key_obj.name}") return { "success": True, "message": f"Clé API '{api_key_obj.name}' révoquée avec succès", } @router.post("/verify", status_code=status.HTTP_200_OK) async def verify_api_key_endpoint( api_key: str = Query(..., description="Clé API à vérifier"), session: AsyncSession = Depends(get_session), ): service = ApiKeyService(session) api_key_obj = await service.verify_api_key(api_key) if not api_key_obj: return { "valid": False, "message": "Clé API invalide, expirée ou révoquée", } return { "valid": True, "message": "Clé API valide", "key_name": api_key_obj.name, "rate_limit": api_key_obj.rate_limit_per_minute, "expires_at": api_key_obj.expires_at, }