Spaces:
Build error
Build error
| """ | |
| 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"]) | |
| 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." | |
| } | |
| 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"], | |
| } | |
| 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, | |
| } | |