Files
Django/jituan/services/admin_context.py

270 lines
9.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""集团后台管理员俱乐部上下文。"""
from jituan.constants import (
ADMIN_ROLE_LABELS,
DATA_SCOPE_ALL,
DATA_SCOPE_SINGLE,
CLUB_ID_DEFAULT,
SUPER_ADMIN_PHONES,
)
from jituan.models import AdminAssignment, Club
GROUP_MANAGE_ROLES = frozenset({
'GROUP_OWNER',
'GROUP_SUPER_ADMIN',
})
def get_allowed_club_ids(user):
"""用户可切换/访问的子公司 club_id 集合(不含集团汇总)。"""
if is_system_super_admin(user):
return {c.club_id for c in Club.query.filter(status=1)}
assignments = AdminAssignment.query.filter(yonghuid=user.UserUID, status=1)
has_group = assignments.filter(
club_id__isnull=True
).exists() or assignments.filter(data_scope=DATA_SCOPE_ALL).exists()
if has_group:
return {c.club_id for c in Club.query.filter(status=1)}
allowed = {
a.club_id for a in assignments if a.club_id
}
if not allowed:
cid = (getattr(user, 'ClubID', None) or '').strip()
if cid:
allowed = {cid}
return allowed
def resolve_admin_effective_club(user, request):
"""
校验后台用户请求的俱乐部/范围,返回 (club_id, scope, error_msg)。
无权限访问请求的俱乐部时,回退到主任职俱乐部(避免 localStorage 脏数据串俱乐部)。
"""
from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope
requested_club = resolve_club_id_from_request(request)
requested_scope = resolve_club_scope(request)
if is_system_super_admin(user):
return requested_club, requested_scope, None
ctx = build_admin_club_context(user)
allowed = get_allowed_club_ids(user)
if requested_scope == DATA_SCOPE_ALL:
if not ctx.get('is_group_admin'):
primary = ctx.get('club_id') or CLUB_ID_DEFAULT
return primary, DATA_SCOPE_SINGLE, None
return ctx.get('club_id') or CLUB_ID_DEFAULT, DATA_SCOPE_ALL, None
if requested_club not in allowed:
primary = ctx.get('club_id') or CLUB_ID_DEFAULT
return primary, DATA_SCOPE_SINGLE, None
return requested_club, DATA_SCOPE_SINGLE, None
def build_admin_club_context(user):
"""
根据 admin_assignment + 超管推断后台登录后的俱乐部上下文。
返回 dict 供前端存储与请求头使用。
"""
yonghuid = user.UserUID
is_super = is_system_super_admin(user)
assignments = list(
AdminAssignment.query.filter(yonghuid=yonghuid, status=1).order_by('-is_primary', 'club_id')
)
clubs_qs = Club.query.filter(status=1).order_by('sort_order', 'club_id')
all_clubs = [
{'club_id': c.club_id, 'name': c.name}
for c in clubs_qs
]
# 系统超管:始终集团视角 + 全部俱乐部(不受任职记录限制)
if is_super:
role_code = 'GROUP_SUPER_ADMIN'
if assignments:
primary = next((a for a in assignments if a.is_primary), assignments[0])
role_code = primary.role_code or role_code
return _pack(
scope=DATA_SCOPE_ALL,
club_id=CLUB_ID_DEFAULT,
is_group_admin=True,
assignments=assignments,
clubs=all_clubs,
can_switch_club=True,
role_code=role_code,
role_name=ADMIN_ROLE_LABELS.get(role_code, role_code),
)
if not assignments:
allowed_ids = get_allowed_club_ids(user)
visible_clubs = [c for c in all_clubs if c['club_id'] in allowed_ids]
club_id = next(iter(allowed_ids), CLUB_ID_DEFAULT) if allowed_ids else CLUB_ID_DEFAULT
return _pack(
scope=DATA_SCOPE_SINGLE,
club_id=club_id,
is_group_admin=False,
assignments=[],
clubs=visible_clubs,
can_switch_club=len(visible_clubs) > 1,
role_code='CLUB_ADMIN',
role_name='子公司客服(默认)',
)
primary = next((a for a in assignments if a.is_primary), assignments[0])
has_group = any(
a.club_id is None or a.data_scope == DATA_SCOPE_ALL
for a in assignments
)
allowed_ids = get_allowed_club_ids(user)
if has_group:
scope = DATA_SCOPE_ALL
club_id = CLUB_ID_DEFAULT
visible_clubs = all_clubs
else:
scope = DATA_SCOPE_SINGLE
primary_cid = primary.club_id or CLUB_ID_DEFAULT
if primary_cid in allowed_ids:
club_id = primary_cid
elif allowed_ids:
club_id = sorted(allowed_ids)[0]
else:
club_id = primary_cid
visible_clubs = [c for c in all_clubs if c['club_id'] in allowed_ids]
role_code = primary.role_code or 'CLUB_ADMIN'
return _pack(
scope=scope,
club_id=club_id,
is_group_admin=has_group,
assignments=assignments,
clubs=visible_clubs,
can_switch_club=has_group or len(visible_clubs) > 1,
role_code=role_code,
role_name=ADMIN_ROLE_LABELS.get(role_code, role_code),
)
def is_system_super_admin(user):
"""系统级超管Django 超管 / admin 账号 / 白名单手机号),非俱乐部 000001 角色。"""
return (
bool(user.IsSuperuser)
or user.UserType == 'admin'
or getattr(user, 'Phone', '') in SUPER_ADMIN_PHONES
)
def is_kefu_backend_account(user):
"""可登录客服后台:超管 / UserType=kefu / 有正常 KefuProfile。"""
if is_system_super_admin(user):
return True
if getattr(user, 'UserType', '') == 'kefu':
return True
try:
return user.KefuProfile.zhuangtai == 1
except Exception:
return False
def can_manage_admin_assignments(user, permissions=None):
"""是否可维护数据范围任职、俱乐部密钥等集团级配置(不含俱乐部 000001"""
if is_system_super_admin(user):
return True
ctx = build_admin_club_context(user)
if ctx.get('is_group_admin') and ctx.get('role_code') in GROUP_MANAGE_ROLES:
return True
return any(
a.role_code in GROUP_MANAGE_ROLES
and (a.club_id is None or a.data_scope == DATA_SCOPE_ALL)
for a in AdminAssignment.query.filter(yonghuid=user.UserUID, status=1)
)
def get_switchable_club_ids(user):
"""顶栏可切换俱乐部:有任职/数据范围即可切换;菜单按当前俱乐部功能角色展示。"""
return get_allowed_club_ids(user)
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.constants import DATA_SCOPE_SINGLE
from jituan.services.club_rbac import resolve_effective_permission_codes
# 与菜单/verify_kefu 同一套:含 legacy避免「页面能进但添加按钮出不来」
codes = resolve_effective_permission_codes(user, cid, DATA_SCOPE_SINGLE)
return '000001' in (codes or [])
def get_manageable_club_ids(user, permissions=None, current_club_id=None):
"""
当前操作者可管理角色/后台用户的俱乐部集合。
current_club_id若请求上下文已带 000001务必把当前顶栏俱乐部算进去。
"""
if can_manage_admin_assignments(user, permissions):
return {c.club_id for c in Club.query.filter(status=1)}
ids = {
c.club_id for c in Club.query.filter(status=1)
if can_manage_roles_for_club(user, permissions, c.club_id)
}
cid = (current_club_id or '').strip()
if cid and permissions and '000001' in permissions:
ids.add(cid)
return ids
def can_access_admin_user_management(user, permissions=None):
"""
是否可访问「后台用户」页(列表、按俱乐部分配功能角色)。
系统超管 / 000001 / 集团高管 / 任一俱乐部超管均可。
"""
if is_system_super_admin(user):
return True
if permissions and '000001' in permissions:
return True
if can_manage_admin_assignments(user, permissions):
return True
return bool(get_manageable_club_ids(user, permissions))
def _pack(scope, club_id, is_group_admin, assignments, clubs, can_switch_club,
role_code, role_name):
allowed_club_ids = sorted({
c['club_id'] for c in clubs if c.get('club_id')
})
return {
'scope': scope,
'club_id': club_id,
'is_group_admin': is_group_admin,
'role_code': role_code,
'role_name': role_name,
'allowed_club_ids': allowed_club_ids,
'perm_source': 'gvsdsdk',
'perm_note': (
'【功能权限】在「角色管理」为各俱乐部创建角色,在「管理员用户」绑定;'
'切换俱乐部后菜单按该俱乐部角色生效。'
'【数据范围】在本页添加任职,可分配多个俱乐部,无需集团权限即可切换。'
),
'assignments': [
{
'club_id': a.club_id,
'role_code': a.role_code,
'role_name': ADMIN_ROLE_LABELS.get(a.role_code, a.role_code),
'data_scope': a.data_scope,
'is_primary': a.is_primary,
}
for a in assignments
],
'clubs': clubs,
'can_switch_club': can_switch_club,
}