models: add User.email_verified_date field (#19634)
This commit is contained in:
parent
34d4b476b1
commit
342ed7f2b9
|
@ -463,7 +463,7 @@ class BaseUserSerializer(serializers.ModelSerializer):
|
|||
if 'ou' in validated_data:
|
||||
self.check_perm('custom_user.change_user', validated_data.get('ou'))
|
||||
if validated_data.get('email') != instance.email and not validated_data.get('email_verified'):
|
||||
instance.email_verified = False
|
||||
instance.set_email_verified(False)
|
||||
super().update(instance, validated_data)
|
||||
for key, value in attributes.items():
|
||||
if is_verified.get(key):
|
||||
|
@ -863,7 +863,7 @@ class UsersAPI(api_mixins.GetOrCreateMixinView, HookMixin, ExceptionHandlerMixin
|
|||
if not serializer.is_valid():
|
||||
response = {'result': 0, 'errors': serializer.errors}
|
||||
return Response(response, status.HTTP_400_BAD_REQUEST)
|
||||
user.email_verified = False
|
||||
user.set_email_verified(False)
|
||||
user.save()
|
||||
utils_misc.send_email_change_email(user, serializer.validated_data['email'], request=request)
|
||||
return Response({'result': 1})
|
||||
|
|
|
@ -710,7 +710,7 @@ class UserCsvImporter:
|
|||
if getattr(user, cell.header.name) != cell.value:
|
||||
setattr(user, cell.header.name, cell.value)
|
||||
if cell.header.name == 'email' and cell.header.verified:
|
||||
user.email_verified = True
|
||||
user.set_email_verified(True)
|
||||
cell.action = 'updated'
|
||||
continue
|
||||
cell.action = 'nothing'
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# Generated by Django 2.2.23 on 2022-01-27 08:03
|
||||
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def set_email_verified_date(apps, schema_editor):
|
||||
User = apps.get_model('custom_user', 'User')
|
||||
qs = User.objects.filter(email_verified=True, email_verified_date__isnull=True)
|
||||
# set all unknown dates to date joined
|
||||
qs.update(email_verified_date=models.F('date_joined'))
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('custom_user', '0027_user_deactivation_reason'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='email_verified_date',
|
||||
field=models.DateTimeField(
|
||||
default=None, blank=True, null=True, verbose_name='email verified date'
|
||||
),
|
||||
),
|
||||
migrations.RunPython(set_email_verified_date, migrations.RunPython.noop),
|
||||
]
|
|
@ -150,6 +150,9 @@ class User(AbstractBaseUser, PermissionMixin):
|
|||
last_name = models.CharField(_('last name'), max_length=128, blank=True)
|
||||
email = models.EmailField(_('email address'), blank=True, max_length=254, validators=[email_validator])
|
||||
email_verified = models.BooleanField(default=False, verbose_name=_('email verified'))
|
||||
email_verified_date = models.DateTimeField(
|
||||
default=None, blank=True, null=True, verbose_name=_('email verified date')
|
||||
)
|
||||
is_staff = models.BooleanField(
|
||||
_('staff status'),
|
||||
default=False,
|
||||
|
@ -428,6 +431,17 @@ class User(AbstractBaseUser, PermissionMixin):
|
|||
def get_absolute_url(self):
|
||||
return reverse('a2-manager-user-detail', kwargs={'pk': self.pk})
|
||||
|
||||
def set_email_verified(self, value):
|
||||
if isinstance(value, datetime.datetime):
|
||||
self.email_verified = True
|
||||
self.email_verified_date = value
|
||||
elif bool(value):
|
||||
self.email_verified = True
|
||||
self.email_verified_date = timezone.now()
|
||||
else:
|
||||
self.email_verified = False
|
||||
self.email_verified_date = None
|
||||
|
||||
|
||||
class DeletedUser(models.Model):
|
||||
deleted = models.DateTimeField(verbose_name=_('Deletion date'), auto_now_add=True)
|
||||
|
|
|
@ -138,7 +138,7 @@ class RegistrationCompletionFormNoPassword(profile_forms.BaseUserForm):
|
|||
return BaseUserManager.normalize_email(email)
|
||||
|
||||
def save(self, commit=True):
|
||||
self.instance.email_verified = True
|
||||
self.instance.set_email_verified(True)
|
||||
self.instance.is_active = True
|
||||
user = super().save(commit=commit)
|
||||
if commit and app_settings.A2_REGISTRATION_GROUPS:
|
||||
|
|
|
@ -485,7 +485,7 @@ class UserEditView(OtherActionsMixin, ActionMixin, BaseEditView):
|
|||
|
||||
def form_valid(self, form):
|
||||
if 'email' in form.changed_data:
|
||||
self.object.email_verified = False
|
||||
self.object.set_email_verified(False)
|
||||
self.object.save()
|
||||
response = super().form_valid(form)
|
||||
if form.has_changed():
|
||||
|
|
|
@ -246,7 +246,7 @@ class EmailChangeVerifyView(TemplateView):
|
|||
raise ValidationError(_('This email is already used by another account.'))
|
||||
old_email = user.email
|
||||
user.email = email
|
||||
user.email_verified = True
|
||||
user.set_email_verified(True)
|
||||
user.save()
|
||||
messages.info(
|
||||
request, _('your request for changing your email for {0} is successful').format(email)
|
||||
|
@ -873,7 +873,7 @@ class PasswordResetConfirmView(cbv.RedirectToNextURLViewMixin, FormView):
|
|||
|
||||
def form_valid(self, form):
|
||||
# Changing password by mail validate the email
|
||||
form.user.email_verified = True
|
||||
form.user.set_email_verified(True)
|
||||
form.save()
|
||||
hooks.call_hooks('event', name='password-reset-confirm', user=form.user, token=self.token, form=form)
|
||||
logger.info('password reset for user %s with token %r', self.user, self.token.uuid)
|
||||
|
|
|
@ -310,8 +310,8 @@ class OIDCBackend(ModelBackend):
|
|||
if getattr(user, attribute) != value:
|
||||
logger.info('auth_oidc: set user %s attribute %s to value %s', user, attribute, value)
|
||||
setattr(user, attribute, value)
|
||||
if attribute == 'email' and verified:
|
||||
user.email_verified = True
|
||||
if attribute == 'email':
|
||||
user.set_email_verified(verified)
|
||||
save_user = True
|
||||
|
||||
if user.ou != user_ou:
|
||||
|
|
|
@ -70,6 +70,7 @@ class SerializerTests(TestCase):
|
|||
'fields': {
|
||||
'uuid': u.uuid,
|
||||
'email_verified': False,
|
||||
'email_verified_date': None,
|
||||
'username': 'john.doe',
|
||||
'email': '',
|
||||
'first_name': '',
|
||||
|
@ -123,7 +124,7 @@ class SerializerTests(TestCase):
|
|||
expected = json.loads(json.dumps(expected, cls=DjangoJSONEncoder))
|
||||
for obj in serializers.deserialize('json', result):
|
||||
obj.save()
|
||||
self.assertEqual(json.loads(result), expected)
|
||||
assert json.loads(result) == expected
|
||||
self.assertEqual(User.objects.count(), ucount + 1)
|
||||
self.assertEqual(Attribute.objects.count(), acount + 1)
|
||||
# first_name and last_name attribute value not recreated since they were not dumped
|
||||
|
|
|
@ -64,6 +64,7 @@ USER_ATTRIBUTES_SET = {
|
|||
'is_active',
|
||||
'modified',
|
||||
'email_verified',
|
||||
'email_verified_date',
|
||||
'last_account_deletion_alert',
|
||||
'deactivation',
|
||||
'deactivation_reason',
|
||||
|
@ -231,7 +232,7 @@ def test_api_member_users_list(app, user, simple_role):
|
|||
|
||||
|
||||
def test_api_users_update_with_email_verified(settings, app, admin, simple_user):
|
||||
simple_user.email_verified = True
|
||||
simple_user.set_email_verified(True)
|
||||
simple_user.save()
|
||||
|
||||
payload = {
|
||||
|
@ -249,7 +250,7 @@ def test_api_users_update_with_email_verified(settings, app, admin, simple_user)
|
|||
assert resp.json['email_verified']
|
||||
assert_event('manager.user.profile.edit', user=admin, api=True)
|
||||
|
||||
user.email_verified = True
|
||||
user.set_email_verified(True)
|
||||
user.email = 'johnny.doeny@foo.bar'
|
||||
user.save()
|
||||
|
||||
|
@ -260,7 +261,7 @@ def test_api_users_update_with_email_verified(settings, app, admin, simple_user)
|
|||
|
||||
|
||||
def test_api_users_update_without_email_verified(settings, app, admin, simple_user):
|
||||
simple_user.email_verified = True
|
||||
simple_user.set_email_verified(True)
|
||||
simple_user.save()
|
||||
|
||||
payload = {
|
||||
|
@ -276,7 +277,7 @@ def test_api_users_update_without_email_verified(settings, app, admin, simple_us
|
|||
assert not user.email_verified
|
||||
assert not resp.json['email_verified']
|
||||
|
||||
user.email_verified = True
|
||||
user.set_email_verified(True)
|
||||
user.email = 'johnny.doeny@foo.bar'
|
||||
user.save()
|
||||
|
||||
|
@ -336,7 +337,7 @@ def test_api_users_create_without_email_verified(settings, app, admin):
|
|||
|
||||
|
||||
def test_api_email_unset_verification(settings, app, admin, simple_user):
|
||||
simple_user.email_verified = True
|
||||
simple_user.set_email_verified(True)
|
||||
simple_user.save()
|
||||
|
||||
payload = {
|
||||
|
|
|
@ -46,3 +46,15 @@ def test_migration_custom_user_0026_remove_user_deleted(transactional_db, migrat
|
|||
DeletedUser = new_apps.get_model('custom_user', 'DeletedUser')
|
||||
assert User.objects.count() == 1
|
||||
assert DeletedUser.objects.count() == 1
|
||||
|
||||
|
||||
def test_migration_custom_user_0028_user_email_verified_date(transactional_db, migration):
|
||||
old_apps = migration.before([('custom_user', '0027_user_deactivation_reason')])
|
||||
|
||||
User = old_apps.get_model('custom_user', 'User')
|
||||
User.objects.create(email='john.doe@example.com', email_verified=True)
|
||||
|
||||
new_apps = migration.apply([('custom_user', '0028_user_email_verified_date')])
|
||||
User = new_apps.get_model('custom_user', 'User')
|
||||
user = User.objects.get()
|
||||
assert user.email_verified_date == user.date_joined
|
||||
|
|
|
@ -918,7 +918,7 @@ def test_ou_hide_username(admin, app, db):
|
|||
|
||||
|
||||
def test_manager_edit_user_email_verified(app, simple_user, superuser_or_admin):
|
||||
simple_user.email_verified = True
|
||||
simple_user.set_email_verified(True)
|
||||
simple_user.save()
|
||||
|
||||
url = '/manage/users/%s/edit/' % simple_user.pk
|
||||
|
@ -959,7 +959,7 @@ def test_manager_email_verified_column_user(app, simple_user, superuser_or_admin
|
|||
resp = app.get('/manage/users/')
|
||||
assert not resp.html.find('span', {'class': 'verified'})
|
||||
|
||||
simple_user.email_verified = True
|
||||
simple_user.set_email_verified(True)
|
||||
simple_user.save()
|
||||
resp = app.get('/manage/users/')
|
||||
assert resp.html.find('span', {'class': 'verified'}).text == simple_user.email
|
||||
|
|
Loading…
Reference in New Issue