class Migration(migrations.Migration): dependencies = [ ("mailauth_user", "0004_auto_20200812_0722"), ] operations = [ # add new permissions migrations.AlterModelOptions( name="emailuser", options={ "permissions": [("anonymize", "Can anonymize user")], "verbose_name": "user", "verbose_name_plural": "users", }, ), # email is now nullable migrations.AlterField( model_name="emailuser", name="email", field=CIEmailField( blank=True, db_index=True, max_length=254, null=True, unique=True, verbose_name="email address", ), ), ]
class User(AbstractBaseUser, UUIDModel, PermissionsMixin): first_name = models.CharField(_('First Name'), max_length=120, blank=True) last_name = models.CharField(_('Last Name'), max_length=120, blank=True) # https://docs.djangoproject.com/en/1.11/ref/contrib/postgres/fields/#citext-fields email = CIEmailField(_('email address'), unique=True, db_index=True) is_staff = models.BooleanField(_('staff status'), default=False, help_text='Designates whether the user can log into this admin site.') is_active = models.BooleanField('active', default=True, help_text='Designates whether this user should be treated as ' 'active. Unselect this instead of deleting accounts.') date_joined = models.DateTimeField(_('date joined'), default=timezone.now) USERNAME_FIELD = 'email' objects = UserManager() class Meta: verbose_name = _('user') verbose_name_plural = _('users') ordering = ('-date_joined', ) def __str__(self): return str(self.id) def get_full_name(self) -> str: """Returns the first_name plus the last_name, with a space in between. """ full_name = '{} {}'.format(self.first_name, self.last_name) return full_name.strip() def get_short_name(self) -> str: """Returns the short name for the user. """ return self.first_name.strip()
class CustomAbstractBaseUser(AbstractBaseUser, BaseModel): first_name = models.TextField(max_length=100, db_index=True) surnames = models.TextField(max_length=100, db_index=True) email = CIEmailField(unique=True, db_index=True) is_active = models.BooleanField(default=True) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['first_name', 'surnames'] class Meta: abstract = True @property def is_staff(self): return False @property def is_user(self): return False @property def full_name(self): return ' '.join(f'{self.first_name} {self.surnames}'.split()) def get_short_name(self): # required for subclasses of `AbstractBaseUser` return self.first_name def __str__(self): return self.email
class RejectedEmailEventData(models.Model): class Meta: verbose_name = "Donnée collectée par le webhook en cas d’erreur d’envoi d’email" verbose_name_plural = "Données collectées par le webhook en cas d’erreur d’envoi d’email" REASON_INVALID = "invalid" REASON_BOUNCED = "bounced" REASON_TIMED_OUT = "timed_out" REASON_BLOCKED = "blocked" REASON_SPAM = "spam" REASON_UNSUBSCRIBED = "unsubscribed" REASON_OTHER = "other" REASON_CHOICES = ( (REASON_INVALID, "Adresse du destinataire invalide"), (REASON_BOUNCED, "Adresse préalablement 'bounced' par notre ESP"), (REASON_TIMED_OUT, "Trop de tentatives d’envoi en erreur sur ce destinataire"), (REASON_BLOCKED, "La politique de notre ESP interdit ce destinataire"), (REASON_SPAM, "Le destinataire nous a taggué comme spammeurs"), (REASON_UNSUBSCRIBED, "Le destinataire ne souhaite plus recevoir ces emails"), (REASON_OTHER, "Non précisé par l’ESP"), ) created_at = models.DateTimeField(default=now, verbose_name="Date de création") recipient = CIEmailField("Adresse e-mail du destinataire", blank=True, db_index=True) reason = models.CharField("La raison du refus de l’envoi d’email", max_length=12, choices=REASON_CHOICES)
class User(AbstractBaseUser): email = CIEmailField(_("email address"), unique=True) # Blank passwords are allowed since we only allow applicants to use # magic links to log in. password = models.CharField(_("password"), max_length=128, blank=True) date_joined = models.DateTimeField(_("date joined"), default=timezone.now) is_staff = models.BooleanField(_("user can access the admin"), default=False) USERNAME_FIELD = "email" REQUIRED_FIELDS: list[str] = [] objects = UserManager() is_active = True def __str__(self) -> str: username, domain = self.email.split("@", 1) # Hide the characters in the username other than the first one. return f"{username[0]}{'*' * (len(username) - 1)}@{domain}" # These methods are required by the Django admin. def has_module_perms(self, package_name: str) -> bool: return self.is_staff def has_perm(self, perm: str, object: object = None) -> bool: return self.is_staff
class User(AbstractUser): USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] email = CIEmailField( verbose_name=_('Email'), max_length=254, unique=True, error_messages={ 'unique': _('That email address is already taken.') } ) def save(self, *args, **kwargs): if not self.username: self.username = self.email return super().save(*args, **kwargs) def get_income_balance(self, currency): from apps.accounts.models import IncomeBalance return IncomeBalance.objects.get_or_create( user=self, balance_currency=currency, defaults={'name': f'Рахунок доходів {currency}', 'balance': Money(0, currency)} )[0] def get_spending_balance(self, currency): from apps.accounts.models import SpendingBalance return SpendingBalance.objects.get_or_create( user=self, balance_currency=currency, defaults={'name': f'Рахунок витрат {currency}', 'balance': Money(0, currency)} )[0]
class User(AbstractBaseUser, UUIDModel, PermissionsMixin): name = models.CharField(_('Name'), max_length=120, blank=True) # https://docs.djangoproject.com/en/1.11/ref/contrib/postgres/fields/#citext-fields email = CIEmailField(_('email address'), unique=True, db_index=True) is_staff = models.BooleanField( _('staff status'), default=False, help_text='Designates whether the user can log into this admin site.') about_me = models.CharField(_('Name'), max_length=120, blank=True) is_active = models.BooleanField( 'active', default=True, help_text='Designates whether this user should be treated as ' 'active. Unselect this instead of deleting accounts.') date_joined = models.DateTimeField(_('date joined'), default=timezone.now) last_login = models.DateTimeField(_('last login'), auto_now=True, null=True, blank=True) reputation = models.PositiveIntegerField(_('Reputation'), default=0) profile_photo = models.ImageField(upload_to=upload_to, blank=True, verbose_name='Profile Photo') USERNAME_FIELD = 'email' objects = UserManager() class Meta: verbose_name = _('user') verbose_name_plural = _('users') ordering = ('-date_joined', ) def __str__(self): return str(self.id)
class User(AbstractUser): initial_type = models.IntegerField( verbose_name="Initial type of user", help_text="Users can check their preference when they sign up to indicate " "they want to be volunteers or create/join organizations", choices=UserType.get_choices(), default=UserType.VOLUNTEER, null=True, ) email = CIEmailField( 'email address', unique=True, error_messages={'unique': "That email address is already in use."}, ) skype_name = models.CharField( verbose_name="Skype user name (Optional)", max_length=50, blank=True, null=True, ) phone_number = models.CharField( verbose_name="Phone number (Optional)", # validators=[PHONE_REGEX], max_length=17, blank=True, null=True, ) special_code = models.CharField( verbose_name="Special signup code (Optional)", help_text="Do you have a signup code from the person or organization that referred you to this site? These codes may unlock special features, so do not forget to use one if you have it.", max_length=20, blank=True, null=True, ) profile_image_file = models.ImageField( verbose_name="Profile image", help_text="Your profile image.", upload_to="userprofiles/", blank=True, null=True, validators=[validate_image_size], ) objects = UserManager() @property def full_name(self): return ' '.join(part for part in (self.first_name, self.last_name) if part) @property def standard_display_name(self): return f'{self.full_name} ({self.username})' if self.full_name else self.username @property def is_type_dssg_staff(self): return self.initial_type == UserType.DSSG_STAFF
class User(AbstractBaseUser, PermissionsMixin): objects = UserManager() username = models.CharField( verbose_name=_('Username'), max_length=30, unique=True, error_messages={'unique': _('That username is already taken.')}) first_name = models.CharField(verbose_name=_('First name'), max_length=30, blank=True, default='') last_name = models.CharField(verbose_name=_('Last name'), max_length=30, blank=True, default='') email = CIEmailField( verbose_name=_('Email'), max_length=254, unique=True, error_messages={'unique': _('That email address is already taken.')}) phone = PhoneField( verbose_name=_('Phone'), blank=True, default='', unique=True, error_messages={'unique': _('That phone number is already taken.')}) is_staff = models.BooleanField(verbose_name=_('Staff status'), default=False) is_active = models.BooleanField(verbose_name=_('Active status'), default=True) date_joined = models.DateTimeField(verbose_name=_('Date joined'), default=timezone.now) last_updated = models.DateTimeField(verbose_name=_('Last updated'), auto_now=True) avatar = models.URLField(verbose_name=_('Avatar'), null=True, blank=True) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username', 'phone'] class Meta: verbose_name = _('User') verbose_name_plural = _('Users') def __str__(self): return f'{self.get_full_name()} {self.email}' def get_short_name(self): return self.first_name def get_full_name(self): return f'{self.first_name} {self.last_name}' get_full_name.short_description = _('Full name')
class User(AbstractUser): """User model.""" username = None email = CIEmailField(_("email address"), unique=True) USERNAME_FIELD = "email" REQUIRED_FIELDS = [] objects = UserManager()
class User(AbstractBaseUser, UUIDModel, PermissionsMixin): name = models.CharField(_('Full Name'), max_length=120) # https://docs.djangoproject.com/en/1.11/ref/contrib/postgres/fields/#citext-fields email = CIEmailField(_('email address'), unique=True, db_index=True) phone_regex = RegexValidator( regex=r'^\+?1?\d{9,15}$', message= "Phone number must be entered in the format: '+999999999'. Up to 15 digits." ) phone_number = models.CharField(validators=[phone_regex], max_length=17) # Language choices as defined by ISO 639 https://en.wiktionary.org/wiki/Index:All_languages language = models.CharField(max_length=2, choices=(('en', 'English'), ('fr', 'French'), ('de', 'German'), ('it', 'Italian'), ('ja', 'Japanese'), ('hi', 'Hindi'), ('ko', 'Korean'), ('ru', 'Russian'))) # Currency choices as defined by ISO 4217 https://en.wikipedia.org/wiki/ISO_4217#Active_codes currency = models.CharField(max_length=3, choices=( ('USD', 'United States dollar'), ('EUR', 'Euro'), ('JPY', 'Japanese yen'), ('INR', 'Indian rupee'), ('KPW', 'North Korean won'), ('KRW', 'South Korean won'), ('RUB', 'Russian ruble'), )) is_staff = models.BooleanField( _('staff status'), default=False, help_text='Designates whether the user can log into this admin site.') is_active = models.BooleanField( 'active', default=True, help_text='Designates whether this user should be treated as ' 'active. Unselect this instead of deleting accounts.') date_joined = models.DateTimeField(_('date joined'), default=timezone.now) USERNAME_FIELD = 'email' objects = UserManager() class Meta: verbose_name = _('user') verbose_name_plural = _('users') ordering = ('-date_joined', ) def __str__(self): return str(self.id) def get_name(self) -> str: """Returns the name of user. """ return self.name
class User(AbstractUser): username = None first_name = None last_name = None REQUIRED_FIELDS = [] # STAFF name = CharField(_("Name of User"), blank=True, max_length=255) id_card = models.ImageField(upload_to="staff/id_card/", blank=True) # CUSTOMER addresses = models.ManyToManyField(Address, blank=True, related_name="user_addresses") default_shipping_address = models.ForeignKey( Address, related_name="+", null=True, blank=True, on_delete=models.SET_NULL ) balance = models.PositiveIntegerField(default=0) # Based email = CIEmailField(unique=True) note = models.TextField(blank=True) USERNAME_FIELD = "email" objects = UserManager() class Meta: permissions = ( (UserPermissions.MANAGE_CUSTOMERS.codename, "Manage customers"), (UserPermissions.MANAGE_STAFF.codename, "Manage staff"), (GroupPermissions.MANAGE_GROUPS.codename, "Manage groups"), ) def save(self, *args, **kwargs): """ Always save the email as lowercase. Helps identifying unique email addresses. The de jure standard is that the local component of email addresses is case sensitive however the de facto standard is that they are not. In practice what happens is user confusion over why an email address entered with camel casing one day does not match an email address """ self.email = self.email.strip().lower() return super().save(*args, **kwargs) def get_full_name(self): if self.name: return self.name return self.email def get_short_name(self): return self.email def has_perm(self, perm, obj=None): # type: ignore # This method is overridden to accept perm as BasePermissionEnum return super().has_perm(perm.value, obj)
class User(AbstractUser, BaseModel): email = CIEmailField( unique=True, null=False, blank=False ) first_name = models.CharField( null=False, blank=False, max_length=50 ) last_name = models.CharField( null=False, blank=False, max_length=50 ) verified_email = models.BooleanField( default=False ) # configs USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['first_name', 'last_name'] EMAIL_FIELD = 'email' objects = CustomUserManager() @property def full_name(self): return self.get_full_name() def delete(self): '''Before user soft delete, delete any saved passport photo''' self.delete_passport_photo() super().delete() def hard_delete(self, **kwargs): '''Before user hard delete, delete any saved passport photo''' self.delete_passport_photo() super().hard_delete(**kwargs) def delete_passport_photo(self): '''Passport photo delete helper that executes''' try: self.passport_photo.delete() except User.passport_photo.RelatedObjectDoesNotExist: pass def __str__(self): return self.email
class EmailUserMixin(models.Model): email = CIEmailField( verbose_name=_('Email address'), unique=True, max_length=511, ) email_verified = True objects = UserManager() USERNAME_FIELD = 'email' class Meta: abstract = True
class User(AbstractUser): USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] email = CIEmailField( verbose_name=_('Email'), max_length=254, unique=True, error_messages={'unique': _('That email address is already taken.')}) def save(self, *args, **kwargs): if not self.username: self.username = self.email return super().save(*args, **kwargs)
class User(AbstractBaseUser, PermissionsMixin): username = CICharField( _('username'), max_length=128, unique=True, help_text= _('Username must match the name in the game IL-2 (including squad tag).' ), # validators=[validators.username], error_messages={ 'unique': _('A user with that username already exists.') }) email = CIEmailField('Email', unique=True) is_staff = models.BooleanField( _('staff status'), default=False, help_text=_( 'Designates whether the user can log into this admin site.')) is_active = models.BooleanField( _('active'), default=True, help_text=_('Designates whether this user should be treated as ' 'active. Unselect this instead of deleting accounts.')) tz = models.CharField(_('timezone'), max_length=64, blank=True, choices=TIME_ZONE_CHOICES) date_joined = models.DateTimeField(_('date joined'), default=timezone.now) objects = UserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] class Meta: db_table = 'users' verbose_name = _('user') verbose_name_plural = _('users') def get_full_name(self): return self.username def get_short_name(self): return self.username
class Applicant(models.Model): applicant_id = models.AutoField(primary_key=True) email = CIEmailField( 'email address', unique=True, error_messages={ 'unique': "An applicant with that email already exists.", }, ) created = models.DateTimeField(auto_now_add=True) class Meta: db_table = 'applicant' def __str__(self): return self.email
class Subscription(TimeStampedModel): email = CIEmailField( verbose_name=_('Email'), max_length=254, unique=True, error_messages={ 'unique': _('That email address is already subscribed.') } ) subscribed = models.BooleanField( verbose_name=_('Subscribed'), default=True ) edit_token = models.UUIDField(default=uuid.uuid4, editable=False) class Meta: verbose_name = _('Subscription') verbose_name_plural = _('Subscriptions') def save(self, **kwargs): previously_subscribed = False if self.pk: prev_version = Subscription.objects.get(pk=self.pk) previously_subscribed = prev_version.subscribed super().save(**kwargs) if not previously_subscribed and self.subscribed: send_template_email.delay( recipient=self.email, subject_template_name='emails/subscription_subject.txt', email_template_name='emails/subscription.txt', html_email_template_name='emails/subscription.html', context={ 'token': self.edit_token, 'host': settings.UI_URL }, language=get_language() ) url = reverse('admin:users_subscription_change', kwargs={'object_id': self.id}) send_email_to_managers.delay( subject="Новая подписка", message=f"Появилась новая подписка на сайте: {settings.API_URL}{url}" ) def __str__(self): subscribed = 'subscribed' if self.subscribed else 'not subscribed' return f'{self.email}: {subscribed}'
class User(AbstractBaseUser, PermissionsMixin): USERNAME_FIELD = 'email' # REQUIRED_FIELDS = ['email'] email = CIEmailField(verbose_name="email", max_length=60, unique=True) first_name = models.CharField(max_length=64, null=True, blank=True) last_name = models.CharField(max_length=64, null=True, blank=True) date_joined = models.DateTimeField(verbose_name="date joined", auto_now_add=True) last_login = models.DateTimeField(verbose_name="last login", auto_now=True) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) is_superuser = models.BooleanField(default=False) objects = CustomUserManager() def __str__(self): return self.email
def _operations(): if CIEmailField: yield CITextExtension() yield migrations.AlterField( model_name="emailuser", name="email", field=CIEmailField(db_index=True, max_length=254, unique=True, verbose_name="email address"), ) else: yield migrations.RunSQL( sql=("CREATE UNIQUE INDEX mailauth_user_emailuser_email_upper_idx" ' ON mailauth_user_emailuser (UPPER("email"));', ), reverse_sql=( "DROP INDEX mailauth_user_emailuser_email_upper_idx;", ), )
class User(AbstractUser, UserInterface): class Meta: db_table = "identity.user" USERNAME_FIELD = "email" REQUIRED_FIELDS = [] username = None id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) email = CIEmailField(_("email address"), unique=True) accepted_tos = models.BooleanField(default=False) objects = UserManager() @property def display_name(self): if self.first_name or self.last_name: return f"{self.first_name} {self.last_name}".strip() return self.email @property def initials(self): if self.first_name != "" and self.last_name != "": return f"{self.first_name[0]}{self.last_name[0]}".upper() return self.email[:2].upper() def has_feature_flag(self, code: str) -> bool: try: # Always return True for "forced-activated features" Feature.objects.get(code=code, force_activate=True) return True except Feature.DoesNotExist: return self.featureflag_set.filter(feature__code=code).exists() def is_member_of(self, team): return self.membership_set.filter(team=team).exists() def is_admin_of(self, team): return self.membership_set.filter(team=team, role=MembershipRole.ADMIN).exists() def __str__(self): return self.display_name
class User(AbstractBaseUser, PermissionsMixin): """Cusomtized version of the default `AbstractUser` from Django. """ first_name = models.CharField(_('first name'), max_length=100, blank=True) last_name = models.CharField(_('last name'), max_length=100, blank=True) email = CIEmailField(_('email address'), blank=True, unique=True) is_staff = models.BooleanField( _('staff status'), default=False, help_text=_('Designates whether the user can log into this admin ' 'site.')) is_active = models.BooleanField( _('active'), default=True, help_text=_('Designates whether this user should be treated as ' 'active. Unselect this instead of deleting accounts.')) date_joined = models.DateTimeField(_('date joined'), default=timezone.now) objects = UserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] class Meta: verbose_name = _('user') verbose_name_plural = _('users') def get_full_name(self): """ Returns the first_name plus the last_name, with a space in between. """ full_name = '%s %s' % (self.first_name, self.last_name) return full_name.strip() def get_short_name(self): "Returns the short name for the user." return self.first_name def email_user(self, subject, message, from_email=None, **kwargs): """ Sends an email to this User. """ send_mail(subject, message, from_email, [self.email], **kwargs)
class User(AbstractBaseUser): id = UUIDField(primary_key=True, default=uuid.uuid4, editable=False) email = CIEmailField(verbose_name="email", max_length=100, unique=True) username = CICharField(max_length=50, unique=True) first_name = CICharField(max_length=100) last_name = CICharField(max_length=100) bio = TextField(blank=True, null=True) date_joined = DateTimeField( verbose_name='date joined', auto_now_add=True) last_login = DateTimeField(verbose_name='last login', auto_now=True) is_admin = BooleanField(default=False) is_active = BooleanField(default=False) is_staff = BooleanField(default=False) is_superuser = BooleanField(default=False) photo = ImageField( upload_to='user_images', default='user_images/avatar.png') USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] objects = MyAccountManager() def __str__(self): return self.email # for permissions, to keep it simple, all admins have all permissions def has_perm(self, perm, obj=None): return self.is_admin # does this user has permission to view app, always yes for simplicity def has_module_perms(self, app_label): return True def save(self, *args, **kwargs): super(User, self).save(*args, **kwargs) # change image dimensions before saving to ensure consistent displays if self.photo: image = Image.open(self.photo) size = (1024, 683) image = image.resize(size, Image.ANTIALIAS) image.save(self.photo.path)
class CustomUser(AbstractBaseUser, PermissionsMixin): uuid = models.UUIDField(default=uuid.uuid4, editable=False) # this email field type is why this user model is # only compatible with Postgres email = CIEmailField(_('email address'), unique=True) full_name = models.CharField(max_length=250) is_staff = models.BooleanField(default=False) is_active = models.BooleanField(default=True) date_joined = models.DateTimeField(default=timezone.now) last_modified = models.DateField(auto_now=True) USERNAME_FIELD = 'email' REQUIRED_FIELDS = [ 'full_name', ] objects = CustomUserManager() def __str__(self): return self.email
class User(AbstractUser, BaseModel): email = CIEmailField(unique=True, null=False, blank=False) first_name = models.CharField(null=False, blank=False, max_length=50) last_name = models.CharField(null=False, blank=False, max_length=50) verified_email = models.BooleanField(default=False) # configs USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['first_name', 'last_name'] EMAIL_FIELD = 'email' objects = CustomUserManager() @property def full_name(self): return self.get_full_name() def __str__(self): return self.email
class EmailAddress(models.Model): class Meta: permissions = (("make_unsubscribe_links", "Can create unsubscribe links for email addresses."), ) email_address = CIEmailField(primary_key=True) created_at = models.DateTimeField(auto_now_add=True, null=True) updated_at = models.DateTimeField(auto_now=True) unsubscribe_datetime = models.DateTimeField(null=True, blank=True, default=None) complain_datetime = models.DateTimeField(null=True, blank=True, default=None) last_bounce_datetime = models.DateTimeField(null=True, blank=True, default=None) def __str__(self): return self.email_address def make_authenticated_unsubscribe_url(self): from .utils import make_authenticated_unsubscribe_url return make_authenticated_unsubscribe_url(self.email_address) @property def owner_profile(self): try: owner_proof = self.owner_proof except ObjectDoesNotExist: return None else: return owner_proof.profile
class ReceiptEmail(models.Model): """An email address to send receipts to""" organization = models.ForeignKey( verbose_name=_("organization"), to="organizations.Organization", related_name="receipt_emails", on_delete=models.CASCADE, help_text=_("The organization this receipt email corresponds to"), ) email = CIEmailField( _("email"), help_text=_("The email address to send the receipt to")) failed = models.BooleanField( _("failed"), default=False, help_text=_("Has sending to this email address failed?"), ) class Meta: unique_together = ("organization", "email") def __str__(self): return f"Receipt Email: <{self.email}>"
class User(AbstractBaseUser, PermissionsMixin): """A user of the app.""" first_name = models.CharField(_("first name"), max_length=100, blank=True) last_name = models.CharField(_("last name"), max_length=100, blank=True) email = CIEmailField( _("email"), db_index=True, max_length=254, unique=True, help_text="User's main email address", ) groups = models.ManyToManyField(Group, blank=True) is_active = models.BooleanField(_("is active"), default=True) is_staff = models.BooleanField(default=False) is_superuser = models.BooleanField(default=False) last_login = models.DateTimeField(_("last login"), default=timezone.now) date_joined = models.DateTimeField(_("date joined"), default=timezone.now) objects = UserManager() USERNAME_FIELD = "email" class Meta: verbose_name = _("user") verbose_name_plural = _("users") def __str__(self): return f"{self.first_name} {self.last_name}" def get_full_name(self): """Return the user's full name.""" return f"{self.first_name} {self.last_name}" @property def is_admin(self): return self.is_staff
class Reviewer(AbstractBaseUser, PermissionsMixin): reviewer_id = models.AutoField(primary_key=True) email = CIEmailField( 'email address', unique=True, error_messages={ 'unique': "A reviewer with that email already exists.", }, ) first_name = models.CharField(max_length=30, blank=True) last_name = models.CharField(max_length=150, blank=True) is_active = models.BooleanField( 'active', default=True, help_text='Designates whether this reviewer should be treated as ' 'active. Unselect this instead of deleting accounts.' ) date_joined = models.DateTimeField(default=timezone.now) # FIXME: In 2018, we used background to describe interviewers' experience # FIXME: with / connection to DSSG, (included in interview email). # FIXME: If we intend to use this field to describe the reviewer's # FIXME: background at all, (and e.g. to match reviewers with applications), # FIXME: then we should provision a new field and migrate # FIXME: currently-populated background values to it, e.g.: # FIXME: program_experience = CharField(max_length=250, blank=True) background = models.CharField(max_length=100, blank=True, choices=( ('soc-sci', 'Social Science'), ('comp-sci', 'Computer Science'), ('math-stat', 'Math/Statistics'), )) class Meta: db_table = 'reviewer' ordering = ('email',) objects = ReviewerManager() USERNAME_FIELD = EMAIL_FIELD = 'email' def clean(self): super().clean() self.email = self.__class__.objects.normalize_email(self.email) def get_full_name(self): """ Return the first_name plus the last_name, with a space in between. """ full_name = '%s %s' % (self.first_name, self.last_name) return full_name.strip() def get_short_name(self): """Return the short name for the user.""" return self.first_name def email_user(self, subject, message, from_email=None, **kwargs): """Send an email to this user.""" send_mail(subject, message, from_email, [self.email], **kwargs) # For compatibility with Django Admin site @property def is_staff(self): return self.trusted @cachedproperty def concession(self): try: return ReviewerConcession.objects.get( reviewer=self, program_year=settings.REVIEW_PROGRAM_YEAR, ) except ReviewerConcession.DoesNotExist: return None
class AnimeSukiUser(AbstractBaseUser, PermissionsMixin): """ AnimeSuki uses a custom user model for several reasons: 1) There is no need for "first_name" and "last_name" 2) Switching to a custom user model later is difficult 3) Username isn't case insensitive by default ("ADMIN" and "admin" can be two different users) 4) Email address isn't mandatory nor unique or case insensitive by default The code below is copied from the Django source code for "AbstractUser" and then modified. """ username_validator = UnicodeUsernameValidator() username = CICharField( _('username'), max_length=150, unique=True, help_text= _('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.' ), validators=[username_validator], error_messages={ 'unique': _("A user with that username already exists."), }, ) slug = models.SlugField(max_length=150, unique=True, allow_unicode=True) email = CIEmailField(_('email address'), unique=True) is_staff = models.BooleanField( _('staff status'), default=False, help_text=_( 'Designates whether the user can log into this admin site.'), ) is_active = models.BooleanField( _('active'), default=True, help_text=_( 'Designates whether this user should be treated as active. ' 'Unselect this instead of deleting accounts.'), ) date_joined = models.DateTimeField(_('date joined'), default=timezone.now) objects = UserManager() EMAIL_FIELD = 'email' USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['email'] class Meta: db_table = 'core_user' verbose_name = _('user') verbose_name_plural = _('users') def clean(self): super().clean() self.email = self.__class__.objects.normalize_email(self.email) def save(self, *args, **kwargs): # Set slug if empty if not self.slug: self.slug = slug = slugify(self.username) # Find unique slug i = 1 while AnimeSukiUser.objects.filter(slug=self.slug).exists(): self.slug = f'{slug}{i}' i += 1 super().save(*args, **kwargs) def get_full_name(self): return self.username def get_short_name(self): return self.username def email_user(self, subject, message, from_email=None, **kwargs): """Send an email to this user.""" send_mail(subject, message, from_email, [self.email], **kwargs) def get_gravatar_url(self, size=80, default='identicon'): url = 'https://www.gravatar.com/avatar/' + md5( self.email.lower().encode('utf-8')).hexdigest() # nosec url += '?' + urlencode({'d': default, 's': str(size)}) return url