149 lines
6.1 KiB
Python
149 lines
6.1 KiB
Python
from django.db import transaction
|
||
from user_roles.models import Role, UserRole
|
||
from django.contrib.auth import get_user_model
|
||
|
||
User = get_user_model()
|
||
|
||
|
||
class RoleService:
|
||
"""Сервис для управления ролями"""
|
||
|
||
@staticmethod
|
||
def create_default_roles():
|
||
"""
|
||
Создает системные роли для тенанта.
|
||
Вызывается при создании тенанта (автоматически через signals или admin).
|
||
|
||
ВАЖНО: Эта функция вызывается в контексте schema_context(tenant.schema_name),
|
||
поэтому роли создаются в schema конкретного тенанта автоматически!
|
||
"""
|
||
default_roles = [
|
||
{
|
||
'code': Role.PLATFORM_SUPPORT,
|
||
'name': 'Техподдержка платформы',
|
||
'description': 'Служебный аккаунт техподдержки платформы. Полный доступ для помощи владельцу.',
|
||
'is_system': True,
|
||
},
|
||
{
|
||
'code': Role.OWNER,
|
||
'name': 'Владелец',
|
||
'description': 'Полный доступ ко всем функциям системы. Управление пользователями и настройками.',
|
||
'is_system': True,
|
||
},
|
||
{
|
||
'code': Role.MANAGER,
|
||
'name': 'Менеджер',
|
||
'description': 'Управление заказами, клиентами, товарами и складом. Без доступа к настройкам.',
|
||
'is_system': True,
|
||
},
|
||
{
|
||
'code': Role.FLORIST,
|
||
'name': 'Флорист',
|
||
'description': 'Работа с заказами и складскими операциями для заказов.',
|
||
'is_system': True,
|
||
},
|
||
{
|
||
'code': Role.COURIER,
|
||
'name': 'Курьер',
|
||
'description': 'Доставка заказов (права будут определены позже).',
|
||
'is_system': True,
|
||
},
|
||
]
|
||
|
||
for role_data in default_roles:
|
||
Role.objects.get_or_create(
|
||
code=role_data['code'],
|
||
defaults=role_data
|
||
)
|
||
|
||
@staticmethod
|
||
def get_visible_roles():
|
||
"""
|
||
Возвращает роли, видимые для пользователей тенанта.
|
||
Исключает служебные роли (platform_support).
|
||
"""
|
||
return Role.objects.exclude(code__in=Role.HIDDEN_ROLES)
|
||
|
||
@staticmethod
|
||
def get_visible_users():
|
||
"""
|
||
Возвращает пользователей, видимых для владельца тенанта.
|
||
Исключает пользователей с ролью platform_support.
|
||
"""
|
||
from accounts.models import CustomUser
|
||
hidden_user_ids = UserRole.objects.filter(
|
||
role__code__in=Role.HIDDEN_ROLES
|
||
).values_list('user_id', flat=True)
|
||
return CustomUser.objects.exclude(id__in=hidden_user_ids)
|
||
|
||
@staticmethod
|
||
def get_role_by_code(code):
|
||
"""Получить роль по коду"""
|
||
try:
|
||
return Role.objects.get(code=code, is_system=True)
|
||
except Role.DoesNotExist:
|
||
return None
|
||
|
||
@staticmethod
|
||
@transaction.atomic
|
||
def assign_role_to_user(user, role_code, created_by=None):
|
||
"""
|
||
Назначить роль пользователю в текущем тенанте.
|
||
Если у пользователя уже есть роль - обновляет её.
|
||
|
||
ВАЖНО: Вызывается в контексте текущего тенанта (через middleware),
|
||
поэтому UserRole создается в schema текущего тенанта автоматически!
|
||
"""
|
||
role = RoleService.get_role_by_code(role_code)
|
||
if not role:
|
||
raise ValueError(f"Роль с кодом '{role_code}' не найдена")
|
||
|
||
user_role, created = UserRole.objects.update_or_create(
|
||
user=user,
|
||
defaults={
|
||
'role': role,
|
||
'created_by': created_by,
|
||
'is_active': True,
|
||
}
|
||
)
|
||
return user_role
|
||
|
||
@staticmethod
|
||
def get_user_role(user):
|
||
"""Получить роль пользователя в текущем тенанте"""
|
||
try:
|
||
user_role = UserRole.objects.get(user=user, is_active=True)
|
||
return user_role.role
|
||
except UserRole.DoesNotExist:
|
||
return None
|
||
|
||
@staticmethod
|
||
def user_has_role(user, *role_codes):
|
||
"""Проверить, имеет ли пользователь одну из указанных ролей"""
|
||
user_role = RoleService.get_user_role(user)
|
||
if not user_role:
|
||
return False
|
||
return user_role.code in role_codes
|
||
|
||
@staticmethod
|
||
def can_modify_user_role(modifier_user, target_user_role):
|
||
"""
|
||
Проверяет, может ли пользователь изменить указанную роль.
|
||
|
||
Args:
|
||
modifier_user: Пользователь, который хочет изменить роль
|
||
target_user_role: UserRole объект, который нужно изменить
|
||
|
||
Returns:
|
||
tuple: (bool, str) - (можно ли изменить, причина отказа)
|
||
"""
|
||
# Защита от самоблокировки
|
||
if target_user_role.user == modifier_user:
|
||
return False, "Вы не можете изменить свою собственную роль"
|
||
|
||
# Можно добавить другие проверки в будущем:
|
||
# - Запрет удаления последнего owner'а
|
||
# - Проверка иерархии ролей и т.д.
|
||
|
||
return True, ""
|