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别名目录
|
||||
- logined: 需要认证的页面和 API
|
||||
- reseller.operator: 运营角色 — 折扣方案、营销方案、客户归属管理
|
||||
- reseller.sale: 销售角色 — 促销码、客户归属查看
|
||||
- reseller.operator: 运营角色 — 全部折扣管理功能
|
||||
- reseller.sale: 销售角色 — 促销码、客户归属
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import glob
|
||||
|
||||
def find_sage_root():
|
||||
candidates = [
|
||||
@ -43,23 +45,58 @@ if not os.path.exists(SET_PERM_SCRIPT):
|
||||
sys.exit(1)
|
||||
|
||||
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别名目录)
|
||||
PATHS_ANY = [
|
||||
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 = [
|
||||
# 模块入口
|
||||
f"/{MOD}",
|
||||
@ -69,142 +106,83 @@ PATHS_LOGINED = [
|
||||
f"/{MOD}/promote",
|
||||
f"/{MOD}/promote.ui",
|
||||
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 可管理折扣方案、营销方案、客户归属
|
||||
PATHS_OPERATOR = [
|
||||
# 折扣方案管理
|
||||
f"/{MOD}/discount_list",
|
||||
f"/{MOD}/discount_list/index.ui",
|
||||
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",
|
||||
# 折扣产品明细
|
||||
f"/{MOD}/discount_detail_list",
|
||||
f"/{MOD}/discount_detail_list/index.ui",
|
||||
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",
|
||||
]
|
||||
for d in crud_defs:
|
||||
alias = d["alias"]
|
||||
tblname = d["tblname"]
|
||||
# any: 别名目录
|
||||
PATHS_ANY.append(f"/{MOD}/{alias}")
|
||||
# logined: index.ui
|
||||
PATHS_LOGINED.append(f"/{MOD}/{alias}/index.ui")
|
||||
# logined: auto-generated .dspy (get/add/update/delete)
|
||||
PATHS_LOGINED.append(f"/{MOD}/{alias}/get_{tblname}.dspy")
|
||||
PATHS_LOGINED.append(f"/{MOD}/{alias}/add_{tblname}.dspy")
|
||||
PATHS_LOGINED.append(f"/{MOD}/{alias}/update_{tblname}.dspy")
|
||||
PATHS_LOGINED.append(f"/{MOD}/{alias}/delete_{tblname}.dspy")
|
||||
|
||||
# 角色专属权限 — sale 可查看促销码和客户归属
|
||||
PATHS_SALE = [
|
||||
# 促销码(生成+查看)
|
||||
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",
|
||||
]
|
||||
# logined: 所有 API 文件
|
||||
for api_path in get_api_files():
|
||||
PATHS_LOGINED.append(api_path)
|
||||
|
||||
# ============================================================
|
||||
# 角色专属权限
|
||||
# ============================================================
|
||||
|
||||
# operator — 全部折扣管理功能
|
||||
PATHS_OPERATOR = []
|
||||
for d in crud_defs:
|
||||
alias = d["alias"]
|
||||
tblname = d["tblname"]
|
||||
PATHS_OPERATOR.append(f"/{MOD}/{alias}")
|
||||
PATHS_OPERATOR.append(f"/{MOD}/{alias}/index.ui")
|
||||
PATHS_OPERATOR.append(f"/{MOD}/{alias}/get_{tblname}.dspy")
|
||||
PATHS_OPERATOR.append(f"/{MOD}/{alias}/add_{tblname}.dspy")
|
||||
PATHS_OPERATOR.append(f"/{MOD}/{alias}/update_{tblname}.dspy")
|
||||
PATHS_OPERATOR.append(f"/{MOD}/{alias}/delete_{tblname}.dspy")
|
||||
|
||||
# operator 也需要所有 API
|
||||
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):
|
||||
"""Register a single permission path."""
|
||||
cmd = [PYTHON, SET_PERM_SCRIPT, role, path]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
if verbose:
|
||||
@ -215,7 +193,6 @@ def run_set_perm(role, path, verbose=True):
|
||||
|
||||
|
||||
def register_role_paths(role, paths):
|
||||
"""Register all paths for a role."""
|
||||
count = 0
|
||||
for path in paths:
|
||||
if run_set_perm(role, path, verbose=False):
|
||||
@ -225,7 +202,7 @@ def register_role_paths(role, paths):
|
||||
|
||||
|
||||
def main():
|
||||
print(f"Sage root: {SAGE_ROOT}")
|
||||
print(f"\nSage root: {SAGE_ROOT}")
|
||||
print(f"set_role_perm.py: {SET_PERM_SCRIPT}")
|
||||
print()
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user