Files
octopus/myproject/accounts/models.py

132 lines
5.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 django.db import models
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.utils import timezone
import uuid
class CustomUserManager(BaseUserManager):
def create_user(self, email, name, password=None, **extra_fields):
if not email:
raise ValueError('Email обязателен')
email = self.normalize_email(email)
# Generate a unique username based on email to satisfy the AbstractUser constraint
username = email
# SECURITY FIX: Явно устанавливаем флаги безопасности в False по умолчанию
# Обычные пользователи НЕ должны иметь доступ к админке
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
user = self.model(email=email, name=name, username=username, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, name, password=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
# Суперпользователь автоматически имеет подтвержденный email
extra_fields.setdefault('is_email_confirmed', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Суперпользователь должен иметь is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Суперпользователь должен иметь is_superuser=True.')
user = self.create_user(email, name, password, **extra_fields)
# Устанавливаем дату подтверждения email
if user.is_email_confirmed and not user.email_confirmed_at:
user.email_confirmed_at = timezone.now()
user.save()
return user
class CustomUser(AbstractUser):
"""
Пользователь тенанта (магазина).
ВАЖНО: Эта модель в TENANT_APPS - каждый тенант имеет свою таблицу!
Один email в разных тенантах = разные записи в разных схемах БД.
Полная изоляция обеспечивается на уровне PostgreSQL schemas.
НЕ является AUTH_USER_MODEL (это PlatformAdmin).
"""
email = models.EmailField(unique=True)
name = models.CharField(max_length=100)
is_email_confirmed = models.BooleanField(default=False)
email_confirmation_token = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
email_confirmed_at = models.DateTimeField(null=True, blank=True)
password_reset_token = models.UUIDField(null=True, blank=True, editable=False, unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
objects = CustomUserManager()
# Изменяем related_name для избежания конфликта с встроенной моделью User
groups = models.ManyToManyField(
'auth.Group',
related_name='custom_user_set',
blank=True,
verbose_name='groups',
help_text='The groups this user belongs to.',
)
user_permissions = models.ManyToManyField(
'auth.Permission',
related_name='custom_user_set',
blank=True,
verbose_name='user permissions',
help_text='Specific permissions for this user.',
)
class Meta:
verbose_name = "Пользователь магазина"
verbose_name_plural = "Пользователи магазина"
def __str__(self):
return self.email
def generate_confirmation_token(self):
"""Генерирует новый токен для подтверждения email"""
self.email_confirmation_token = uuid.uuid4()
self.save()
return self.email_confirmation_token
def confirm_email(self):
"""Подтверждает email пользователя"""
self.is_email_confirmed = True
self.email_confirmed_at = timezone.now()
self.save()
def get_tenant_role(self):
"""Получить роль пользователя в текущем тенанте"""
from user_roles.services import RoleService
return RoleService.get_user_role(self)
def has_role(self, *role_codes):
"""Проверить, имеет ли пользователь одну из указанных ролей"""
from user_roles.services import RoleService
return RoleService.user_has_role(self, *role_codes)
@property
def is_owner(self):
"""Является ли пользователь владельцем"""
return self.has_role('owner')
@property
def is_manager(self):
"""Является ли пользователь менеджером"""
return self.has_role('manager')
@property
def is_florist(self):
"""Является ли пользователь флористом"""
return self.has_role('florist')
@property
def is_courier(self):
"""Является ли пользователь курьером"""
return self.has_role('courier')