from typing import List from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from backend.api.deps import AuthUser, get_current_user, require_admin from backend.db.session import get_session from backend.modules.aws_accounts.schemas import ( AWSCredentialCreate, AWSCredentialOut, AWSCredentialUpdate, CustomerCredentialCreate, CustomerCredentialOut, ) from backend.modules.aws_accounts.service import ( authorize_customer, create_credential, delete_credential, get_credential, list_credentials, update_credential, ) from backend.modules.users.models import RoleName router = APIRouter(prefix="/api/v1/aws_credentials", tags=["aws_credentials"]) @router.get("", response_model=List[AWSCredentialOut]) async def get_credentials( session: AsyncSession = Depends(get_session), auth_user: AuthUser = Depends(get_current_user), ) -> List[AWSCredentialOut]: # 客户普通用户只能看到自己所属客户被授权的凭证 if auth_user.role_name == RoleName.ADMIN.value: target_customer_id = None else: target_customer_id = auth_user.customer_id if target_customer_id is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="customer_id required for non-admin user" ) credentials = await list_credentials(session, target_customer_id) return [AWSCredentialOut.model_validate(c) for c in credentials] @router.post("", response_model=AWSCredentialOut, status_code=status.HTTP_201_CREATED) async def create_credential_endpoint( payload: AWSCredentialCreate, session: AsyncSession = Depends(get_session), auth_user: AuthUser = Depends(require_admin), ) -> AWSCredentialOut: cred = await create_credential(session, payload.model_dump(), auth_user.user) return AWSCredentialOut.model_validate(cred) @router.put("/{credential_id}", response_model=AWSCredentialOut) async def update_credential_endpoint( credential_id: int, payload: AWSCredentialUpdate, session: AsyncSession = Depends(get_session), auth_user: AuthUser = Depends(require_admin), ) -> AWSCredentialOut: cred = await update_credential(session, credential_id, payload.model_dump(exclude_unset=True), auth_user.user) return AWSCredentialOut.model_validate(cred) @router.get("/{credential_id}", response_model=AWSCredentialOut) async def get_credential_endpoint( credential_id: int, session: AsyncSession = Depends(get_session), auth_user: AuthUser = Depends(get_current_user), ) -> AWSCredentialOut: cred = await get_credential(session, credential_id) if auth_user.role_name != RoleName.ADMIN.value: # ensure mapping _ = await session.execute( select(CustomerCredential).where( CustomerCredential.customer_id == auth_user.customer_id, CustomerCredential.credential_id == credential_id, CustomerCredential.is_allowed == 1, ) ) return AWSCredentialOut.model_validate(cred) @router.delete("/{credential_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_credential_endpoint( credential_id: int, session: AsyncSession = Depends(get_session), auth_user: AuthUser = Depends(require_admin), ) -> None: await delete_credential(session, credential_id, auth_user.user) @router.post("/{credential_id}/authorize", response_model=CustomerCredentialOut) async def authorize_credential_endpoint( credential_id: int, payload: CustomerCredentialCreate, session: AsyncSession = Depends(get_session), auth_user: AuthUser = Depends(require_admin), ) -> CustomerCredentialOut: if credential_id != payload.credential_id: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="credential_id mismatch") mapping = await authorize_customer( session, payload.customer_id, payload.credential_id, payload.is_allowed, auth_user.user ) return CustomerCredentialOut.model_validate(mapping)