Добавлена система ролей пользователей для управления доступом в multi-tenant приложении. Новые роли: - Владелец (Owner): полный доступ, управление пользователями - Менеджер (Manager): управление заказами, клиентами, товарами, складом - Флорист (Florist): работа с заказами и складскими операциями - Курьер (Courier): роль создана, права будут определены позже Архитектура: - Роли автоматически изолируются по тенантам через django-tenants (TENANT_APPS) - Не требуется FK на Client/Tenant - изоляция через PostgreSQL schemas - Роли автоматически создаются при создании нового тенанта Компоненты: - user_roles/models.py: модели Role и UserRole - user_roles/services.py: RoleService для управления ролями - user_roles/decorators.py: @role_required, @owner_required - user_roles/mixins.py: RoleBasedAdminMixin, OwnerOnlyAdminMixin - user_roles/admin.py: админка для управления ролями - user_roles/management/commands/init_roles.py: команда для инициализации Изменения: - accounts/models.py: добавлены helper методы (is_owner, has_role, etc) - settings.py: добавлен user_roles в TENANT_APPS - tenants/admin.py: автосоздание ролей при создании тенанта 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
101 lines
4.0 KiB
Python
101 lines
4.0 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.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_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
|