From c7adec20db2809ea3ab1b91252edd3d740bc1223 Mon Sep 17 00:00:00 2001 From: XingQue Date: Thu, 2 Jul 2026 16:03:23 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=E7=94=A8=E6=88=B7=20RoleUUID=20=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E9=94=99=E8=AF=AF=E5=B9=B6=E4=B8=A5=E6=A0=BC=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E8=A7=92=E8=89=B2=E7=BB=91=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/view.py | 38 ++++++++++++++++++++++-------------- jituan/services/club_rbac.py | 32 ++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/backend/view.py b/backend/view.py index 81bccd0..9c03575 100644 --- a/backend/view.py +++ b/backend/view.py @@ -717,7 +717,7 @@ class AddAdminUserView(APIView): return Response({'code': 400, 'msg': '密码和二级密码至少6位'}) from jituan.services.club_context import resolve_club_id_from_request - from jituan.services.club_rbac import resolve_role_by_name + from jituan.services.club_rbac import resolve_roles_for_binding target_club_id = resolve_club_id_from_request(request) @@ -728,6 +728,27 @@ class AddAdminUserView(APIView): if existing_kefu: return Response({'code': 400, 'msg': '该账号已存在'}) + if not isinstance(role_codes, list): + return Response({'code': 400, 'msg': 'role_codes 格式错误'}) + + # 分配角色(默认客服 + 所选角色,去重;任一角色找不到则整单拒绝) + role_names_to_bind = [] + seen_names = set() + for name in (['客服'] if '客服' not in role_codes else []) + list(role_codes): + n = (name or '').strip() + if n and n not in seen_names: + seen_names.add(n) + role_names_to_bind.append(n) + + roles_to_bind, missing_roles = resolve_roles_for_binding(role_names_to_bind, target_club_id) + if missing_roles: + return Response({ + 'code': 400, + 'msg': f'角色不存在或与当前俱乐部不匹配:{", ".join(missing_roles)}', + }) + if not roles_to_bind: + return Response({'code': 400, 'msg': '请至少选择一个有效角色'}) + with transaction.atomic(): # 事务内二次校验,防止并发重复创建 if User.query.filter(Phone=phone, KefuProfile__isnull=False).exists(): @@ -765,20 +786,7 @@ class AddAdminUserView(APIView): erjimima=erjimima_hashed, zhuangtai=1 ) - # 分配角色(默认客服 + 所选角色,按俱乐部解析,去重) - role_names_to_bind = [] - if '客服' not in role_codes: - role_names_to_bind.append('客服') - role_names_to_bind.extend(role_codes) - bound_role_uuids = set() - for rc in role_names_to_bind: - role = resolve_role_by_name(rc, target_club_id) - if not role: - continue - role_uuid = bytes(role.RoleUUID) if not isinstance(role.RoleUUID, bytes) else role.RoleUUID - if role_uuid in bound_role_uuids: - continue - bound_role_uuids.add(role_uuid) + for role in roles_to_bind: UserRole.objects.get_or_create( UserUUID=user_main.UserUUID, RoleUUID=role.RoleUUID, diff --git a/jituan/services/club_rbac.py b/jituan/services/club_rbac.py index c73a3f6..e1dea07 100644 --- a/jituan/services/club_rbac.py +++ b/jituan/services/club_rbac.py @@ -76,6 +76,38 @@ def resolve_role_by_name(role_name, club_id=None): return qs.filter(ClubID='').first() or qs.first() +def role_uuid_bytes(role_uuid): + """RoleUUID 统一转 bytes(兼容 UUIDObj / bytes / str)。""" + from gvsdsdk.model_utils import UUIDObj + if isinstance(role_uuid, bytes): + return role_uuid + return UUIDObj(role_uuid).bytes + + +def resolve_roles_for_binding(role_names, club_id=None): + """ + 按角色名解析并去重;任一角色在当前俱乐部下找不到则整体失败。 + 返回 (roles, missing_names)。 + """ + resolved = [] + missing = [] + seen_bytes = set() + for raw in role_names or []: + name = (raw or '').strip() + if not name: + continue + role = resolve_role_by_name(name, club_id) + if not role: + missing.append(name) + continue + key = role_uuid_bytes(role.RoleUUID) + if key in seen_bytes: + continue + seen_bytes.add(key) + resolved.append(role) + return resolved, missing + + def user_bound_role_names(user): from backend.utils import _legacy_backend_role_permissions