yumoqing 0f470fca61 fix: remove manual css/js references from shell.ui and load_path.py
- Remove Html widget in shell.ui that manually loaded shell_theme.css/js
  (ahserver auto-serves wwwroot js/css files)
- Remove shell_theme.css/js from load_path.py permission list
  (ahserver handles static resources automatically)
2026-05-26 07:36:52 +08:00

140 lines
4.5 KiB
Python

"""Generate RBAC permissions for dashboard_for_sage module paths.
Run from Sage root with Sage venv:
cd ~/repos/sage && ./py3/bin/python ../dashboard_for_sage/scripts/load_path.py
Or set SAGE_ROOT environment variable.
"""
import os
import sys
import asyncio
# Ensure Sage root is in path
sage_root = os.environ.get('SAGE_ROOT')
if sage_root and sage_root not in sys.path:
sys.path.insert(0, sage_root)
from sqlor.dbpools import DBPools
from appPublic.jsonConfig import getConfig
from appPublic.dictObject import DictObject
from appPublic.uniqueID import getID
# ── Permission definitions ──
# Format: (path, role)
# Dashboard files are accessible to all logined users except menu.ui (any)
paths = [
# Module root and index
("/dashboard_for_sage", "logined"),
("/dashboard_for_sage/index.ui", "logined"),
# Menu — must be any so unauthenticated users can see nav
("/dashboard_for_sage/menu.ui", "any"),
# Shell
("/dashboard_for_sage/shell.ui", "logined"),
# Global menu
("/dashboard_for_sage/global_menu.ui", "logined"),
# Stat cards
("/dashboard_for_sage/stat_today_usage.ui", "logined"),
("/dashboard_for_sage/stat_today_amount.ui", "logined"),
("/dashboard_for_sage/stat_total_users.ui", "logined"),
("/dashboard_for_sage/stat_active_users.ui", "logined"),
("/dashboard_for_sage/stat_concurrent.ui", "logined"),
("/dashboard_for_sage/stat_errors.ui", "logined"),
("/dashboard_for_sage/stat_new_users_month.ui", "logined"),
("/dashboard_for_sage/stat_total_orgs.ui", "logined"),
# Legacy stat cards (backward compat)
("/dashboard_for_sage/today_usage.ui", "logined"),
("/dashboard_for_sage/today_amount.ui", "logined"),
("/dashboard_for_sage/total_users.ui", "logined"),
("/dashboard_for_sage/concurrent_users.ui", "logined"),
("/dashboard_for_sage/accounting_errors.ui", "logined"),
# Top 5 ranking cards
("/dashboard_for_sage/table_top_users.ui", "logined"),
("/dashboard_for_sage/table_top_users_amount.ui", "logined"),
("/dashboard_for_sage/table_top_users_count.ui", "logined"),
("/dashboard_for_sage/table_top_providers_amount.ui", "logined"),
("/dashboard_for_sage/table_top_providers_count.ui", "logined"),
("/dashboard_for_sage/top_users_amount.ui", "logined"),
# Charts
("/dashboard_for_sage/chart_top_models.ui", "logined"),
("/dashboard_for_sage/top_models_chart.ui", "logined"),
# API endpoints
("/dashboard_for_sage/api/top_models.dspy", "logined"),
]
async def add_roleperm(sor, roleid, permid):
"""Add role-permission mapping if not exists."""
ns = {'roleid': roleid, 'permid': permid}
recs = await sor.R('rolepermission', ns.copy())
if not recs:
ns['id'] = getID()
await sor.C('rolepermission', ns.copy())
async def add_roles_perm(sor, perm, roles):
"""Register permission for special roles."""
if roles in [['any'], ['anonymous'], ['logined']]:
role = roles[0]
await add_roleperm(sor, role, perm.id)
return
for role in roles:
if '.' in role:
orgtypeid, name = role.split('.', 1)
else:
orgtypeid, name = '*', role
ns = {'orgtypeid': orgtypeid, 'name': name}
roles_rec = await sor.R('role', ns.copy())
if not roles_rec:
ns['id'] = getID()
await sor.C('role', ns.copy())
else:
ns['id'] = roles_rec[0].id
await add_roleperm(sor, ns['id'], perm.id)
# Remove 'any' fallback for this perm
ns_any = {'roleid': 'any', 'permid': perm.id}
existing = await sor.R('rolepermission', ns_any.copy())
if existing:
await sor.D('rolepermission', {'id': existing[0].id})
async def main():
config = getConfig('.')
db = DBPools(config.databases)
cnt = 0
async with db.sqlorContext('sage') as sor:
for path, role in paths:
ns = {'path': path}
recs = await sor.R('permission', ns.copy())
if recs:
# Permission exists, skip (idempotent)
continue
cnt += 1
pid = getID()
ns['id'] = pid
await sor.C('permission', ns.copy())
perm = DictObject(**ns)
await add_roles_perm(sor, perm, [role])
print(f'{cnt} path(s) inserted for dashboard_for_sage')
if cnt == 0:
print('All paths already registered — no changes needed.')
if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(main())