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