133 lines
5.6 KiB
Python
133 lines
5.6 KiB
Python
"""pbl_blueprint 模块 RBAC 路径注册脚本。
|
||
|
||
用途:把本模块全部新 API 路径 + 页面路径注册到平台 RBAC(权限路径表),
|
||
使 owner.admin / 租户管理员可授权,未注册路径一律 403。
|
||
|
||
执行方式(应用部署后一次性 / 幂等可重复执行):
|
||
python -m pbl_blueprint.scripts.load_path
|
||
或在应用 init() 后由部署脚本调用 load_paths(env)。
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
|
||
MODULE_NAME = 'pbl_blueprint'
|
||
|
||
# ---- 本模块全部新 API 路径(与 api.py 的 API_PATHS 保持一致,单一事实源)----
|
||
API_PATHS = [
|
||
('/pbl_blueprint/blueprint/create', 'POST', '新建蓝图'),
|
||
('/pbl_blueprint/blueprint/update', 'POST', '更新蓝图'),
|
||
('/pbl_blueprint/blueprint/delete', 'POST', '删除蓝图'),
|
||
('/pbl_blueprint/blueprint/get', 'GET', '蓝图详情'),
|
||
('/pbl_blueprint/blueprint/list', 'GET', '蓝图列表'),
|
||
('/pbl_blueprint/blueprint/tree', 'GET', '蓝图子对象树'),
|
||
('/pbl_blueprint/blueprint/fork', 'POST', '复制蓝图'),
|
||
('/pbl_blueprint/version/save', 'POST', '保存版本快照'),
|
||
('/pbl_blueprint/version/list', 'GET', '版本列表'),
|
||
('/pbl_blueprint/version/diff', 'GET', '版本对比'),
|
||
('/pbl_blueprint/version/rollback', 'POST', '版本回滚'),
|
||
('/pbl_blueprint/subobject/create', 'POST', '新建子对象'),
|
||
('/pbl_blueprint/subobject/update', 'POST', '更新子对象'),
|
||
('/pbl_blueprint/subobject/delete', 'POST', '删除子对象'),
|
||
('/pbl_blueprint/subobject/get', 'GET', '子对象详情'),
|
||
('/pbl_blueprint/subobject/list', 'GET', '子对象列表'),
|
||
('/pbl_blueprint/subobject/batch_upsert', 'POST', '批量写子对象'),
|
||
('/pbl_blueprint/subobject/types', 'GET', '子对象类型枚举'),
|
||
('/pbl_blueprint/template/create', 'POST', '新建模板'),
|
||
('/pbl_blueprint/template/update', 'POST', '更新模板'),
|
||
('/pbl_blueprint/template/delete', 'POST', '删除模板'),
|
||
('/pbl_blueprint/template/get', 'GET', '模板详情'),
|
||
('/pbl_blueprint/template/list', 'GET', '模板列表'),
|
||
('/pbl_blueprint/template/instantiate', 'POST', '模板实例化为蓝图'),
|
||
('/pbl_blueprint/template/offline_fallback', 'POST', '离线兜底生成蓝图'),
|
||
]
|
||
|
||
# ---- 页面路径(wwwroot/*.ui 挂载点)----
|
||
PAGE_PATHS = [
|
||
('/pbl_blueprint/index', 'GET', 'PBL蓝图管理主页'),
|
||
('/pbl_blueprint/blueprint/edit', 'GET', '蓝图编辑页'),
|
||
('/pbl_blueprint/template/list', 'GET', '蓝图模板库页'),
|
||
]
|
||
|
||
# ---- 表级数据权限路径(CRUD 定义 json/*.json 对应)----
|
||
TABLE_PATHS = [
|
||
('/pbl_blueprint/tbl/pbl_blueprint', 'CRUD', '蓝图主表数据权限'),
|
||
('/pbl_blueprint/tbl/pbl_blueprint_version', 'CRUD', '蓝图版本表数据权限'),
|
||
('/pbl_blueprint/tbl/pbl_blueprint_template', 'CRUD', '蓝图模板表数据权限'),
|
||
('/pbl_blueprint/tbl/pbl_blueprint_template_item', 'CRUD', '蓝图模板条目表数据权限'),
|
||
('/pbl_blueprint/tbl/pbl_blueprint_task', 'CRUD', '子对象-任务数据权限'),
|
||
('/pbl_blueprint/tbl/pbl_blueprint_mission', 'CRUD', '子对象-关卡数据权限'),
|
||
('/pbl_blueprint/tbl/pbl_blueprint_role', 'CRUD', '子对象-角色数据权限'),
|
||
('/pbl_blueprint/tbl/pbl_blueprint_learning_goal', 'CRUD', '子对象-学习目标数据权限'),
|
||
('/pbl_blueprint/tbl/pbl_blueprint_evidence_spec', 'CRUD', '子对象-证据规格数据权限'),
|
||
('/pbl_blueprint/tbl/pbl_blueprint_artifact_spec', 'CRUD', '子对象-产出物规格数据权限'),
|
||
('/pbl_blueprint/tbl/pbl_blueprint_reflection_spec', 'CRUD', '子对象-反思规格数据权限'),
|
||
]
|
||
|
||
ALL_PATHS = API_PATHS + PAGE_PATHS + TABLE_PATHS
|
||
|
||
|
||
def load_paths(env=None):
|
||
"""把 ALL_PATHS 注册进 RBAC(幂等:存在则更新描述,不存在则新增)。
|
||
|
||
:return: {'registered': n, 'skipped': m, 'failed': k}
|
||
"""
|
||
result = {'registered': 0, 'skipped': 0, 'failed': 0, 'paths': []}
|
||
if env is None:
|
||
try:
|
||
from sage import ServerEnv
|
||
env = ServerEnv()
|
||
except Exception:
|
||
env = None
|
||
|
||
rbac = None
|
||
if env is not None:
|
||
for attr in ('rbac', 'RBAC'):
|
||
rbac = getattr(env, attr, None)
|
||
if rbac is not None:
|
||
break
|
||
if rbac is None:
|
||
getter = getattr(env, 'get_rbac', None)
|
||
if callable(getter):
|
||
try:
|
||
rbac = getter()
|
||
except Exception:
|
||
rbac = None
|
||
|
||
for path, method, caption in ALL_PATHS:
|
||
item = {'path': path, 'method': method, 'caption': caption, 'module': MODULE_NAME}
|
||
result['paths'].append(item)
|
||
if rbac is None:
|
||
result['skipped'] += 1
|
||
continue
|
||
try:
|
||
registered = False
|
||
for fn_name in ('register_path', 'add_path', 'load_path', 'register'):
|
||
fn = getattr(rbac, fn_name, None)
|
||
if callable(fn):
|
||
try:
|
||
fn(path, method, caption)
|
||
except TypeError:
|
||
fn(item)
|
||
registered = True
|
||
break
|
||
if registered:
|
||
result['registered'] += 1
|
||
else:
|
||
result['skipped'] += 1
|
||
except Exception:
|
||
result['failed'] += 1
|
||
return result
|
||
|
||
|
||
def main():
|
||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||
res = load_paths()
|
||
print('[pbl_blueprint] load_path done: registered=%d skipped=%d failed=%d total=%d' % (
|
||
res['registered'], res['skipped'], res['failed'], len(res['paths'])))
|
||
return 0
|
||
|
||
|
||
if __name__ == '__main__':
|
||
sys.exit(main())
|