Multi-tenant Claude Code monitoring dashboard. FastAPI + PostgreSQL + Docker + SSE real-time updates. Montserrat font, black/#FFC407 color scheme. Apache reverse proxy config at /cc-dashboard/. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
41 lines
1.6 KiB
Python
41 lines
1.6 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from src.auth import CurrentUser, generate_api_key
|
|
from src.database import get_db
|
|
from src.models import ApiKey
|
|
from src.schemas import ApiKeyCreate, ApiKeyCreated, ApiKeyOut
|
|
|
|
router = APIRouter(prefix="/api/keys", tags=["keys"])
|
|
|
|
|
|
@router.get("", response_model=list[ApiKeyOut])
|
|
async def list_keys(user: CurrentUser, db: AsyncSession = Depends(get_db)):
|
|
result = await db.execute(
|
|
select(ApiKey).where(ApiKey.user_id == user.id).order_by(ApiKey.created_at.desc())
|
|
)
|
|
return result.scalars().all()
|
|
|
|
|
|
@router.post("", response_model=ApiKeyCreated, status_code=status.HTTP_201_CREATED)
|
|
async def create_key(body: ApiKeyCreate, user: CurrentUser, db: AsyncSession = Depends(get_db)):
|
|
raw_key, prefix, key_hash = generate_api_key()
|
|
key = ApiKey(user_id=user.id, key_hash=key_hash, key_prefix=prefix, label=body.label)
|
|
db.add(key)
|
|
await db.commit()
|
|
await db.refresh(key)
|
|
return ApiKeyCreated(
|
|
id=key.id, label=key.label, key_prefix=key.key_prefix,
|
|
is_active=key.is_active, last_used_at=key.last_used_at,
|
|
created_at=key.created_at, raw_key=raw_key,
|
|
)
|
|
|
|
|
|
@router.delete("/{key_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
async def revoke_key(key_id: str, user: CurrentUser, db: AsyncSession = Depends(get_db)):
|
|
key = await db.get(ApiKey, key_id)
|
|
if not key or key.user_id != user.id:
|
|
raise HTTPException(status_code=404, detail="Key not found")
|
|
key.is_active = False
|
|
await db.commit()
|