"""Admin-only management of public Realtime API credentials.""" from __future__ import annotations from datetime import UTC, datetime from db.models import RealtimeApiKey from db.session import get_session from fastapi import APIRouter, Depends, HTTPException, Response, status from schemas import RealtimeApiKeyCreate, RealtimeApiKeyCreated, RealtimeApiKeyOut from services.auth import require_admin from services.openai_realtime.auth import create_api_key_value from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession router = APIRouter( prefix="/api/realtime/api-keys", tags=["realtime-api-keys"], dependencies=[Depends(require_admin)], ) def _status(row: RealtimeApiKey) -> str: if row.revoked_at is not None: return "revoked" if row.expires_at is not None and row.expires_at <= datetime.now(UTC): return "expired" return "active" def _out(row: RealtimeApiKey) -> RealtimeApiKeyOut: return RealtimeApiKeyOut( id=row.id, name=row.name, key_prefix=row.key_prefix, status=_status(row), expires_at=row.expires_at, last_used_at=row.last_used_at, revoked_at=row.revoked_at, created_at=row.created_at, ) @router.post("", response_model=RealtimeApiKeyCreated, status_code=status.HTTP_201_CREATED) async def create_realtime_api_key( body: RealtimeApiKeyCreate, session: AsyncSession = Depends(get_session), ): key_id, key, prefix, digest = create_api_key_value() row = RealtimeApiKey( id=key_id, name=body.name, key_prefix=prefix, key_hash=digest, expires_at=body.expires_at, ) session.add(row) await session.commit() await session.refresh(row) return RealtimeApiKeyCreated(**_out(row).model_dump(), key=key) @router.get("", response_model=list[RealtimeApiKeyOut]) async def list_realtime_api_keys(session: AsyncSession = Depends(get_session)): rows = ( await session.execute( select(RealtimeApiKey).order_by(RealtimeApiKey.created_at.desc()) ) ).scalars().all() return [_out(row) for row in rows] @router.delete("/{key_id}", status_code=status.HTTP_204_NO_CONTENT) async def revoke_realtime_api_key( key_id: str, session: AsyncSession = Depends(get_session), ): row = await session.get(RealtimeApiKey, key_id) if row is None: raise HTTPException(404, "Realtime API Key 不存在") if row.revoked_at is None: row.revoked_at = datetime.now(UTC) await session.commit() return Response(status_code=status.HTTP_204_NO_CONTENT)