fix(load_path): review修复——单事件循环直连注册(去掉600+次subprocess),get_accdetail恢复page/sort

This commit is contained in:
yumoqing 2026-08-27 18:17:45 +08:00
parent 89592b9585
commit 411d1017cf
2 changed files with 84 additions and 88 deletions

View File

@ -48,7 +48,9 @@ where b.subjectid = c.id
""" """
ns = { ns = {
'accountid': accountid, 'accountid': accountid,
'orgid': userorgid 'orgid': userorgid,
'page': page,
'sort': 'acc_date desc'
} }
ret = await sor.sqlExe(sql, ns) ret = await sor.sqlExe(sql, ns)
return ret return ret

View File

@ -22,11 +22,10 @@ accounting 模块 RBAC 权限管理脚本(角色分层版,2026-08-27 重构
用 orgtypeid+name 查 role 表解析出真实 role.id 后注册,同名多条全部注册。 用 orgtypeid+name 查 role 表解析出真实 role.id 后注册,同名多条全部注册。
使用方法: 使用方法:
cd <app root>(含 py3/ 与 set_role_perm.py 的目录,如 /d/pipeline/pipeline-app) cd <app root>(含 py3/ 的目录,如 /d/pipeline/pipeline-app)
./py3/bin/python pkgs/accounting/scripts/load_path.py [--add-only] ./py3/bin/python pkgs/accounting/scripts/load_path.py [--add-only]
""" """
import subprocess
import os import os
import sys import sys
import asyncio import asyncio
@ -51,9 +50,6 @@ if not APP_ROOT:
print("ERROR: Cannot find app root directory") print("ERROR: Cannot find app root directory")
sys.exit(1) sys.exit(1)
PYTHON = os.path.join(APP_ROOT, "py3", "bin", "python")
SET_PERM_SCRIPT = os.path.join(APP_ROOT, "set_role_perm.py")
MOD = "accounting" MOD = "accounting"
# ============================================================ # ============================================================
@ -252,102 +248,100 @@ async def _find_rbac_db(db):
return None return None
async def resolve_role_ids(labels): async def resolve_role_ids(sor, labels):
"""标签 'orgtypeid.name' → 真实 role.id 列表(同名多条全返回)。""" """标签 'orgtypeid.name' → 真实 role.id 列表(同名多条全返回)。"""
db = _get_db()
dbname = await _find_rbac_db(db)
mapping = {} mapping = {}
if not dbname: for label in labels:
print('WARN: role 表不可达,按字面量注册(可能无效)') if label in ('any', 'logined', 'anonymous'):
return {lb: [lb] for lb in labels} mapping[label] = [label]
async with db.sqlorContext(dbname) as sor: continue
for label in labels: orgtypeid, _, name = label.partition('.')
if label in ('any', 'logined', 'anonymous'): recs = await sor.sqlExe(
mapping[label] = [label] 'select id from role where orgtypeid=${o}$ and name=${n}$',
continue {'o': orgtypeid, 'n': name})
orgtypeid, _, name = label.partition('.') ids = [_row_get(r, 'id') for r in recs]
recs = await sor.sqlExe( ids = [i for i in ids if i]
'select id from role where orgtypeid=${o}$ and name=${n}$', if not ids:
{'o': orgtypeid, 'n': name}) print(f'WARN: 角色不存在 {label},跳过')
ids = [_row_get(r, 'id') for r in recs] mapping[label] = ids
ids = [i for i in ids if i]
if not ids:
print(f'WARN: 角色不存在 {label},跳过')
mapping[label] = ids
await sor.sqlExe('COMMIT', {})
return mapping return mapping
async def clean_accounting_roleperms(): async def set_role_perm(sor, role_id, path):
"""删除 /accounting/ 下全部旧授权(保留 permission 行本身)。""" """注册单条权限(幂等):permission 缺则建,rolepermission 缺则建。"""
db = _get_db() from appPublic.uniqueID import getID
dbname = await _find_rbac_db(db) recs = await sor.R('permission', {'path': path})
if not dbname: if not recs:
print('ERROR: 无法定位 RBAC 库,清理中止') permid = getID()
return -1 await sor.C('permission', {'id': permid, 'path': path})
total = 0 else:
async with db.sqlorContext(dbname) as sor: permid = _row_get(recs[0], 'id')
perms = await sor.sqlExe( rp = await sor.R('rolepermission', {'roleid': role_id, 'permid': permid})
'select id from permission where path like ${p}$ or path=${p2}$', if rp:
{'p': f'/{MOD}/%', 'p2': f'/{MOD}'})
for p in perms:
pid = _row_get(p, 'id')
r = await sor.sqlExe('delete from rolepermission where permid=${pid}$', {'pid': pid})
total += 1
await sor.sqlExe('COMMIT', {})
print(f'清理完成:/accounting/ 下 {len(perms)} 个 permission 的旧授权已删除')
return total
# ============================================================
# 注册
# ============================================================
def run_set_perm(role_id, path):
cmd = [PYTHON, SET_PERM_SCRIPT, role_id, path]
result = subprocess.run(cmd, capture_output=True, text=True, cwd=APP_ROOT)
if result.returncode != 0:
print(f" FAIL {role_id} {path}: {(result.stderr or result.stdout).strip()[:200]}")
return False return False
await sor.C('rolepermission', {'id': getID(), 'roleid': role_id, 'permid': permid})
return True return True
def register_role_paths(role_label, role_ids, paths): async def run_all(add_only):
if not role_ids: db = _get_db()
return 0 dbname = await _find_rbac_db(db)
count = 0 if not dbname:
for rid in role_ids: print('ERROR: 无法定位 RBAC 库(role 表不可达),中止')
for p in paths: return 1
if run_set_perm(rid, p): print(f'RBAC 库: {dbname}')
count += 1
print(f" {role_label} ({','.join(role_ids)}): {count}/{len(paths) * len(role_ids)} entries registered") total = 0
return count async with db.sqlorContext(dbname) as sor:
if not add_only:
print('=== 清理旧授权 ===')
perms = await sor.sqlExe(
'select id from permission where path like ${p}$ or path=${p2}$',
{'p': f'/{MOD}/%', 'p2': f'/{MOD}'})
for p in perms:
await sor.sqlExe('delete from rolepermission where permid=${pid}$',
{'pid': _row_get(p, 'id')})
await sor.sqlExe('COMMIT', {})
print(f'清理完成:/accounting/ 下 {len(perms)} 个 permission 的旧授权已删除')
print('=== 解析角色 ===')
all_labels = sorted(set(FIN_ROLES + PROXY_ROLES))
role_map = await resolve_role_ids(sor, all_labels)
for lb in all_labels:
print(f' {lb} -> {role_map.get(lb) or "(不存在)"}')
print('=== 注册新矩阵 ===')
async def register_group(group_label, role_ids, paths):
nonlocal total
if not role_ids:
return
added = 0
for rid in role_ids:
for p in paths:
if await set_role_perm(sor, rid, p):
added += 1
await sor.sqlExe('COMMIT', {})
total += added
print(f' {group_label} ({",".join(role_ids)}): +{added} 条'
f'(目标 {len(paths) * len(role_ids)} 条,其余为已存在)')
await register_group('any', ['any'], PATHS_ANY)
await register_group('logined', ['logined'], PATHS_LOGINED)
for label in FIN_ROLES:
await register_group(label, role_map.get(label, []), PATHS_FIN)
for label in PROXY_ROLES:
await register_group(label, role_map.get(label, []), PATHS_PROXY)
print(f'\nDone. 本次新增 {total} 条授权。')
print('NOTE: 重启应用(或调用 /rbac/refresh_userperm.dspy)后权限生效。')
return 0
def main(): def main():
add_only = '--add-only' in sys.argv add_only = '--add-only' in sys.argv
print(f"App root: {APP_ROOT}") print(f"App root: {APP_ROOT}")
sys.exit(asyncio.run(run_all(add_only)))
if not add_only:
print('=== 清理旧授权 ===')
asyncio.run(clean_accounting_roleperms())
print('=== 解析角色 ===')
all_labels = sorted(set(FIN_ROLES + PROXY_ROLES))
role_map = asyncio.run(resolve_role_ids(all_labels))
for lb in all_labels:
print(f' {lb} -> {role_map.get(lb) or "(不存在)"}')
print('=== 注册新矩阵 ===')
total = 0
total += register_role_paths('any', ['any'], PATHS_ANY)
total += register_role_paths('logined', ['logined'], PATHS_LOGINED)
for label in FIN_ROLES:
total += register_role_paths(label, role_map.get(label, []), PATHS_FIN)
for label in PROXY_ROLES:
total += register_role_paths(label, role_map.get(label, []), PATHS_PROXY)
print(f"\nDone. Total {total} permission entries registered.")
print("NOTE: 重启应用(或调用 /rbac/refresh_userperm.dspy)后权限生效。")
if __name__ == "__main__": if __name__ == "__main__":