Files
MES_Core/shiftflow/authz.py
2026-04-13 07:36:57 +03:00

106 lines
3.7 KiB
Python
Raw Permalink 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 __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