- 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)
140 lines
4.5 KiB
Python
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())
|