All checks were successful
Deploy MES Core / deploy (push) Successful in 13s
106 lines
3.7 KiB
Python
106 lines
3.7 KiB
Python
from __future__ import annotations
|
||
|
||
from typing import Iterable
|
||
|
||
|
||
ROLE_PRIORITY = [
|
||
'admin',
|
||
'prod_head',
|
||
'technologist',
|
||
'master',
|
||
'clerk',
|
||
'supply',
|
||
'manager',
|
||
'operator',
|
||
'observer',
|
||
'director',
|
||
]
|
||
|
||
|
||
def get_user_group_roles(user) -> set[str]:
|
||
"""Возвращает роли пользователя только из Django Groups.
|
||
|
||
Используется для экранов, где включён строгий доступ "только по группам".
|
||
EmployeeProfile.role здесь намеренно не учитывается.
|
||
|
||
Правило: superuser получает роль admin.
|
||
"""
|
||
|
||
roles: set[str] = set()
|
||
if not user or not getattr(user, 'is_authenticated', False):
|
||
return roles
|
||
|
||
if getattr(user, 'is_superuser', False):
|
||
roles.add('admin')
|
||
|
||
try:
|
||
roles |= set(user.groups.values_list('name', flat=True))
|
||
except Exception:
|
||
pass
|
||
|
||
return roles
|
||
|
||
|
||
def get_user_roles(user) -> set[str]:
|
||
"""Возвращает множество ролей пользователя.
|
||
|
||
Источник ролей (вариант A, плавная миграция):
|
||
- Django Groups: позволяет назначать несколько ролей одному пользователю.
|
||
- Fallback на EmployeeProfile.role: чтобы при деплое и до раздачи групп система
|
||
продолжала работать по старой модели (одна роль).
|
||
|
||
Правило: superuser всегда получает роль admin независимо от групп/профиля.
|
||
"""
|
||
|
||
roles: set[str] = set() # Изначально множество пустое
|
||
# 1. Проверяем, что пользователь авторизован
|
||
if not user or not getattr(user, 'is_authenticated', False):
|
||
return roles
|
||
# 2. Проверяем, что пользователь не superuser
|
||
if getattr(user, 'is_superuser', False):
|
||
roles.add('admin')
|
||
# 3. Проверяем, что у пользователя есть хотя бы одна группа
|
||
try:
|
||
roles |= set(user.groups.values_list('name', flat=True))
|
||
except Exception:
|
||
pass
|
||
|
||
|
||
# 4. Проверяем, что у пользователя есть роль в EmployeeProfile
|
||
profile = getattr(user, 'profile', None)
|
||
if profile and getattr(profile, 'role', None):
|
||
roles.add(str(profile.role))
|
||
|
||
return roles
|
||
|
||
|
||
def primary_role(roles: Iterable[str]) -> str:
|
||
"""Выбирает "основную" роль для отображения в UI.
|
||
|
||
Примечание: права доступа должны проверяться по всем ролям (has_any_role).
|
||
primary_role используется только для:
|
||
- подписи/лейбла "роль пользователя" в шаблонах
|
||
- дефолтного поведения, где требуется один статус (например, оформление UI)
|
||
"""
|
||
|
||
s = set(roles or [])
|
||
for r in ROLE_PRIORITY:
|
||
if r in s:
|
||
return r
|
||
return 'operator'
|
||
|
||
|
||
def has_any_role(roles: Iterable[str], required: Iterable[str]) -> bool:
|
||
"""Проверяет, что у пользователя есть хотя бы одна роль из required.
|
||
|
||
Используется во вьюхах для разрешений вида:
|
||
roles = get_user_roles(request.user)
|
||
if not has_any_role(roles, ['admin', 'master']):
|
||
return redirect('registry')
|
||
"""
|
||
|
||
s = set(roles or [])
|
||
for r in required or []:
|
||
if r in s:
|
||
return True
|
||
return False |