""" User endpoints – registration, tenant creation, quota information. """ import uuid from datetime import datetime from fastapi import APIRouter, Depends, HTTPException, Request, Query from sqlalchemy.orm import Session from slowapi import Limiter from slowapi.util import get_remote_address from app.core.usage_tracker import tracker, enforce_quota, Tier from app.api.deps import get_db from app.database.models_intents import TenantDB # <-- NEW router = APIRouter(prefix="/users", tags=["users"]) # Rate limiter for registration (5 per hour per IP) limiter = Limiter(key_func=get_remote_address, default_limits=["5/hour"]) @router.post("/register") @limiter.limit("5/hour") async def register_user( request: Request, db: Session = Depends(get_db), org_name: str = Query(None, description="Optional organisation name for the new tenant"), ): """ Public endpoint to create a new free‑tier API key and a new tenant. Rate‑limited to 5 requests per hour per IP address. """ if tracker is None: raise HTTPException(status_code=503, detail="Usage tracking service not initialised") # 1. Create a new tenant in the main database tenant_id = str(uuid.uuid4()) name = org_name or "Default Organization" new_tenant = TenantDB( id=tenant_id, name=name, created_at=datetime.utcnow(), created_by="self_service" ) db.add(new_tenant) db.commit() db.refresh(new_tenant) # 2. Generate a new API key for this tenant new_key = f"sk_free_{uuid.uuid4().hex[:24]}" success = tracker.get_or_create_api_key(api_key=new_key, tenant_id=tenant_id, tier=Tier.FREE) if not success: # Rollback tenant creation if key creation fails db.delete(new_tenant) db.commit() raise HTTPException(status_code=500, detail="Failed to create API key") return { "api_key": new_key, "tenant_id": tenant_id, "tier": "free", "organization": name, "message": "API key and tenant created. Store the key securely – you won't see it again." } @router.get("/me") async def get_current_user_info( request: Request, quota: dict = Depends(enforce_quota), db: Session = Depends(get_db), ): """ Return information about the current user's tenant and quota. Requires API key in Authorization header. """ tenant_id = quota.get("tenant_id") if not tenant_id: raise HTTPException(status_code=403, detail="No tenant associated with this API key") tenant = db.query(TenantDB).filter(TenantDB.id == tenant_id).first() if not tenant: raise HTTPException(status_code=404, detail="Tenant not found") return { "tenant_id": tenant_id, "organization": tenant.name, "created_at": tenant.created_at.isoformat() if tenant.created_at else None, "tier": quota["tier"].value, "remaining": quota["remaining"], "limit": quota["limit"], } @router.get("/quota") async def get_user_quota( request: Request, quota: dict = Depends(enforce_quota), ): """ Return the current user's tier, remaining quota, and tenant ID. Requires API key in Authorization header. """ tier = quota["tier"] remaining = quota["remaining"] limit = tier.monthly_evaluation_limit if tier else None tenant_id = quota.get("tenant_id") return { "tenant_id": tenant_id, "tier": tier.value, "remaining": remaining, "limit": limit, }