diff --git a/scripts/load_path.py b/scripts/load_path.py index 8701a4d..66b9680 100644 --- a/scripts/load_path.py +++ b/scripts/load_path.py @@ -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()