From 66831e6ebf0f24d40201f2cb11399efdab4a5f27 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 19 May 2020 17:28:40 +0200 Subject: [PATCH 3/5] misc: let User model validate identifiers and uniqueness (#43074) --- src/authentic2/custom_user/models.py | 27 +++++++++++++++-------- src/authentic2/manager/forms.py | 32 ---------------------------- 2 files changed, 18 insertions(+), 41 deletions(-) diff --git a/src/authentic2/custom_user/models.py b/src/authentic2/custom_user/models.py index 3853b518..41163455 100644 --- a/src/authentic2/custom_user/models.py +++ b/src/authentic2/custom_user/models.py @@ -245,7 +245,11 @@ class User(AbstractBaseUser, PermissionMixin): return '' % six.text_type(self) def clean(self): - pass + if (not self.username + and not self.email + and not (self.first_name + or self.last_name)): + raise ValidationError(_('An account needs at least one identifier.')) def validate_unique(self, exclude=None): errors = {} @@ -259,15 +263,15 @@ class User(AbstractBaseUser, PermissionMixin): qs = model.objects if self.pk: qs = qs.exclude(pk=self.pk) - if self.ou_id: - qs = qs.filter(ou_id=self.ou_id) - else: - qs = qs.filter(ou__isnull=True) - if 'username' not in exclude and self.username and app_settings.A2_USERNAME_IS_UNIQUE: + if 'username' not in exclude and self.username and (app_settings.A2_USERNAME_IS_UNIQUE + or (self.ou and self.ou.username_is_unique)): + username_qs = qs + if not app_settings.A2_USERNAME_IS_UNIQUE: + username_qs = qs.filter(ou=self.ou) try: try: - qs.get(username=self.username) + username_qs.get(username=self.username) except MultipleObjectsReturned: pass except model.DoesNotExist: @@ -275,10 +279,15 @@ class User(AbstractBaseUser, PermissionMixin): else: errors.setdefault('username', []).append( _('This username is already in use. Please supply a different username.')) - if 'email' not in exclude and self.email and app_settings.A2_EMAIL_IS_UNIQUE: + + if 'email' not in exclude and self.email and (app_settings.A2_EMAIL_IS_UNIQUE + or (self.ou and self.ou.email_is_unique)): + email_qs = qs + if not app_settings.A2_EMAIL_IS_UNIQUE: + email_qs = email_qs.filter(ou=self.ou) try: try: - qs.get(email__iexact=self.email) + email_qs.get(email__iexact=self.email) except MultipleObjectsReturned: pass except model.DoesNotExist: diff --git a/src/authentic2/manager/forms.py b/src/authentic2/manager/forms.py index 7d5a0fa7..10eba0f2 100644 --- a/src/authentic2/manager/forms.py +++ b/src/authentic2/manager/forms.py @@ -201,38 +201,6 @@ class UserEditForm(LimitQuerysetFormMixin, CssClass, BaseUserForm): self.data[self.add_prefix('ou')] = qs[0].pk self.data._mutable = False - def clean(self): - if (self.instance.has_usable_password() - and ('username' in self.fields - or 'email' in self.fields)): - if not self.cleaned_data.get('username') and \ - not self.cleaned_data.get('email'): - raise forms.ValidationError( - _('You must set a username or an email.')) - - if self.cleaned_data.get('email'): - qs = User.objects.all() - ou = getattr(self, 'ou', None) - - if self.instance and self.instance.pk: - qs = qs.exclude(pk=self.instance.pk) - ou = self.instance.ou - - email = self.cleaned_data['email'] - already_used = False - - if a2_app_settings.A2_EMAIL_IS_UNIQUE and qs.filter(email=email).exists(): - already_used = True - - if ou and ou.email_is_unique and qs.filter(ou=ou, email=email).exists(): - already_used = True - - if already_used: - raise forms.ValidationError({ - 'email': _('Email already used.') - }) - return super(UserEditForm, self).clean() - class Meta: model = User exclude = ('is_staff', 'groups', 'user_permissions', 'last_login', -- 2.26.2