105 lines
3.5 KiB
Python

"""Permission initialization utility for business modules.
Scans wwwroot directory for .ui and .dspy files, registers them in
the permission table, and grants access to convention roles.
Convention roles:
- any: anyone (no auth required)
- logined: any logged-in user
- customer.*: customer org arbitrary role
- owner.*: owner org arbitrary role
- owner.superuser: superuser for initialization
"""
import os
from appPublic.uniqueID import getID
from appPublic.log import debug
from sqlor.dbpools import DBPools
def collect_ui_dspy_paths(wwwroot_dir):
"""Scan wwwroot directory and return list of URL paths for .ui/.dspy files."""
paths = []
for dirpath, _, filenames in os.walk(wwwroot_dir):
for fn in sorted(filenames):
if fn.endswith(('.ui', '.dspy')):
full = os.path.join(dirpath, fn)
rel = os.path.relpath(full, wwwroot_dir)
# Convert to URL path: module_name/relative/path
url = '/' + rel.replace(os.sep, '/')
# Skip base.ui (layout template, not a standalone page)
if fn == 'base.ui':
continue
paths.append(url)
return paths
async def ensure_permission(sor, path, permtype='page'):
"""Ensure permission exists in database, return permid."""
recs = await sor.R('permission', {'path': path})
if recs:
return recs[0].id
permid = getID()
await sor.C('permission', {
'id': permid,
'name': path.split('/')[-1],
'path': path,
'permtype': permtype,
})
return permid
async def ensure_role(sor, orgtypeid, name):
"""Ensure role exists in database, return roleid."""
recs = await sor.R('role', {'orgtypeid': orgtypeid, 'name': name})
if recs:
return recs[0].id
roleid = getID()
await sor.C('role', {
'id': roleid,
'orgtypeid': orgtypeid,
'name': name,
})
return roleid
async def grant_permission(sor, roleid, permid):
"""Grant permission to role if not already granted."""
recs = await sor.R('rolepermission', {'roleid': roleid, 'permid': permid})
if not recs:
await sor.C('rolepermission', {
'id': getID(),
'roleid': roleid,
'permid': permid,
})
async def init_module_permissions(dbname, module_name, wwwroot_dir):
"""Initialize permissions for a business module.
Scans wwwroot for .ui/.dspy files, registers paths in permission table,
and grants access to convention roles (logined, customer.*, owner.superuser).
"""
paths = collect_ui_dspy_paths(wwwroot_dir)
if not paths:
debug(f'{module_name}: no UI/DSPY paths found, skipping permission init')
return
db = DBPools()
async with db.sqlorContext(dbname) as sor:
# Ensure convention roles exist
role_logined = await ensure_role(sor, '*', 'logined')
role_customer = await ensure_role(sor, 'customer', '*')
role_superuser = await ensure_role(sor, 'owner', 'superuser')
# Register paths and grant permissions
for path in paths:
permid = await ensure_permission(sor, path)
# Grant to logined users
await grant_permission(sor, role_logined, permid)
# Grant to customer org users
await grant_permission(sor, role_customer, permid)
# Grant to superuser
await grant_permission(sor, role_superuser, permid)
debug(f'{module_name}: registered {len(paths)} permissions')