116 lines
3.7 KiB
Python
116 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""仅刷新 5 个业务角色的菜单授权(不删角色、不动用户绑定)。
|
|
|
|
用于修复「角色只勾 F 按钮、缺少 C 页面 :list」导致前端侧栏为空的问题。
|
|
|
|
用法:
|
|
cd backend && ./venv/bin/python scripts/refresh_business_role_menus.py --env-file .env.production
|
|
./venv/bin/python scripts/refresh_business_role_menus.py --dry-run --env-file .env.production
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
import sys
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
from sqlalchemy import create_engine, text
|
|
|
|
BACKEND_ROOT = Path(__file__).resolve().parents[1]
|
|
if str(BACKEND_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(BACKEND_ROOT))
|
|
|
|
from scripts.setup_business_roles import ( # noqa: E402
|
|
MODULE_MENU_ROOTS,
|
|
NEW_ROLES,
|
|
TENANT_NO,
|
|
collect_subtree_menu_ids,
|
|
grant_module_menus,
|
|
perm_menu_ids,
|
|
)
|
|
|
|
|
|
def load_settings_env(env_file: str) -> None:
|
|
if env_file:
|
|
os.environ["ENV_FILE"] = env_file
|
|
from dotenv import load_dotenv
|
|
|
|
path = Path(env_file) if env_file else BACKEND_ROOT / ".env.production"
|
|
if not path.is_absolute():
|
|
path = BACKEND_ROOT / path
|
|
if path.is_file():
|
|
load_dotenv(path, override=True)
|
|
|
|
|
|
def load_runtime_settings():
|
|
from app.core.config import Settings
|
|
|
|
return Settings()
|
|
|
|
|
|
def verify_user_menu_codes(engine, user_no: str) -> None:
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.services.web_auth_roles import iter_user_menu_perm_codes
|
|
|
|
with Session(engine) as db:
|
|
row = db.execute(
|
|
text(
|
|
"""
|
|
SELECT id FROM sys_user
|
|
WHERE tenant_no = :tenant AND user_no = :user_no AND del_flag = 0
|
|
LIMIT 1
|
|
"""
|
|
),
|
|
{"tenant": TENANT_NO, "user_no": user_no},
|
|
).first()
|
|
if not row:
|
|
print(f" [verify] 用户不存在: {user_no}")
|
|
return
|
|
uid = str(row[0])
|
|
codes = sorted(iter_user_menu_perm_codes(db, uid, TENANT_NO))
|
|
list_codes = [c for c in codes if c.endswith(":list")]
|
|
print(f" [verify] {user_no}: 共 {len(codes)} 个 perms,其中 :list {len(list_codes)} 个")
|
|
if list_codes:
|
|
print(f" 示例: {', '.join(list_codes[:5])}...")
|
|
else:
|
|
print(" 警告: 无任何 :list 权限,前端侧栏仍会为空")
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description="刷新业务角色菜单授权")
|
|
parser.add_argument("--env-file", default=".env.production")
|
|
parser.add_argument("--dry-run", action="store_true")
|
|
parser.add_argument("--verify-user", default="方金强", help="刷新后校验该用户的 menuCodes")
|
|
args = parser.parse_args()
|
|
|
|
load_settings_env(args.env_file)
|
|
settings = load_runtime_settings()
|
|
engine = create_engine(settings.DATABASE_URL, pool_pre_ping=True)
|
|
|
|
print("=== refresh_business_role_menus ===")
|
|
print(f"模式: {'DRY-RUN' if args.dry_run else 'EXECUTE'}")
|
|
print(f"租户: {TENANT_NO}")
|
|
print()
|
|
|
|
with engine.begin() as conn:
|
|
subtree = collect_subtree_menu_ids(conn, MODULE_MENU_ROOTS, TENANT_NO)
|
|
grant_ids = perm_menu_ids(conn, subtree, TENANT_NO)
|
|
print(f"模块子树 {len(subtree)} 项,带 perms 菜单 {len(grant_ids)} 项")
|
|
for role_name, role_id in NEW_ROLES.items():
|
|
cnt = grant_module_menus(conn, role_id, grant_ids, TENANT_NO, args.dry_run)
|
|
print(f" {role_name}: {cnt} 项")
|
|
|
|
if not args.dry_run and args.verify_user:
|
|
print()
|
|
print("校验 menuCodes:")
|
|
verify_user_menu_codes(engine, args.verify_user)
|
|
|
|
print("完成.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|