后台权限管理支持「自定义」角色:按人存 pages_override,可见页逐页勾选并即时生效
admin_user 加 pages_override(可空 JSON)+ Alembic 迁移;role=="custom" 时可见页由这份逐页 勾选决定,否则跟随角色。create/update 收 pages_override(切回普通角色自动清空),_validate_role 放行 custom 哨兵角色。登录/me 下发有效页时优先用 override → 左侧导航直接按勾选生效。 补 4 个用例覆盖建/改/切回/切入,test_admin_roles 全绿。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -150,3 +150,80 @@ def test_create_admin_rejects_unknown_role(admin_client, super_token) -> None:
|
||||
headers=_auth(super_token),
|
||||
)
|
||||
assert r.status_code == 400
|
||||
|
||||
|
||||
def _login_pages(username: str, password: str = "pass1234") -> list[str]:
|
||||
"""以某账号登录,取下发的有效可见页(左侧导航过滤依据)。"""
|
||||
c = TestClient(admin_app)
|
||||
return c.post(
|
||||
"/admin/api/auth/login", json={"username": username, "password": password}
|
||||
).json()["admin"]["pages"]
|
||||
|
||||
|
||||
def test_custom_role_create_pages_take_effect(admin_client, super_token) -> None:
|
||||
# 建「自定义」账号:role=custom + 勾选页(含一个非法 key,应被过滤)
|
||||
r = admin_client.post(
|
||||
"/admin/api/admins",
|
||||
json={
|
||||
"username": "cust_user", "password": "pass1234", "role": "custom",
|
||||
"pages_override": ["dashboard", "withdraws", "xx-bad"],
|
||||
},
|
||||
headers=_auth(super_token),
|
||||
)
|
||||
assert r.status_code == 200, r.text
|
||||
# 登录下发的 pages == 勾选集(非法 key 过滤),真正驱动左侧导航
|
||||
assert set(_login_pages("cust_user")) == {"dashboard", "withdraws"}
|
||||
# 账号列表回显原始勾选集(供编辑回填),同样已过滤
|
||||
admins = {a["username"]: a for a in admin_client.get("/admin/api/admins", headers=_auth(super_token)).json()}
|
||||
assert set(admins["cust_user"]["pages_override"]) == {"dashboard", "withdraws"}
|
||||
assert admins["cust_user"]["role"] == "custom"
|
||||
|
||||
|
||||
def test_custom_role_update_and_switch_back_clears_override(admin_client, super_token) -> None:
|
||||
admin_client.post(
|
||||
"/admin/api/admins",
|
||||
json={
|
||||
"username": "cust_sw", "password": "pass1234", "role": "custom",
|
||||
"pages_override": ["dashboard"],
|
||||
},
|
||||
headers=_auth(super_token),
|
||||
)
|
||||
aid = next(
|
||||
a["id"] for a in admin_client.get("/admin/api/admins", headers=_auth(super_token)).json()
|
||||
if a["username"] == "cust_sw"
|
||||
)
|
||||
# 只改勾选集(角色不变)→ 生效
|
||||
u = admin_client.patch(
|
||||
f"/admin/api/admins/{aid}", json={"pages_override": ["dashboard", "feedbacks"]},
|
||||
headers=_auth(super_token),
|
||||
)
|
||||
assert u.status_code == 200, u.text
|
||||
assert set(_login_pages("cust_sw")) == {"dashboard", "feedbacks"}
|
||||
# 切回普通角色 operator → override 清空,pages 跟随角色(运营页集,且不含 admins)
|
||||
u2 = admin_client.patch(
|
||||
f"/admin/api/admins/{aid}", json={"role": "operator"}, headers=_auth(super_token)
|
||||
)
|
||||
assert u2.status_code == 200, u2.text
|
||||
admins = {a["username"]: a for a in admin_client.get("/admin/api/admins", headers=_auth(super_token)).json()}
|
||||
assert admins["cust_sw"]["pages_override"] is None
|
||||
pages = set(_login_pages("cust_sw"))
|
||||
assert "feedbacks" in pages and "admins" not in pages # 运营口径,自定义页已不生效
|
||||
|
||||
|
||||
def test_switch_operator_to_custom_sets_override(admin_client, super_token) -> None:
|
||||
admin_client.post(
|
||||
"/admin/api/admins",
|
||||
json={"username": "op2cust", "password": "pass1234", "role": "operator"},
|
||||
headers=_auth(super_token),
|
||||
)
|
||||
aid = next(
|
||||
a["id"] for a in admin_client.get("/admin/api/admins", headers=_auth(super_token)).json()
|
||||
if a["username"] == "op2cust"
|
||||
)
|
||||
u = admin_client.patch(
|
||||
f"/admin/api/admins/{aid}",
|
||||
json={"role": "custom", "pages_override": ["config"]},
|
||||
headers=_auth(super_token),
|
||||
)
|
||||
assert u.status_code == 200, u.text
|
||||
assert set(_login_pages("op2cust")) == {"config"}
|
||||
|
||||
Reference in New Issue
Block a user