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>
96 lines
3.8 KiB
Python
96 lines
3.8 KiB
Python
"""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},
|
|
) |