feat: Add admin auth

This commit is contained in:
wilson 2026-03-27 10:36:43 +00:00
parent 046504e6a1
commit e05a62cda9
4 changed files with 21 additions and 5 deletions

View file

@ -48,3 +48,18 @@ def verify_token(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or expired token",
)
def _admin_emails() -> frozenset[str]:
return frozenset(
e.strip() for e in settings.admin_user_emails.split(",") if e.strip()
)
def require_admin(token_data: dict = Depends(verify_token)) -> dict:
if token_data.get("email") not in _admin_emails():
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin access required",
)
return token_data

View file

@ -8,6 +8,7 @@ class Settings(BaseSettings):
deepl_api_key: str
deepgram_api_key: str
gemini_api_key: str
admin_user_emails: str = "" # comma-separated list of admin email addresses
storage_endpoint_url: str
storage_access_key: str
storage_secret_key: str

View file

@ -10,7 +10,7 @@ from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
from ...languages import SUPPORTED_LANGUAGES, SUPPORTED_LEVELS
from ...auth import verify_token
from ...auth import require_admin
from ...storage import upload_audio
from ...outbound.postgres.database import get_db, AsyncSessionLocal
from ...outbound.postgres.repositories import summarise_job_repository
@ -125,7 +125,7 @@ async def _run_generation(job_id: uuid.UUID, request: GenerationRequest) -> None
async def create_generation_job(
request: GenerationRequest,
db: AsyncSession = Depends(get_db),
token_data: dict = Depends(verify_token),
token_data: dict = Depends(require_admin),
) -> GenerationResponse:
if request.target_language not in SUPPORTED_LANGUAGES:
raise HTTPException(

View file

@ -6,7 +6,7 @@ from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
from ...auth import verify_token
from ...auth import require_admin
from ...outbound.postgres.database import get_db, AsyncSessionLocal
from ...outbound.postgres.repositories import summarise_job_repository
from ...outbound.gemini.gemini_client import GeminiClient
@ -14,7 +14,7 @@ from ...storage import upload_audio
from ...config import settings
from ... import worker
router = APIRouter(prefix="/jobs", dependencies=[Depends(verify_token)])
router = APIRouter(prefix="/jobs", dependencies=[Depends(require_admin)])
class JobResponse(BaseModel):
@ -124,7 +124,7 @@ async def _run_regenerate_audio(job_id: uuid.UUID) -> None:
async def regenerate_audio(
job_id: str,
db: AsyncSession = Depends(get_db),
token_data: dict = Depends(verify_token),
token_data: dict = Depends(require_admin),
) -> dict:
try:
uid = uuid.UUID(job_id)