revert: restore gvsdsdk role/permission APIs; keep KefuProfile login fix

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-06-29 00:02:40 +08:00
parent 42cb117a8a
commit dd9e4afa49
4 changed files with 203 additions and 165 deletions

View File

@@ -77,19 +77,14 @@ class _AllPermissions(list):
return True
def _legacy_backend_role_permissions(phone, yonghuid=None):
def _legacy_backend_role_permissions(phone):
"""
读取旧权限表backend.models
user_role.account_id = 手机号或 UserUID → role → role_permission → permission.perm_code
user_role.account_id = 手机号 → role → role_permission → permission.perm_code
与 gvsdsdk 表并行,未改 SDK 结构。
"""
account_ids = []
ph = (phone or '').strip()
uid = (yonghuid or '').strip()
if ph:
account_ids.append(ph)
if uid and uid not in account_ids:
account_ids.append(uid)
if not account_ids:
phone = (phone or '').strip()
if not phone:
return [], []
try:
from backend.models import (
@@ -98,7 +93,7 @@ def _legacy_backend_role_permissions(phone, yonghuid=None):
Permission as BackendPermission,
)
role_ids = list(
LegacyUserRole.objects.filter(account_id__in=account_ids).values_list('role_id', flat=True)
LegacyUserRole.objects.filter(account_id=phone).values_list('role_id', flat=True)
)
if not role_ids:
return [], []
@@ -112,22 +107,10 @@ def _legacy_backend_role_permissions(phone, yonghuid=None):
)
return perm_codes, role_names
except Exception as e:
logger.warning('legacy_backend_role_permissions ids=%s err=%s', account_ids, e)
logger.warning('legacy_backend_role_permissions phone=%s err=%s', phone, e)
return [], []
def has_legacy_backend_binding(user):
"""旧表 user_role 或 role 下已有 perm_code。"""
from backend.models import UserRole as LegacyUserRole
ph = getattr(user, 'Phone', '') or ''
uid = getattr(user, 'UserUID', '') or ''
ids = [x for x in [ph, uid] if x]
if ids and LegacyUserRole.objects.filter(account_id__in=ids).exists():
return True
codes, _ = _legacy_backend_role_permissions(ph, uid)
return bool(codes)
def verify_kefu_permission(request, username_from_frontend=None):
"""
验证客服/管理员身份并返回该用户的所有权限列表基于新RBAC表
@@ -174,12 +157,42 @@ def verify_kefu_permission(request, username_from_frontend=None):
'msg': '身份错误,无权操作其他账号,相关操作已记录'
}, status=403)
# ---------- 4. 权限码:只读旧表 permissionuser_role → role → role_permission----------
legacy_codes, _ = _legacy_backend_role_permissions(
current_user.Phone,
getattr(current_user, 'UserUID', None),
)
permissions = list(legacy_codes) if legacy_codes else []
# ---------- 4. 获取用户的所有权限 ----------
# 使用 gvsdsdk RBAC 表UserRole → RolePermission → Permission
try:
user_uuid = current_user.UserUUID
role_uuids = list(SdkUserRole.objects.filter(
UserUUID=user_uuid
).values_list('RoleUUID', flat=True))
if role_uuids:
perm_uuids = list(SdkRolePermission.objects.filter(
RoleUUID__in=role_uuids
).values_list('PermUUID', flat=True))
permissions = list(SdkPermission.objects.filter(
PermUUID__in=perm_uuids,
PermStatus=1
).values_list('PermCode', flat=True).distinct())
else:
permissions = []
except Exception as e:
logger.warning(
'verify_kefu_permission failed: UserUUID=%s Phone=%s err=%s',
getattr(current_user, 'UserUUID', None),
getattr(current_user, 'Phone', None),
e,
exc_info=True,
)
permissions = []
# 旧权限表user_role 按手机号),与 gvsdsdk 合并
legacy_codes, _ = _legacy_backend_role_permissions(current_user.Phone)
if legacy_codes:
if isinstance(permissions, _AllPermissions):
pass
else:
permissions = list(set(list(permissions) + legacy_codes))
# 管理员/超级用户自动拥有所有权限
if is_admin and '000001' not in permissions:

View File

@@ -148,62 +148,46 @@ class GetRolePermissionView(APIView):
if '000001' not in permissions:
return Response({'code': 403, 'msg': '您无权访问此页面'})
from backend.models import (
Role as BackendRole,
Permission as BackendPermission,
UserRole as LegacyUserRole,
# 3. 获取所有权限
all_perms = Permission.objects.filter(PermStatus=1).values('PermCode', 'PermName', 'PermDesc')
permissions_list = [_serialize_permission_row(p) for p in all_perms]
from jituan.services.club_rbac import count_role_users_in_scope, filter_roles_for_request
kefu_user_uuids = list(
User.objects.filter(KefuProfile__isnull=False).values_list('UserUUID', flat=True)
)
all_perms = BackendPermission.objects.all().values('perm_code', 'perm_name', 'description')
permissions_list = [
{
'perm_code': p['perm_code'],
'perm_name': p['perm_name'],
'perm_desc': p.get('description') or '',
}
for p in all_perms
]
roles = filter_roles_for_request(request)
roles_data = []
for role in BackendRole.objects.all().order_by('role_id'):
user_count = LegacyUserRole.objects.filter(role=role).count()
perms_of_role = BackendPermission.objects.filter(rolepermission__role=role).distinct()
for role in roles:
user_count = count_role_users_in_scope(role, request, kefu_user_uuids)
role_perm_uuids = RolePermission.objects.filter(
RoleUUID=role.RoleUUID
).values_list('PermUUID', flat=True)
perms_of_role = [
_serialize_permission_row(p)
for p in Permission.objects.filter(
PermUUID__in=list(role_perm_uuids)
).values('PermCode', 'PermName', 'PermDesc')
]
roles_data.append({
'role_code': role.role_name,
'role_name': role.role_name,
'description': role.description or '',
'club_id': '',
'role_code': role.RoleName,
'role_name': role.RoleName,
'description': role.RoleDesc or '',
'club_id': getattr(role, 'ClubID', '') or '',
'user_count': user_count,
'permissions': [
{
'perm_code': p.perm_code,
'perm_name': p.perm_name,
'perm_desc': p.description or '',
}
for p in perms_of_role
],
'permissions': perms_of_role
})
return Response({
'code': 0,
'data': {
'roles': roles_data,
'permissions': permissions_list,
},
'permissions': permissions_list
}
})
def _resolve_backend_role(role_code):
from backend.models import Role as BackendRole
rc = (role_code or '').strip()
if not rc:
return None
return (
BackendRole.objects.filter(role_name=rc).first()
or BackendRole.objects.filter(role_code=rc).first()
)
class ModifyRolePermissionView(APIView):
"""
通用接口:支持删除角色、为角色添加权限、移除角色权限
@@ -229,26 +213,22 @@ class ModifyRolePermissionView(APIView):
if not role_code:
return Response({'code': 400, 'msg': '缺少角色编码'})
from backend.models import (
Permission as BackendPermission,
RolePermission as LegacyRolePermission,
UserRole as LegacyUserRole,
)
role = _resolve_backend_role(role_code)
if not role:
try:
role = Role.objects.get(RoleName=role_code)
except Role.DoesNotExist:
return Response({'code': 404, 'msg': '角色不存在'})
# 超级管理员角色的特殊限制
if role.role_name == '管理员':
if role.RoleName == '管理员':
if action in ['delete_role']:
return Response({'code': 403, 'msg': '超级管理员角色不能删除'})
# 根据 action 处理
if action == 'delete_role':
# 删除角色:同时删除角色权限关联、用户角色关联
with transaction.atomic():
LegacyRolePermission.objects.filter(role=role).delete()
LegacyUserRole.objects.filter(role=role).delete()
RolePermission.objects.filter(RoleUUID=role.RoleUUID).delete()
UserRole.objects.filter(RoleUUID=role.RoleUUID).delete()
role.delete()
return Response({'code': 0, 'msg': '角色删除成功'})
@@ -256,26 +236,34 @@ class ModifyRolePermissionView(APIView):
perm_code = request.data.get('perm_code')
if not perm_code:
return Response({'code': 400, 'msg': '缺少权限编码'})
if role.role_name == '管理员' and perm_code == '000001':
if role.RoleName == '管理员' and perm_code == '000001':
return Response({'code': 403, 'msg': '此权限已存在,不能重复添加'})
perm = BackendPermission.objects.filter(perm_code=perm_code).first()
if not perm:
try:
perm = Permission.objects.get(PermCode=perm_code)
except Permission.DoesNotExist:
return Response({'code': 404, 'msg': '权限不存在'})
if LegacyRolePermission.objects.filter(role=role, permission=perm).exists():
# 检查是否已存在
if RolePermission.objects.filter(RoleUUID=role.RoleUUID, PermUUID=perm.PermUUID).exists():
return Response({'code': 400, 'msg': '该角色已拥有此权限'})
LegacyRolePermission.objects.create(role=role, permission=perm)
RolePermission.objects.create(
RolePermUUID=uuid.uuid4().bytes,
RoleUUID=role.RoleUUID,
PermUUID=perm.PermUUID,
CreateTime=timezone.now(),
)
return Response({'code': 0, 'msg': '权限添加成功'})
elif action == 'remove_permission':
perm_code = request.data.get('perm_code')
if not perm_code:
return Response({'code': 400, 'msg': '缺少权限编码'})
if role.role_name == '管理员' and perm_code == '000001':
if role.RoleName == '管理员' and perm_code == '000001':
return Response({'code': 403, 'msg': '不能移除超级管理员的此权限'})
perm = BackendPermission.objects.filter(perm_code=perm_code).first()
if not perm:
try:
perm = Permission.objects.get(PermCode=perm_code)
except Permission.DoesNotExist:
return Response({'code': 404, 'msg': '权限不存在'})
deleted, _ = LegacyRolePermission.objects.filter(role=role, permission=perm).delete()
deleted, _ = RolePermission.objects.filter(RoleUUID=role.RoleUUID, PermUUID=perm.PermUUID).delete()
if deleted == 0:
return Response({'code': 400, 'msg': '该角色未拥有此权限'})
return Response({'code': 0, 'msg': '权限移除成功'})
@@ -284,32 +272,45 @@ class ModifyRolePermissionView(APIView):
role_name = (request.data.get('role_name') or '').strip()
description = (request.data.get('description') or '').strip()
perm_codes = request.data.get('perm_codes') or []
from backend.models import Role as BackendRole
if role.role_name == '管理员':
role_name = role.role_name
elif role_name and role_name != role.role_name:
if BackendRole.objects.filter(role_name=role_name).exclude(role_id=role.role_id).exists():
if role.RoleName == '管理员':
role_name = role.RoleName
elif role_name and role_name != role.RoleName:
if Role.objects.filter(RoleName=role_name).exclude(RoleUUID=role.RoleUUID).exists():
return Response({'code': 400, 'msg': '角色名称已存在'})
with transaction.atomic():
if role.role_name != '管理员':
if role.RoleName != '管理员':
if role_name:
role.role_name = role_name
role.description = description
role.save(update_fields=['role_name', 'description'])
LegacyRolePermission.objects.filter(role=role).delete()
role.RoleName = role_name
role.RoleDesc = description
role.save(update_fields=['RoleName', 'RoleDesc'])
RolePermission.objects.filter(RoleUUID=role.RoleUUID).delete()
for pc in perm_codes:
if pc == '000001' and role.role_name != '管理员':
if pc == '000001' and role.RoleName != '管理员':
continue
perm = BackendPermission.objects.filter(perm_code=pc).first()
if not perm:
try:
perm = Permission.objects.get(PermCode=pc, PermStatus=1)
except Permission.DoesNotExist:
continue
LegacyRolePermission.objects.create(role=role, permission=perm)
if role.role_name == '管理员':
super_perm = BackendPermission.objects.filter(perm_code='000001').first()
if super_perm and not LegacyRolePermission.objects.filter(
role=role, permission=super_perm,
).exists():
LegacyRolePermission.objects.create(role=role, permission=super_perm)
RolePermission.objects.create(
RolePermUUID=uuid.uuid4().bytes,
RoleUUID=role.RoleUUID,
PermUUID=perm.PermUUID,
CreateTime=timezone.now(),
)
if role.RoleName == '管理员':
try:
super_perm = Permission.objects.get(PermCode='000001', PermStatus=1)
if not RolePermission.objects.filter(
RoleUUID=role.RoleUUID, PermUUID=super_perm.PermUUID,
).exists():
RolePermission.objects.create(
RolePermUUID=uuid.uuid4().bytes,
RoleUUID=role.RoleUUID,
PermUUID=super_perm.PermUUID,
CreateTime=timezone.now(),
)
except Permission.DoesNotExist:
pass
return Response({'code': 0, 'msg': '角色保存成功'})
else:
@@ -338,33 +339,47 @@ class AddRoleView(APIView):
if '000001' not in permissions:
return Response({'code': 403, 'msg': '您无权进行此操作'})
from backend.models import (
Role as BackendRole,
Permission as BackendPermission,
RolePermission as LegacyRolePermission,
# 检查角色名称是否已存在(同俱乐部内唯一)
from jituan.services.club_rbac import resolve_role_club_id, role_name_exists
target_club_id = resolve_role_club_id(
request, (request.data.get('target_club_id') or '').strip() or None,
)
if role_name_exists(role_name, target_club_id):
return Response({'code': 400, 'msg': '该俱乐部下角色名称已存在'})
if BackendRole.objects.filter(role_name=role_name).exists():
return Response({'code': 400, 'msg': '角色名称已存在'})
# 生成唯一角色编码格式ROLE_ + 8位随机字母数字
role_code = f"ROLE_{''.join(random.choices(string.ascii_uppercase + string.digits, k=8))}"
# 创建角色
with transaction.atomic():
role = BackendRole.objects.create(
role_code=role_code,
role_name=role_name,
description=description,
role = Role.objects.create(
RoleUUID=uuid.uuid4().bytes,
TenantUUID=b'\x00' * 16,
RoleName=role_name,
RoleType=2,
RoleStatus=1,
AssignScope=0,
RoleDesc=description,
ClubID=target_club_id,
CreateTime=timezone.now(),
)
# 绑定权限(过滤掉不存在的权限编码)
for pc in perm_codes:
# 不允许添加 000001 权限(此权限仅供超级管理员)
if pc == '000001':
continue
perm = BackendPermission.objects.filter(perm_code=pc).first()
if not perm:
try:
perm = Permission.objects.get(PermCode=pc)
RolePermission.objects.create(
RolePermUUID=uuid.uuid4().bytes,
RoleUUID=role.RoleUUID,
PermUUID=perm.PermUUID,
CreateTime=timezone.now(),
)
except Permission.DoesNotExist:
logger.warning(f"添加角色时忽略不存在的权限编码: {pc}")
continue
LegacyRolePermission.objects.create(role=role, permission=perm)
return Response({'code': 0, 'msg': '角色添加成功', 'data': {'role_code': role_name}})
return Response({'code': 0, 'msg': '角色添加成功', 'data': {'role_code': role_code}})
@@ -403,14 +418,15 @@ class GetAdminUserListView(APIView):
if nicheng:
users = users.filter(KefuProfile__nicheng__icontains=nicheng)
# 关键修正:先求值为列表,再传入 phone__in
if role_code:
from backend.models import Role as BackendRole, UserRole as LegacyUserRole
target_role = _resolve_backend_role(role_code)
target_role = Role.objects.filter(RoleName=role_code).first()
if target_role:
account_ids = list(
LegacyUserRole.objects.filter(role=target_role).values_list('account_id', flat=True)
user_uuids = list(
UserRole.objects.filter(RoleUUID=target_role.RoleUUID)
.values_list('UserUUID', flat=True)
)
users = users.filter(Phone__in=account_ids)
users = users.filter(UserUUID__in=user_uuids)
else:
users = users.none()
@@ -419,12 +435,16 @@ class GetAdminUserListView(APIView):
page_obj = paginator.get_page(page)
data_list = []
from backend.models import UserRole as LegacyUserRole
for user in page_obj:
user_roles = LegacyUserRole.objects.filter(account_id=user.Phone).select_related('role')
# 通过 gvsdsdk UserRole 获取用户角色
user_role_uuids = list(
UserRole.objects.filter(UserUUID=user.UserUUID)
.values_list('RoleUUID', flat=True)
)
user_roles = Role.objects.filter(RoleUUID__in=user_role_uuids)
roles_data = [
{'role_code': ur.role.role_name, 'role_name': ur.role.role_name}
for ur in user_roles
{'role_code': r.RoleName, 'role_name': r.RoleName}
for r in user_roles
]
data_list.append({
'phone': user.Phone or '',
@@ -470,16 +490,16 @@ class GetAdminRolesView(APIView):
if '000001' not in permissions:
return Response({'code': 403, 'msg': '您无权访问此页面'})
from backend.models import Role as BackendRole
roles = BackendRole.objects.all().order_by('role_id')
from jituan.services.club_rbac import filter_roles_for_request
roles = filter_roles_for_request(request).values('RoleName', 'ClubID')
return Response({
'code': 0,
'data': {
'roles': [
{
'role_code': r.role_name,
'role_name': r.role_name,
'club_id': '',
'role_code': r['RoleName'],
'role_name': r['RoleName'],
'club_id': r.get('ClubID') or '',
}
for r in roles
]
@@ -618,22 +638,25 @@ class ModifyAdminUserView(APIView):
role_codes = request.data.get('role_codes', [])
if not role_codes:
return Response({'code': 400, 'msg': '请选择角色'})
from backend.models import Role as BackendRole, UserRole as LegacyUserRole
from jituan.services.club_rbac import resolve_role_by_name
club_id = getattr(target_user, 'ClubID', '') or ''
added, missing = [], []
for rc in role_codes:
role = _resolve_backend_role(rc)
role = resolve_role_by_name(rc, club_id)
if not role:
missing.append(rc)
continue
LegacyUserRole.objects.get_or_create(
account_id=target_user.Phone,
role=role,
UserRole.objects.get_or_create(
UserRoleUUID=uuid.uuid4().bytes,
UserUUID=target_user.UserUUID,
RoleUUID=role.RoleUUID,
CompanyUUID=uuid.UUID('b0000000-0000-0000-0000-000000000001').bytes,
)
added.append(role.role_name)
added.append(role.RoleName)
if not added:
return Response({
'code': 400,
'msg': f'未找到可绑定的角色:{", ".join(missing or role_codes)}',
'msg': f'未找到可绑定的角色:{", ".join(missing or role_codes)}。请确认顶栏俱乐部与角色所属俱乐部一致',
})
if missing:
return Response({
@@ -646,11 +669,12 @@ class ModifyAdminUserView(APIView):
role_code = request.data.get('role_code')
if not role_code:
return Response({'code': 400, 'msg': '缺少角色编码'})
from backend.models import UserRole as LegacyUserRole
role = _resolve_backend_role(role_code)
from jituan.services.club_rbac import resolve_role_by_name
club_id = getattr(target_user, 'ClubID', '') or ''
role = resolve_role_by_name(role_code, club_id)
if not role:
return Response({'code': 404, 'msg': '角色不存在'})
LegacyUserRole.objects.filter(account_id=target_user.Phone, role=role).delete()
return Response({'code': 404, 'msg': '角色不存在或与用户俱乐部不匹配'})
UserRole.objects.filter(UserUUID=target_user.UserUUID, RoleUUID=role.RoleUUID).delete()
return Response({'code': 0, 'msg': '角色移除成功'})
else: