File size: 3,542 Bytes
2d521fd
bc549c5
2d521fd
 
 
bc549c5
 
 
2d521fd
 
bc549c5
2d521fd
bc549c5
 
2d521fd
 
 
 
 
 
 
 
 
bc549c5
 
 
 
 
2d521fd
bc549c5
2d521fd
 
 
bc549c5
2d521fd
bc549c5
 
 
 
 
 
 
 
 
 
 
 
2d521fd
bc549c5
 
 
2d521fd
bc549c5
 
 
2d521fd
 
 
 
bc549c5
2d521fd
bc549c5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2d521fd
 
 
6d20eab
bc549c5
 
 
2d521fd
bc549c5
2d521fd
 
 
 
 
bc549c5
2d521fd
 
bc549c5
2d521fd
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""
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,
    }