Files
zkxw/backend/app/services/permission_administration.py
T
zlwu 0bddf38e52 feat(project): enforce team-scoped selection with explicit all-project permission
Separate cross-team selection from attribution maintenance and apply the same scope to options, history filters and writes. Add an opt-in tenant permission without granting existing roles.

Protect authorization mutation paths against self-grants, validate tenant targets and links, and include menu ancestors atomically. Cover role union, revocation, mobile writes and administration boundaries with regression tests.
2026-11-02 17:09:20 +08:00

36 lines
1.5 KiB
Python

"""Validate authorization targets before any role/menu relationship is changed."""
from app.models.models import SysMenu
def validate_tenant_references(db, model, ids, tenant_no):
"""Reject deleted, foreign or missing targets without writing partial grants."""
ids = list(dict.fromkeys(ids or []))
if not ids:
return
found = {row.id for row in db.query(model.id).filter(
model.id.in_(ids), model.tenant_no == tenant_no, model.del_flag == 0)}
if found != set(ids):
raise ValueError('关联记录不存在或不属于当前租户')
def menu_ids_with_ancestors(db, menu_ids, tenant_no):
"""Include only each selected node's same-tenant ancestors, up to its own root."""
menus = {row.id: row for row in db.query(SysMenu).filter(
SysMenu.tenant_no == tenant_no, SysMenu.del_flag == 0)}
result, included = [], set()
for selected in menu_ids:
current, path = selected, set()
while current and current != '0':
if current in path:
raise ValueError('菜单存在循环父级,不能授权')
if current not in menus:
raise ValueError('菜单或祖先不存在或不属于当前租户')
path.add(current)
if current not in included:
result.append(current)
included.add(current)
current = menus[current].parent_id
if not path:
raise ValueError('菜单不存在或不属于当前租户')
return result