feat(compute): /v1中继鉴权重写与平台用户余额视图
- relay 鉴权重写:JWT→引擎 PAT 逐用户归属,拒绝匿名调用,余额<=0 预检 403 - compute_client 增 list_engine_users/get_engine_user/sync_user_mirror 等 - 运营端新增 /admin/compute/platform-users 平台用户视图(引擎真实余额/折扣/用量)与充值镜像回写 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -188,8 +188,8 @@ async def adjust_user_quota(engine_user_id: int, value: int, mode: str = "add")
|
||||
- mode="add" 充值(增加余额)
|
||||
- mode="subtract" 扣减
|
||||
- mode="override" 直接设为该值
|
||||
``value`` 为配额单位(见 /api/status 的 quota_per_unit:500000 = $1)。
|
||||
被充值用户的其他 PAT/会话会实时扣除,额度耗尽时引擎返回 403。
|
||||
``value`` 为微元(人民币实际金额,1 元 = 1_000_000,见 compute-service meter.py)。
|
||||
额度耗尽时引擎 /v1 返回 403。
|
||||
"""
|
||||
return await _request(
|
||||
method="POST", path="/api/user/manage", headers=_admin_headers(),
|
||||
@@ -197,6 +197,50 @@ async def adjust_user_quota(engine_user_id: int, value: int, mode: str = "add")
|
||||
)
|
||||
|
||||
|
||||
async def list_engine_users(page: int = 1, page_size: int = 100, status: int = 1) -> list[dict]:
|
||||
"""分页拉取引擎用户(GET /api/user),返回 items 列表。"""
|
||||
data = await _request(
|
||||
method="GET",
|
||||
path=f"/api/user?status={int(status)}&type=-1&p={int(page)}&page_size={int(page_size)}",
|
||||
headers=_admin_headers(),
|
||||
)
|
||||
return (data.get("data") or {}).get("items") or []
|
||||
|
||||
|
||||
async def get_engine_user(engine_user_id: int) -> dict | None:
|
||||
"""按 id 取引擎用户(GET /api/user?id=),无则 None。"""
|
||||
data = await _request(
|
||||
method="GET", path=f"/api/user?id={int(engine_user_id)}&p=1&page_size=1",
|
||||
headers=_admin_headers(),
|
||||
)
|
||||
items = (data.get("data") or {}).get("items") or []
|
||||
return items[0] if items else None
|
||||
|
||||
|
||||
async def sync_user_mirror(db, engine_user_id: int) -> bool:
|
||||
"""把引擎用户余额回写到平台镜像(compute_quota/compute_used_quota)。
|
||||
|
||||
best-effort:引擎用户不存在或平台用户未映射时静默返回 False。
|
||||
"""
|
||||
try:
|
||||
engine_user = await get_engine_user(engine_user_id)
|
||||
username = str((engine_user or {}).get("username") or "")
|
||||
if not username:
|
||||
return False
|
||||
balance = await user_balance(username)
|
||||
platform_user = await db.users.get_by_username(username)
|
||||
if platform_user is None:
|
||||
return False
|
||||
await db.users.set_compute_mirror(
|
||||
platform_user["id"], provisioned=True, username=username,
|
||||
quota=int(balance.get("quota") or 0),
|
||||
used_quota=int(balance.get("used_quota") or 0),
|
||||
)
|
||||
return True
|
||||
except Exception: # noqa: BLE001
|
||||
return False
|
||||
|
||||
|
||||
async def set_user_group_by_username(username: str, group: str) -> dict:
|
||||
"""把引擎用户划到某个用户组(企业折扣凭 User.Group 触发组倍率)。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user