accounts: fix deletion message on missing phone (#82739) #162

Merged
pmarillonnet merged 2 commits from wip/82739-account-deletion-no-phone-yet-validated into main 2023-11-16 09:38:46 +01:00
5 changed files with 65 additions and 3 deletions

View File

@ -45,7 +45,14 @@ from authentic2.apps.journal.views import JournalViewWithContext
from authentic2.backends.ldap_backend import LDAPBackend
from authentic2.models import Attribute, PasswordReset
from authentic2.utils import hooks, spooler, switch_user
from authentic2.utils.misc import is_ajax, make_url, redirect, select_next_url, send_password_reset_mail
from authentic2.utils.misc import (
get_password_authenticator,
is_ajax,
make_url,
redirect,
select_next_url,
send_password_reset_mail,
)
from authentic2_idp_oidc.models import OIDCAuthorization, OIDCClient
from . import app_settings
@ -517,8 +524,18 @@ class UserEditView(OtherActionsMixin, ActionMixin, BaseEditView):
return self._get_next_url()
def form_valid(self, form):
changed = False
if 'email' in form.changed_data:
self.object.set_email_verified(False)
changed = True
authenticator = get_password_authenticator()
if (
authenticator.phone_identifier_field
and authenticator.phone_identifier_field.name in form.changed_data
):
self.object.phone_verified_on = None
changed = True
if changed:
self.object.save()
response = super().form_valid(form)
if form.has_changed():

View File

@ -20,14 +20,14 @@
Do you really want to delete your account?
{% endblocktrans %}
</p>
{% if user.email_verified %}
{% if email and user.email_verified %}
<p>
{% blocktrans trimmed %}
A validation message will be sent to {{ email }}. You will have to visit the
link in this email in order to complete the deletion process.
{% endblocktrans %}
</p>
{% elif user.phone_verified_on %}
{% elif is_phone_authn_active and phone and user.phone_verified_on %}
<p>
{% blocktrans trimmed %}
A validation code will be sent to {{ phone }}. You will have to type in the

View File

@ -2107,6 +2107,7 @@ class AccountDeleteView(HomeURLMixin, RecentAuthenticationMixin, TemplateView):
ctx = super().get_context_data(**kwargs)
ctx['email'] = self.request.user.email
ctx['phone'] = self.request.user.phone_identifier
ctx['is_phone_authn_active'] = self.authenticator.is_phone_authn_active
return ctx

View File

@ -25,6 +25,7 @@ import pytest
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.urls import reverse
from django.utils.timezone import now
from webtest import Upload
from authentic2.a2_rbac.models import VIEW_OP
@ -1090,6 +1091,31 @@ def test_manager_user_disabled_user(app, superuser, simple_user):
assert resp.pyquery('h2 .disabled-badge')
def test_manager_user_edit_reset_phone(app, superuser, simple_user, phone_activated_authn):
simple_user.attributes.phone = '+33122334455'
simple_user.phone_verified_on = now()
simple_user.save()
login(app, superuser, '/manage/')
resp = app.get(reverse('a2-manager-user-edit', kwargs={'pk': simple_user.id}))
resp.form.set('phone_1', '111221122')
resp.form.submit()
simple_user.refresh_from_db()
assert simple_user.phone_identifier == '+33111221122'
assert not simple_user.phone_verified_on
simple_user.phone_verified_on = now()
simple_user.save()
resp = app.get(reverse('a2-manager-user-edit', kwargs={'pk': simple_user.id}))
resp.form.set('phone_1', '')
resp.form.submit()
simple_user.refresh_from_db()
assert not simple_user.phone_identifier
assert not simple_user.phone_verified_on
def test_manager_user_username_field(app, superuser, simple_user):
login(app, superuser, '/manage/')

View File

@ -402,6 +402,24 @@ def test_delete_account_phone_identifier_deactivated_user(app, nomail_user, sett
User.objects.get(id=nomail_user_id)
def test_delete_account_phone_verified_yet_missing(app, nomail_user, settings, phone_activated_authn):
settings.SMS_URL = 'https://foo.whatever.none/'
nomail_user.attributes.phone = '+33122446666'
nomail_user.phone_verified_on = now()
nomail_user.save()
login(
app, nomail_user, login=nomail_user.attributes.phone, path='/accounts/', password=nomail_user.username
)
# some improper use, e.g. in backoffice where phones can be arbitrarily erased
nomail_user.attributes.phone = ''
nomail_user.save()
resp = app.get('/accounts/delete/')
assert resp.pyquery('form p')[-1].text.strip() == 'Do you really want to delete your account?'
assert 'validation code' not in resp.form.html
assert '+33122446666' not in resp.html
def test_delete_account_verified_email_precedence_over_verified_phone(
app, simple_user, settings, phone_activated_authn
):