ticket/scripts/load_path.py

89 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""RBAC path registration for ticket module (pipeline format).
从应用根执行py3/bin/python pkgs/ticket/scripts/load_path.py
load_path.sh 自动扫描 pkgs/*/scripts/load_path.py 并调用本脚本)
权限设计(设计文档 §7.2,逐个精确配不用统一兜底):
- logined模块页面壳 + 全部 API。
⚠ staff 动作端点claim/staff_reply/transfer/transfer_candidates/staff_tickets
只能授 logined 而不能授固定角色——D4 决策:转派目标是 owner 组织类型下的
**任意动态角色**role 表运行时可增删RBAC 路径权限无法枚举动态角色,
业务权限由服务端 _check_staff_access 校验(操作者须持有工单 assignee_role
admin/superuser 豁免)。客户侧数据由 I5 服务端自过滤customer_user_id/org_id
- owner.maintainer / owner.admin / owner.superuser管理页壳 /ticket/manage/**。
菜单「工单管理」入口也按角色 Jinja 分支渲染,客户直接访问 URL 403。
"""
import sys
import os
import asyncio
# 应用根:本脚本在 pkgs/ticket/scripts/ 下,上溯三级
APP_ROOT = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../.."))
sys.path.insert(0, os.path.join(APP_ROOT, "py3", "lib", "python3.10", "site-packages"))
sys.path.insert(0, APP_ROOT)
from sqlor.dbpools import DBPools
from appPublic.jsonConfig import getConfig
from appPublic.uniqueID import getID
MOD = "ticket"
PATHS_LOGINED = [
# 客户侧页面
f"/{MOD}/my",
f"/{MOD}/my/index.ui",
f"/{MOD}/my/new_ticket_form.ui",
# 客户侧 APII5 服务端自过滤)
f"/{MOD}/api/ticket_create.dspy",
f"/{MOD}/api/my_tickets.dspy",
f"/{MOD}/api/ticket_detail.dspy",
f"/{MOD}/api/ticket_detail_popup.dspy",
f"/{MOD}/api/ticket_followup.dspy",
f"/{MOD}/api/ticket_confirm.dspy",
f"/{MOD}/api/ticket_cancel.dspy",
# staff 侧 API服务端 _check_staff_access 按工单 assignee_role 动态校验)
f"/{MOD}/api/staff_tickets.dspy",
f"/{MOD}/api/ticket_claim.dspy",
f"/{MOD}/api/ticket_staff_reply.dspy",
f"/{MOD}/api/ticket_transfer.dspy",
f"/{MOD}/api/transfer_candidates.dspy",
]
# 管理页壳:运维三角色
PATHS_STAFF = [
f"/{MOD}/manage",
f"/{MOD}/manage/index.ui",
]
STAFF_ROLES = ["owner.maintainer", "owner.admin", "owner.superuser"]
async def main():
config = getConfig(APP_ROOT, NS={"workdir": APP_ROOT})
DBPools(config.databases)
cnt = 0
async with DBPools().sqlorContext("pipeline") as sor:
pairs = [("logined", p) for p in PATHS_LOGINED]
for role in STAFF_ROLES:
pairs += [(role, p) for p in PATHS_STAFF]
for role, path in pairs:
recs = await sor.R("permission", {"path": path})
if recs:
permid = recs[0].id
else:
permid = getID()
await sor.C("permission", {"id": permid, "path": path})
rp = await sor.R("rolepermission", {"roleid": role, "permid": permid})
if not rp:
await sor.C("rolepermission", {
"id": getID(), "roleid": role, "permid": permid})
cnt += 1
await sor.sqlExe("COMMIT", {})
print(f"ticket load_path: {cnt} path-role entries ensured "
f"({len(PATHS_LOGINED)} logined + {len(PATHS_STAFF)}x{len(STAFF_ROLES)} staff)")
if __name__ == "__main__":
asyncio.run(main())