Add /admin/overview endpoint (member list + spend + co-op aggregates)
This commit is contained in:
1 parent
841eb70e4d
commit
9da67a9021
1 file changed
+59
+59
@@ -1080,6 +1080,65 @@ async def admin_migrate_teams(token: str):
|
||||
return {"status": "migrated", "results": results}
|
||||
|
||||
|
||||
@app.get("/admin/overview/{token}")
|
||||
async def admin_overview(token: str):
|
||||
"""Return a co-op-wide overview for the admin dashboard.
|
||||
|
||||
Protected by the same secret token as the other /admin endpoints. Returns
|
||||
every member (active + inactive) with their balance, spend, remaining, and
|
||||
team reset date, plus co-op aggregates (total members, total spend).
|
||||
"""
|
||||
if not WEBHOOK_TOKEN or not secrets.compare_digest(token, WEBHOOK_TOKEN):
|
||||
raise HTTPException(401, "Invalid token")
|
||||
|
||||
conn = get_db()
|
||||
rows = conn.execute(
|
||||
"SELECT email, active, balance, cloudron_user_id FROM members ORDER BY email"
|
||||
).fetchall()
|
||||
conn.close()
|
||||
|
||||
# Fetch team spend/budget from LiteLLM once.
|
||||
teams = {}
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=15.0) as client:
|
||||
r = await client.get(
|
||||
f"{LITELLM_BASE}/team/list",
|
||||
headers={"Authorization": f"Bearer {LITELLM_MASTER_KEY}"},
|
||||
)
|
||||
r.raise_for_status()
|
||||
for t in r.json():
|
||||
teams[t.get("team_alias")] = t
|
||||
except Exception as e:
|
||||
logger.warning("admin overview: team/list failed: %s", e)
|
||||
|
||||
members = []
|
||||
total_spend = 0.0
|
||||
for email, active, balance, user_id in rows:
|
||||
team = teams.get(f"member:{email}", {})
|
||||
spend = float(team.get("spend") or 0.0)
|
||||
total_spend += spend
|
||||
members.append(
|
||||
{
|
||||
"email": email,
|
||||
"active": bool(active),
|
||||
"balance": float(balance) if balance is not None else MEMBER_BUDGET,
|
||||
"spend": spend,
|
||||
"remaining": max((balance or MEMBER_BUDGET) - spend, 0.0),
|
||||
"reset_at": team.get("budget_reset_at"),
|
||||
"cloudron_user_id": user_id,
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
"members": members,
|
||||
"totals": {
|
||||
"members": len(members),
|
||||
"active": sum(1 for m in members if m["active"]),
|
||||
"total_spend": total_spend,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
async def litellm_delete_keys_by_alias(email: str) -> None:
|
||||
"""Delete all LiteLLM keys whose alias matches member:<email>.
|
||||
|
||||
|
||||
Reference in new issue
Block a user