integrate sub2api as upstream for auth/keys/usage via FastAPI BFF
Preserve local user table for superDream-specific features while syncing user lifecycle, API key CRUD and usage queries through sub2api. Admin token handles reads and user lifecycle; per-user tokens (Fernet-encrypted in DB) handle key writes that admin endpoints do not expose. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
96
app/integrations/sub2api/user.py
Normal file
96
app/integrations/sub2api/user.py
Normal file
@@ -0,0 +1,96 @@
|
||||
"""User-JWT-authenticated calls to sub2api.
|
||||
|
||||
Used for:
|
||||
- Auth login / refresh / me (to obtain tokens for BFF proxying)
|
||||
- API Key CRUD (admin endpoints cannot create / delete keys)
|
||||
- Usage list / detail / dashboard for the authenticated user
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from app.integrations.sub2api.client import request, user_request
|
||||
|
||||
|
||||
# ── Auth (public; no Bearer required) ─────────────────────────────────
|
||||
|
||||
async def login(email: str, password: str) -> dict[str, Any]:
|
||||
"""Returns AuthResponse: {access_token, refresh_token, expires_in, token_type, user}."""
|
||||
return await request(
|
||||
"POST",
|
||||
"/auth/login",
|
||||
json={"email": email, "password": password, "turnstile_token": ""},
|
||||
)
|
||||
|
||||
|
||||
async def refresh_tokens(refresh_token: str) -> dict[str, Any]:
|
||||
"""Returns RefreshTokenResponse: {access_token, refresh_token, expires_in, token_type}."""
|
||||
return await request(
|
||||
"POST",
|
||||
"/auth/refresh",
|
||||
json={"refresh_token": refresh_token},
|
||||
)
|
||||
|
||||
|
||||
async def logout(refresh_token: str | None = None) -> dict[str, Any]:
|
||||
body = {"refresh_token": refresh_token} if refresh_token else {}
|
||||
return await request("POST", "/auth/logout", json=body)
|
||||
|
||||
|
||||
# ── API Key CRUD ──────────────────────────────────────────────────────
|
||||
|
||||
async def create_key(access_token: str, payload: dict[str, Any]) -> dict[str, Any]:
|
||||
return await user_request(access_token, "POST", "/keys", json=payload)
|
||||
|
||||
|
||||
async def update_key(access_token: str, key_id: int, payload: dict[str, Any]) -> dict[str, Any]:
|
||||
return await user_request(access_token, "PUT", f"/keys/{key_id}", json=payload)
|
||||
|
||||
|
||||
async def delete_key(access_token: str, key_id: int) -> dict[str, Any]:
|
||||
return await user_request(access_token, "DELETE", f"/keys/{key_id}")
|
||||
|
||||
|
||||
async def get_key(access_token: str, key_id: int) -> dict[str, Any]:
|
||||
return await user_request(access_token, "GET", f"/keys/{key_id}")
|
||||
|
||||
|
||||
# ── Groups ────────────────────────────────────────────────────────────
|
||||
|
||||
async def list_available_groups(access_token: str) -> list[dict[str, Any]]:
|
||||
return await user_request(access_token, "GET", "/groups/available")
|
||||
|
||||
|
||||
async def get_user_group_rates(access_token: str) -> dict[str, float]:
|
||||
return await user_request(access_token, "GET", "/groups/rates")
|
||||
|
||||
|
||||
# ── Usage (user view) ─────────────────────────────────────────────────
|
||||
|
||||
async def list_usage(access_token: str, **params: Any) -> dict[str, Any]:
|
||||
return await user_request(access_token, "GET", "/usage", params=params)
|
||||
|
||||
|
||||
async def usage_stats(access_token: str, **params: Any) -> dict[str, Any]:
|
||||
return await user_request(access_token, "GET", "/usage/stats", params=params)
|
||||
|
||||
|
||||
async def dashboard_stats(access_token: str) -> dict[str, Any]:
|
||||
return await user_request(access_token, "GET", "/usage/dashboard/stats")
|
||||
|
||||
|
||||
async def dashboard_trend(access_token: str, **params: Any) -> dict[str, Any]:
|
||||
return await user_request(access_token, "GET", "/usage/dashboard/trend", params=params)
|
||||
|
||||
|
||||
async def dashboard_models(access_token: str, **params: Any) -> dict[str, Any]:
|
||||
return await user_request(access_token, "GET", "/usage/dashboard/models", params=params)
|
||||
|
||||
|
||||
async def dashboard_api_keys_usage(access_token: str, api_key_ids: list[int]) -> dict[str, Any]:
|
||||
return await user_request(
|
||||
access_token,
|
||||
"POST",
|
||||
"/usage/dashboard/api-keys-usage",
|
||||
json={"api_key_ids": api_key_ids},
|
||||
)
|
||||
Reference in New Issue
Block a user