fix: 角色分配按俱乐部超管权限隔离

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-06 18:23:29 +08:00
parent 2bbe166d63
commit 1c6607fa6e
3 changed files with 68 additions and 5 deletions

View File

@@ -510,7 +510,7 @@ class GetAdminUserListView(APIView):
'UpdateTime': user.KefuProfile.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user.KefuProfile, 'UpdateTime', None) else '',
})
from jituan.services.admin_context import can_manage_admin_assignments
from jituan.services.admin_context import can_manage_admin_assignments, get_manageable_club_ids
return Response({
'code': 0,
'data': {
@@ -519,6 +519,7 @@ class GetAdminUserListView(APIView):
'page': page,
'pageSize': page_size,
'can_manage_club_assignments': can_manage_admin_assignments(request.user, permissions),
'manageable_club_ids': sorted(get_manageable_club_ids(request.user, permissions)),
}
})
@@ -543,12 +544,19 @@ class GetAdminRolesView(APIView):
if '000001' not in permissions:
return Response({'code': 403, 'msg': '您无权访问此页面'})
from jituan.services.admin_context import can_manage_admin_assignments, get_manageable_club_ids
from jituan.services.club_rbac import filter_roles_for_request
all_clubs = request.data.get('all_clubs') in (True, 1, '1', 'true', 'yes')
if all_clubs:
if all_clubs and can_manage_admin_assignments(request.user, permissions):
roles = Role.objects.filter(RoleStatus=1).order_by('ClubID', 'RoleName').values('RoleName', 'ClubID')
else:
roles = filter_roles_for_request(request).values('RoleName', 'ClubID')
manageable = get_manageable_club_ids(request.user, permissions)
if manageable:
roles = Role.objects.filter(
RoleStatus=1, ClubID__in=manageable,
).order_by('ClubID', 'RoleName').values('RoleName', 'ClubID')
else:
roles = filter_roles_for_request(request).values('RoleName', 'ClubID')
return Response({
'code': 0,
'data': {
@@ -651,12 +659,15 @@ class ModifyAdminUserView(APIView):
if kefu is None:
return permissions
from jituan.services.admin_context import can_manage_admin_assignments
from jituan.services.admin_context import can_manage_admin_assignments, can_manage_roles_for_club
club_assign_actions = {'add_club_assignment', 'remove_club_assignment'}
role_manage_actions = {'add_user_roles', 'remove_user_role'}
if action in club_assign_actions:
if not can_manage_admin_assignments(request.user, permissions):
return Response({'code': 403, 'msg': '仅集团高层(集团总负责人/集团超管)可分配俱乐部任职'})
return Response({'code': 403, 'msg': '无权分配俱乐部任职'})
elif action in role_manage_actions:
pass
elif '000001' not in permissions:
return Response({'code': 403, 'msg': '您无权进行此操作'})
@@ -707,6 +718,8 @@ class ModifyAdminUserView(APIView):
bind_club_id = (request.data.get('target_club_id') or '').strip()
if not bind_club_id:
bind_club_id = resolve_club_id_from_request(request)
if not can_manage_roles_for_club(request.user, permissions, bind_club_id):
return Response({'code': 403, 'msg': '您无权管理该俱乐部的角色分配'})
added, missing = [], []
for rc in role_codes:
role = resolve_role_by_name(rc, bind_club_id)
@@ -746,6 +759,8 @@ class ModifyAdminUserView(APIView):
bind_club_id = (request.data.get('target_club_id') or '').strip()
if not bind_club_id:
bind_club_id = resolve_club_id_from_request(request)
if not can_manage_roles_for_club(request.user, permissions, bind_club_id):
return Response({'code': 403, 'msg': '您无权管理该俱乐部的角色分配'})
role = resolve_role_by_name(role_code, bind_club_id)
if not role:
return Response({'code': 404, 'msg': '角色不存在或与所选俱乐部不匹配'})

View File

@@ -171,6 +171,31 @@ def can_manage_admin_assignments(user, permissions=None):
)
def can_manage_roles_for_club(user, permissions, club_id):
"""
是否可为指定俱乐部分配/移除功能角色。
集团高层:全部俱乐部;否则须在该俱乐部拥有 000001 超级管理权限。
"""
if can_manage_admin_assignments(user, permissions):
return True
cid = (club_id or '').strip()
if not cid:
return False
from jituan.services.club_rbac import resolve_permission_codes_for_club
codes = resolve_permission_codes_for_club(user, cid)
return '000001' in codes
def get_manageable_club_ids(user, permissions=None):
"""当前操作者可管理角色分配的俱乐部集合。"""
if can_manage_admin_assignments(user, permissions):
return {c.club_id for c in Club.query.filter(status=1)}
return {
c.club_id for c in Club.query.filter(status=1)
if can_manage_roles_for_club(user, permissions, c.club_id)
}
def _pack(scope, club_id, is_group_admin, assignments, clubs, can_switch_club,
role_code, role_name):
allowed_club_ids = sorted({

View File

@@ -152,6 +152,29 @@ def filter_role_uuids_for_club_scope(role_uuids, club_id, scope, allowed_club_id
return list(qs.filter(Q(ClubID=cid) | Q(ClubID='')).values_list('RoleUUID', flat=True))
def resolve_permission_codes_for_club(user, club_id, allowed_club_ids=None):
"""指定俱乐部 SINGLE 视图下用户的 gvsdsdk 权限码。"""
from jituan.constants import DATA_SCOPE_SINGLE
from gvsdsdk.models import Permission as SdkPermission, RolePermission as SdkRolePermission, UserRole as SdkUserRole
role_uuids = list(SdkUserRole.objects.filter(
UserUUID=user.UserUUID,
).values_list('RoleUUID', flat=True))
role_uuids = filter_role_uuids_for_club_scope(
role_uuids, club_id, DATA_SCOPE_SINGLE, allowed_club_ids,
)
if not role_uuids:
return []
perm_uuids = SdkRolePermission.objects.filter(
RoleUUID__in=role_uuids,
).values_list('PermUUID', flat=True)
return list(
SdkPermission.objects.filter(
PermUUID__in=perm_uuids, PermStatus=1,
).values_list('PermCode', flat=True).distinct()
)
def user_bound_role_names(user, club_id=None, scope=None, allowed_club_ids=None):
from backend.utils import _legacy_backend_role_permissions