Add /admin/overview endpoint (member list + spend + co-op aggregates)

This commit is contained in:
inference-bot committed 2026-09-14 16:39:54 -06:00
1 parent 841eb70e4d
commit 9da67a9021
1 file changed
+59
+59
View File
@@ -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>.