refactor: load_path.py自动扫描json/和api/目录生成完整权限路径
- 从json/*.json自动提取tblname和alias,生成所有CRUD路径 - 自动扫描wwwroot/api/*.dspy注册所有API路径 - 去重处理,避免重复注册 - operator获得全部CRUD+API权限,sale获得促销码+客户归属权限
This commit is contained in:
parent
95b91c4c25
commit
b8a5de7a07
@ -11,13 +11,15 @@ discount 模块 RBAC 权限管理脚本
|
|||||||
路径分类:
|
路径分类:
|
||||||
- any: 静态资源/菜单/CRUD别名目录
|
- any: 静态资源/菜单/CRUD别名目录
|
||||||
- logined: 需要认证的页面和 API
|
- logined: 需要认证的页面和 API
|
||||||
- reseller.operator: 运营角色 — 折扣方案、营销方案、客户归属管理
|
- reseller.operator: 运营角色 — 全部折扣管理功能
|
||||||
- reseller.sale: 销售角色 — 促销码、客户归属查看
|
- reseller.sale: 销售角色 — 促销码、客户归属
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import json
|
||||||
|
import glob
|
||||||
|
|
||||||
def find_sage_root():
|
def find_sage_root():
|
||||||
candidates = [
|
candidates = [
|
||||||
@ -43,23 +45,58 @@ if not os.path.exists(SET_PERM_SCRIPT):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
MOD = "discount"
|
MOD = "discount"
|
||||||
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
JSON_DIR = os.path.join(os.path.dirname(SCRIPT_DIR), "json")
|
||||||
|
API_DIR = os.path.join(os.path.dirname(SCRIPT_DIR), "wwwroot", "api")
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 权限路径定义 — 每次新增页面或API时同步更新
|
# 从 json/ 目录自动推导 CRUD 路径
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
|
def load_crud_definitions():
|
||||||
|
"""读取所有 json/*.json,提取 CRUD 定义信息"""
|
||||||
|
defs = []
|
||||||
|
for f in sorted(glob.glob(os.path.join(JSON_DIR, "*.json"))):
|
||||||
|
try:
|
||||||
|
d = json.load(open(f))
|
||||||
|
tblname = d.get("tblname", "")
|
||||||
|
alias = d.get("alias", tblname)
|
||||||
|
params = d.get("params", {})
|
||||||
|
subtables = params.get("subtables", [])
|
||||||
|
defs.append({
|
||||||
|
"tblname": tblname,
|
||||||
|
"alias": alias,
|
||||||
|
"subtables": subtables,
|
||||||
|
"file": f,
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
print(f" WARNING: skip {f}: {e}")
|
||||||
|
return defs
|
||||||
|
|
||||||
|
def get_api_files():
|
||||||
|
"""扫描 wwwroot/api/ 下所有 .dspy 文件"""
|
||||||
|
apis = []
|
||||||
|
if os.path.isdir(API_DIR):
|
||||||
|
for f in sorted(os.listdir(API_DIR)):
|
||||||
|
if f.endswith(".dspy"):
|
||||||
|
apis.append(f"/{MOD}/api/{f}")
|
||||||
|
return apis
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 构建路径列表
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
crud_defs = load_crud_definitions()
|
||||||
|
print(f"Found {len(crud_defs)} CRUD definitions in {JSON_DIR}")
|
||||||
|
for d in crud_defs:
|
||||||
|
print(f" - {d['tblname']} (alias: {d['alias']})")
|
||||||
|
|
||||||
# any — 无需登录(菜单、CRUD别名目录)
|
# any — 无需登录(菜单、CRUD别名目录)
|
||||||
PATHS_ANY = [
|
PATHS_ANY = [
|
||||||
f"/{MOD}/menu.ui",
|
f"/{MOD}/menu.ui",
|
||||||
# CRUD alias directories
|
|
||||||
f"/{MOD}/discount_list",
|
|
||||||
f"/{MOD}/discount_detail_list",
|
|
||||||
f"/{MOD}/discount_marketing_list",
|
|
||||||
f"/{MOD}/discount_promo_code_list",
|
|
||||||
f"/{MOD}/discount_customer_bind_list",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# logined — 需要认证的页面和 API
|
# 每个 CRUD 定义 → any 别名目录 + logined 页面和脚本
|
||||||
PATHS_LOGINED = [
|
PATHS_LOGINED = [
|
||||||
# 模块入口
|
# 模块入口
|
||||||
f"/{MOD}",
|
f"/{MOD}",
|
||||||
@ -69,142 +106,83 @@ PATHS_LOGINED = [
|
|||||||
f"/{MOD}/promote",
|
f"/{MOD}/promote",
|
||||||
f"/{MOD}/promote.ui",
|
f"/{MOD}/promote.ui",
|
||||||
f"/{MOD}/promote/index.dspy",
|
f"/{MOD}/promote/index.dspy",
|
||||||
# CRUD 列表页
|
|
||||||
f"/{MOD}/discount_list/index.ui",
|
|
||||||
f"/{MOD}/discount_detail_list/index.ui",
|
|
||||||
f"/{MOD}/discount_marketing_list/index.ui",
|
|
||||||
f"/{MOD}/discount_promo_code_list/index.ui",
|
|
||||||
f"/{MOD}/discount_customer_bind_list/index.ui",
|
|
||||||
# CRUD auto-generated .dspy — discount
|
|
||||||
f"/{MOD}/discount_list/get_discount.dspy",
|
|
||||||
f"/{MOD}/discount_list/add_discount.dspy",
|
|
||||||
f"/{MOD}/discount_list/update_discount.dspy",
|
|
||||||
f"/{MOD}/discount_list/delete_discount.dspy",
|
|
||||||
# CRUD auto-generated .dspy — discount_detail
|
|
||||||
f"/{MOD}/discount_detail_list/get_discount_detail.dspy",
|
|
||||||
f"/{MOD}/discount_detail_list/add_discount_detail.dspy",
|
|
||||||
f"/{MOD}/discount_detail_list/update_discount_detail.dspy",
|
|
||||||
f"/{MOD}/discount_detail_list/delete_discount_detail.dspy",
|
|
||||||
# CRUD auto-generated .dspy — discount_marketing
|
|
||||||
f"/{MOD}/discount_marketing_list/get_discount_marketing.dspy",
|
|
||||||
f"/{MOD}/discount_marketing_list/add_discount_marketing.dspy",
|
|
||||||
f"/{MOD}/discount_marketing_list/update_discount_marketing.dspy",
|
|
||||||
f"/{MOD}/discount_marketing_list/delete_discount_marketing.dspy",
|
|
||||||
# CRUD auto-generated .dspy — discount_promo_code
|
|
||||||
f"/{MOD}/discount_promo_code_list/get_discount_promo_code.dspy",
|
|
||||||
f"/{MOD}/discount_promo_code_list/add_discount_promo_code.dspy",
|
|
||||||
f"/{MOD}/discount_promo_code_list/update_discount_promo_code.dspy",
|
|
||||||
f"/{MOD}/discount_promo_code_list/delete_discount_promo_code.dspy",
|
|
||||||
# CRUD auto-generated .dspy — discount_customer_bind
|
|
||||||
f"/{MOD}/discount_customer_bind_list/get_discount_customer_bind.dspy",
|
|
||||||
f"/{MOD}/discount_customer_bind_list/add_discount_customer_bind.dspy",
|
|
||||||
f"/{MOD}/discount_customer_bind_list/update_discount_customer_bind.dspy",
|
|
||||||
f"/{MOD}/discount_customer_bind_list/delete_discount_customer_bind.dspy",
|
|
||||||
# CRUD API (json/ defined)
|
|
||||||
f"/{MOD}/api/get_customer_list.dspy",
|
|
||||||
f"/{MOD}/api/discount_create.dspy",
|
|
||||||
f"/{MOD}/api/discount_update.dspy",
|
|
||||||
f"/{MOD}/api/discount_delete.dspy",
|
|
||||||
f"/{MOD}/api/discount_detail_create.dspy",
|
|
||||||
f"/{MOD}/api/discount_detail_update.dspy",
|
|
||||||
f"/{MOD}/api/discount_detail_delete.dspy",
|
|
||||||
f"/{MOD}/api/marketing_create.dspy",
|
|
||||||
f"/{MOD}/api/marketing_update.dspy",
|
|
||||||
f"/{MOD}/api/marketing_delete.dspy",
|
|
||||||
f"/{MOD}/api/promo_code_create.dspy",
|
|
||||||
f"/{MOD}/api/promo_code_update.dspy",
|
|
||||||
f"/{MOD}/api/promo_code_delete.dspy",
|
|
||||||
f"/{MOD}/api/customer_bind_create.dspy",
|
|
||||||
f"/{MOD}/api/customer_bind_update.dspy",
|
|
||||||
f"/{MOD}/api/customer_bind_delete.dspy",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# 角色专属权限 — operator 可管理折扣方案、营销方案、客户归属
|
for d in crud_defs:
|
||||||
PATHS_OPERATOR = [
|
alias = d["alias"]
|
||||||
# 折扣方案管理
|
tblname = d["tblname"]
|
||||||
f"/{MOD}/discount_list",
|
# any: 别名目录
|
||||||
f"/{MOD}/discount_list/index.ui",
|
PATHS_ANY.append(f"/{MOD}/{alias}")
|
||||||
f"/{MOD}/discount_list/get_discount.dspy",
|
# logined: index.ui
|
||||||
f"/{MOD}/discount_list/add_discount.dspy",
|
PATHS_LOGINED.append(f"/{MOD}/{alias}/index.ui")
|
||||||
f"/{MOD}/discount_list/update_discount.dspy",
|
# logined: auto-generated .dspy (get/add/update/delete)
|
||||||
f"/{MOD}/discount_list/delete_discount.dspy",
|
PATHS_LOGINED.append(f"/{MOD}/{alias}/get_{tblname}.dspy")
|
||||||
# 折扣产品明细
|
PATHS_LOGINED.append(f"/{MOD}/{alias}/add_{tblname}.dspy")
|
||||||
f"/{MOD}/discount_detail_list",
|
PATHS_LOGINED.append(f"/{MOD}/{alias}/update_{tblname}.dspy")
|
||||||
f"/{MOD}/discount_detail_list/index.ui",
|
PATHS_LOGINED.append(f"/{MOD}/{alias}/delete_{tblname}.dspy")
|
||||||
f"/{MOD}/discount_detail_list/get_discount_detail.dspy",
|
|
||||||
f"/{MOD}/discount_detail_list/add_discount_detail.dspy",
|
|
||||||
f"/{MOD}/discount_detail_list/update_discount_detail.dspy",
|
|
||||||
f"/{MOD}/discount_detail_list/delete_discount_detail.dspy",
|
|
||||||
# 营销方案管理
|
|
||||||
f"/{MOD}/discount_marketing_list",
|
|
||||||
f"/{MOD}/discount_marketing_list/index.ui",
|
|
||||||
f"/{MOD}/discount_marketing_list/get_discount_marketing.dspy",
|
|
||||||
f"/{MOD}/discount_marketing_list/add_discount_marketing.dspy",
|
|
||||||
f"/{MOD}/discount_marketing_list/update_discount_marketing.dspy",
|
|
||||||
f"/{MOD}/discount_marketing_list/delete_discount_marketing.dspy",
|
|
||||||
f"/{MOD}/api/marketing_create.dspy",
|
|
||||||
f"/{MOD}/api/marketing_update.dspy",
|
|
||||||
f"/{MOD}/api/marketing_delete.dspy",
|
|
||||||
# 促销码管理
|
|
||||||
f"/{MOD}/discount_promo_code_list",
|
|
||||||
f"/{MOD}/discount_promo_code_list/index.ui",
|
|
||||||
f"/{MOD}/discount_promo_code_list/get_discount_promo_code.dspy",
|
|
||||||
f"/{MOD}/discount_promo_code_list/add_discount_promo_code.dspy",
|
|
||||||
f"/{MOD}/discount_promo_code_list/update_discount_promo_code.dspy",
|
|
||||||
f"/{MOD}/discount_promo_code_list/delete_discount_promo_code.dspy",
|
|
||||||
f"/{MOD}/api/promo_code_create.dspy",
|
|
||||||
f"/{MOD}/api/promo_code_update.dspy",
|
|
||||||
f"/{MOD}/api/promo_code_delete.dspy",
|
|
||||||
# 客户归属管理
|
|
||||||
f"/{MOD}/discount_customer_bind_list",
|
|
||||||
f"/{MOD}/discount_customer_bind_list/index.ui",
|
|
||||||
f"/{MOD}/discount_customer_bind_list/get_discount_customer_bind.dspy",
|
|
||||||
f"/{MOD}/discount_customer_bind_list/add_discount_customer_bind.dspy",
|
|
||||||
f"/{MOD}/discount_customer_bind_list/update_discount_customer_bind.dspy",
|
|
||||||
f"/{MOD}/discount_customer_bind_list/delete_discount_customer_bind.dspy",
|
|
||||||
f"/{MOD}/api/customer_bind_create.dspy",
|
|
||||||
f"/{MOD}/api/customer_bind_update.dspy",
|
|
||||||
f"/{MOD}/api/customer_bind_delete.dspy",
|
|
||||||
# 折扣方案和明细 API
|
|
||||||
f"/{MOD}/api/get_customer_list.dspy",
|
|
||||||
f"/{MOD}/api/discount_create.dspy",
|
|
||||||
f"/{MOD}/api/discount_update.dspy",
|
|
||||||
f"/{MOD}/api/discount_delete.dspy",
|
|
||||||
f"/{MOD}/api/discount_detail_create.dspy",
|
|
||||||
f"/{MOD}/api/discount_detail_update.dspy",
|
|
||||||
f"/{MOD}/api/discount_detail_delete.dspy",
|
|
||||||
]
|
|
||||||
|
|
||||||
# 角色专属权限 — sale 可查看促销码和客户归属
|
# logined: 所有 API 文件
|
||||||
PATHS_SALE = [
|
for api_path in get_api_files():
|
||||||
# 促销码(生成+查看)
|
PATHS_LOGINED.append(api_path)
|
||||||
f"/{MOD}/discount_promo_code_list",
|
|
||||||
f"/{MOD}/discount_promo_code_list/index.ui",
|
# ============================================================
|
||||||
f"/{MOD}/discount_promo_code_list/get_discount_promo_code.dspy",
|
# 角色专属权限
|
||||||
f"/{MOD}/discount_promo_code_list/add_discount_promo_code.dspy",
|
# ============================================================
|
||||||
f"/{MOD}/discount_promo_code_list/update_discount_promo_code.dspy",
|
|
||||||
f"/{MOD}/discount_promo_code_list/delete_discount_promo_code.dspy",
|
# operator — 全部折扣管理功能
|
||||||
f"/{MOD}/api/promo_code_create.dspy",
|
PATHS_OPERATOR = []
|
||||||
f"/{MOD}/api/promo_code_update.dspy",
|
for d in crud_defs:
|
||||||
f"/{MOD}/api/promo_code_delete.dspy",
|
alias = d["alias"]
|
||||||
# 客户归属(查看+手动分配)
|
tblname = d["tblname"]
|
||||||
f"/{MOD}/discount_customer_bind_list",
|
PATHS_OPERATOR.append(f"/{MOD}/{alias}")
|
||||||
f"/{MOD}/discount_customer_bind_list/index.ui",
|
PATHS_OPERATOR.append(f"/{MOD}/{alias}/index.ui")
|
||||||
f"/{MOD}/discount_customer_bind_list/get_discount_customer_bind.dspy",
|
PATHS_OPERATOR.append(f"/{MOD}/{alias}/get_{tblname}.dspy")
|
||||||
f"/{MOD}/discount_customer_bind_list/add_discount_customer_bind.dspy",
|
PATHS_OPERATOR.append(f"/{MOD}/{alias}/add_{tblname}.dspy")
|
||||||
f"/{MOD}/discount_customer_bind_list/update_discount_customer_bind.dspy",
|
PATHS_OPERATOR.append(f"/{MOD}/{alias}/update_{tblname}.dspy")
|
||||||
f"/{MOD}/discount_customer_bind_list/delete_discount_customer_bind.dspy",
|
PATHS_OPERATOR.append(f"/{MOD}/{alias}/delete_{tblname}.dspy")
|
||||||
f"/{MOD}/api/customer_bind_create.dspy",
|
|
||||||
f"/{MOD}/api/customer_bind_update.dspy",
|
# operator 也需要所有 API
|
||||||
f"/{MOD}/api/customer_bind_delete.dspy",
|
for api_path in get_api_files():
|
||||||
]
|
PATHS_OPERATOR.append(api_path)
|
||||||
|
|
||||||
|
# sale — 促销码、客户归属
|
||||||
|
PATHS_SALE = []
|
||||||
|
SALE_TABLES = ["discount_promo_code", "discount_customer_bind"]
|
||||||
|
SALE_ALIASES = {d["tblname"]: d["alias"] for d in crud_defs}
|
||||||
|
for tblname in SALE_TABLES:
|
||||||
|
alias = SALE_ALIASES.get(tblname, tblname + "_list")
|
||||||
|
PATHS_SALE.append(f"/{MOD}/{alias}")
|
||||||
|
PATHS_SALE.append(f"/{MOD}/{alias}/index.ui")
|
||||||
|
PATHS_SALE.append(f"/{MOD}/{alias}/get_{tblname}.dspy")
|
||||||
|
PATHS_SALE.append(f"/{MOD}/{alias}/add_{tblname}.dspy")
|
||||||
|
PATHS_SALE.append(f"/{MOD}/{alias}/update_{tblname}.dspy")
|
||||||
|
PATHS_SALE.append(f"/{MOD}/{alias}/delete_{tblname}.dspy")
|
||||||
|
|
||||||
|
# sale 相关 API
|
||||||
|
for api_path in get_api_files():
|
||||||
|
basename = os.path.basename(api_path)
|
||||||
|
if any(k in basename for k in ["promo_code", "customer_bind"]):
|
||||||
|
PATHS_SALE.append(api_path)
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 去重
|
||||||
|
# ============================================================
|
||||||
|
PATHS_ANY = list(dict.fromkeys(PATHS_ANY))
|
||||||
|
PATHS_LOGINED = list(dict.fromkeys(PATHS_LOGINED))
|
||||||
|
PATHS_OPERATOR = list(dict.fromkeys(PATHS_OPERATOR))
|
||||||
|
PATHS_SALE = list(dict.fromkeys(PATHS_SALE))
|
||||||
|
|
||||||
|
print(f"\nPath counts:")
|
||||||
|
print(f" any: {len(PATHS_ANY)}")
|
||||||
|
print(f" logined: {len(PATHS_LOGINED)}")
|
||||||
|
print(f" reseller.operator: {len(PATHS_OPERATOR)}")
|
||||||
|
print(f" reseller.sale: {len(PATHS_SALE)}")
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 执行注册
|
# 执行注册
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
def run_set_perm(role, path, verbose=True):
|
def run_set_perm(role, path, verbose=True):
|
||||||
"""Register a single permission path."""
|
|
||||||
cmd = [PYTHON, SET_PERM_SCRIPT, role, path]
|
cmd = [PYTHON, SET_PERM_SCRIPT, role, path]
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
if verbose:
|
if verbose:
|
||||||
@ -215,7 +193,6 @@ def run_set_perm(role, path, verbose=True):
|
|||||||
|
|
||||||
|
|
||||||
def register_role_paths(role, paths):
|
def register_role_paths(role, paths):
|
||||||
"""Register all paths for a role."""
|
|
||||||
count = 0
|
count = 0
|
||||||
for path in paths:
|
for path in paths:
|
||||||
if run_set_perm(role, path, verbose=False):
|
if run_set_perm(role, path, verbose=False):
|
||||||
@ -225,7 +202,7 @@ def register_role_paths(role, paths):
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print(f"Sage root: {SAGE_ROOT}")
|
print(f"\nSage root: {SAGE_ROOT}")
|
||||||
print(f"set_role_perm.py: {SET_PERM_SCRIPT}")
|
print(f"set_role_perm.py: {SET_PERM_SCRIPT}")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user