from django.conf import settings from django.contrib.auth.models import ( AbstractBaseUser, BaseUserManager, PermissionsMixin, ) from django.contrib.contenttypes.models import ContentType from django.db import models from django.utils.translation import ugettext_lazy as _ from django_otp.models import Device from pretix.base.i18n import language from pretix.helpers.urls import build_absolute_uri from .base import LoggingMixin class UserManager(BaseUserManager): """ This is the user manager for our custom user model. See the User model documentation to see what's so special about our user model. """ def create_user(self, email: str, password: str=None, **kwargs): user = self.model(email=email, **kwargs) user.set_password(password) user.save() return user def create_superuser(self, email: str, password: str=None): # NOQA # Not used in the software but required by Django if password is None: raise Exception("You must provide a password") user = self.model(email=email) user.is_staff = True user.is_superuser = True user.set_password(password) user.save() return user class User(AbstractBaseUser, PermissionsMixin, LoggingMixin): """ This is the user model used by pretix for authentication. :param email: The user's email address, used for identification. :type email: str :param fullname: The user's full name. May be empty or null. :type fullname: str :param is_active: Whether this user account is activated. :type is_active: bool :param is_staff: ``True`` for system operators. :type is_staff: bool :param date_joined: The datetime of the user's registration. :type date_joined: datetime :param locale: The user's preferred locale code. :type locale: str :param timezone: The user's preferred timezone. :type timezone: str """ USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] email = models.EmailField(unique=True, db_index=True, null=True, blank=True, verbose_name=_('E-mail')) fullname = models.CharField(max_length=255, blank=True, null=True, verbose_name=_('Full name')) is_active = models.BooleanField(default=True, verbose_name=_('Is active')) is_staff = models.BooleanField(default=False, verbose_name=_('Is site admin')) date_joined = models.DateTimeField(auto_now_add=True, verbose_name=_('Date joined')) locale = models.CharField(max_length=50, choices=settings.LANGUAGES, default=settings.LANGUAGE_CODE, verbose_name=_('Language')) timezone = models.CharField(max_length=100, default=settings.TIME_ZONE, verbose_name=_('Timezone')) require_2fa = models.BooleanField(default=False) objects = UserManager() class Meta: verbose_name = _("User") verbose_name_plural = _("Users") def save(self, *args, **kwargs): self.email = self.email.lower() super().save(*args, **kwargs) def __str__(self): return self.email def get_short_name(self) -> str: """ Returns the first of the following user properties that is found to exist: * Full name * Email address Only present for backwards compatibility """ if self.fullname: return self.fullname else: return self.email def get_full_name(self) -> str: """ Returns the first of the following user properties that is found to exist: * Full name * Email address """ if self.fullname: return self.fullname else: return self.email def send_security_notice(self, messages, email=None): from pretix.base.services.mail import mail, SendMailException try: with language(self.locale): msg = '- ' + '\n- '.join(str(m) for m in messages) mail( email or self.email, _('Account information changed'), 'pretixcontrol/email/security_notice.txt', { 'user': self, 'messages': msg, 'url': build_absolute_uri('control:user.settings') }, event=None, locale=self.locale ) except SendMailException: pass # Already logged @property def all_logentries(self): from pretix.base.models import LogEntry return LogEntry.objects.filter(content_type=ContentType.objects.get_for_model(User), object_id=self.pk) class U2FDevice(Device): json_data = models.TextField()