Projet

Général

Profil

0001-Allow-users-to-provide-their-email-or-username-for-p.patch

Benjamin Renard, 04 décembre 2020 13:54

Télécharger (27,9 ko)

Voir les différences:

Subject: [PATCH] Allow users to provide their email or username for password
 reset process

 src/authentic2/forms/passwords.py             |  13 ++-
 src/authentic2/journal_event_types.py         |   8 +-
 .../locale/fr/LC_MESSAGES/django.po           | 109 ++++++++++--------
 .../password_reset_instructions.html          |   5 +-
 src/authentic2/utils/__init__.py              |   4 +-
 src/authentic2/views.py                       |  25 ++--
 tests/auth_fc/test_auth_fc.py                 |   4 +-
 tests/test_ldap.py                            |   2 +-
 tests/test_password_reset.py                  |  36 +++++-
 tests/test_views.py                           |  24 ++--
 10 files changed, 138 insertions(+), 92 deletions(-)
src/authentic2/forms/passwords.py
19 19

  
20 20
from django.contrib.auth import forms as auth_forms
21 21
from django.core.exceptions import ValidationError
22
from django.db.models import Q
22 23
from django.forms import Form
23 24
from django import forms
24 25
from django.utils.translation import ugettext_lazy as _
......
35 36
class PasswordResetForm(forms.Form):
36 37
    next_url = forms.CharField(widget=forms.HiddenInput, required=False)
37 38

  
38
    email = ValidatedEmailField(
39
        label=_("Email"), max_length=254)
39
    email_or_username = forms.CharField(
40
        label=_("Email or username"), max_length=254)
40 41

  
41 42
    def save(self):
42 43
        """
43 44
        Generates a one-use only link for resetting password and sends to the
44 45
        user.
45 46
        """
46
        email = self.cleaned_data["email"].strip()
47
        email_or_username = self.cleaned_data["email_or_username"].strip()
47 48
        users = get_user_queryset()
48
        active_users = users.filter(email__iexact=email, is_active=True)
49
        active_users = users.filter(Q(email__iexact=email_or_username) | Q(username__iexact=email_or_username), is_active=True)
49 50
        for user in active_users:
50 51
            # we don't set the password to a random string, as some users should not have
51 52
            # a password
......
56 57
                set_random_password=set_random_password,
57 58
                next_url=self.cleaned_data.get('next_url'))
58 59
        if not active_users:
59
            logger.info(u'password reset request for "%s", no user found', email)
60
        hooks.call_hooks('event', name='password-reset', email=email, users=active_users)
60
            logger.info(u'password reset request for "%s", no user found', email_or_username)
61
        hooks.call_hooks('event', name='password-reset', email_or_username=email_or_username, users=active_users)
61 62

  
62 63

  
63 64
class PasswordResetMixin(Form):
src/authentic2/journal_event_types.py
172 172
    label = _('password reset failure')
173 173

  
174 174
    @classmethod
175
    def record(cls, email):
176
        super().record(data={'email': email})
175
    def record(cls, email_or_username):
176
        super().record(data={'email_or_username': email_or_username})
177 177

  
178 178
    @classmethod
179 179
    def get_message(cls, event, context):
180
        email = event.get_data('email')
180
        email_or_username = event.get_data('email_or_username')
181 181
        if email:
182
            return _('password reset failure with email "%s"') % email
182
            return _('password reset failure with email (or username) "%s"') % email_or_username
183 183
        return super().get_message(event, context)
184 184

  
185 185

  
src/authentic2/locale/fr/LC_MESSAGES/django.po
7 7
msgstr ""
8 8
"Project-Id-Version: Authentic\n"
9 9
"Report-Msgid-Bugs-To: \n"
10
"POT-Creation-Date: 2020-11-23 10:34+0100\n"
10
"POT-Creation-Date: 2020-12-04 13:46+0100\n"
11 11
"PO-Revision-Date: 2020-10-13 11:25+0200\n"
12 12
"Last-Translator: Mikaël Ates <mates@entrouvert.com>\n"
13 13
"Language-Team: None\n"
......
17 17
"Content-Transfer-Encoding: 8bit\n"
18 18
"Plural-Forms: nplurals=2; plural=n>1;\n"
19 19

  
20
#: debian/multitenant/debian_config.py:40 src/authentic2/forms/passwords.py:39
20
#: debian/multitenant/debian_config.py:40
21 21
#: src/authentic2/forms/registration.py:40 src/authentic2/manager/forms.py:644
22 22
#: src/authentic2/manager/templates/authentic2/manager/user_create_registration_email_body.txt:4
23 23
#: src/authentic2/saml/models.py:134
......
1148 1148
msgid "The image is not valid"
1149 1149
msgstr "L’image n’est pas valide"
1150 1150

  
1151
#: src/authentic2/forms/passwords.py:95 src/authentic2/forms/passwords.py:108
1151
#: src/authentic2/forms/passwords.py:40
1152
msgid "Email or username"
1153
msgstr "Courriel ou nom d'utilisateur"
1154

  
1155
#: src/authentic2/forms/passwords.py:96 src/authentic2/forms/passwords.py:109
1152 1156
msgid "New password"
1153 1157
msgstr "Nouveau mot de passe"
1154 1158

  
1155
#: src/authentic2/forms/passwords.py:96 src/authentic2/forms/passwords.py:109
1159
#: src/authentic2/forms/passwords.py:97 src/authentic2/forms/passwords.py:110
1156 1160
msgid "New password confirmation"
1157 1161
msgstr "Confirmation du nouveau mot de passe"
1158 1162

  
1159
#: src/authentic2/forms/passwords.py:101 src/authentic2/forms/passwords.py:115
1163
#: src/authentic2/forms/passwords.py:102 src/authentic2/forms/passwords.py:116
1160 1164
msgid "New password must differ from old password"
1161 1165
msgstr "Le nouveau mot de passe doit être différent de l’ancien."
1162 1166

  
1163
#: src/authentic2/forms/passwords.py:107
1167
#: src/authentic2/forms/passwords.py:108
1164 1168
msgid "Old password"
1165 1169
msgstr "Ancien mot de passe"
1166 1170

  
......
1406 1410

  
1407 1411
#: src/authentic2/journal_event_types.py:182
1408 1412
#, python-format
1409
msgid "password reset failure with email \"%s\""
1413
msgid "password reset failure with email (or username) \"%s\""
1410 1414
msgstr ""
1411
"échec de réinitialisation du mot de passe pour l’adresse de courriel « %s »"
1415
"échec de réinitialisation du mot de passe pour l’adresse de courriel (ou le "
1416
"nom d'utilisateur) « %s »"
1412 1417

  
1413 1418
#: src/authentic2/journal_event_types.py:188
1414 1419
msgid "password change"
......
4651 4656
msgstr "Déconnecté"
4652 4657

  
4653 4658
#: src/authentic2/templates/registration/password_change_done.html:9
4654
#: src/authentic2/views.py:1302
4659
#: src/authentic2/views.py:1303
4655 4660
msgid "Password changed"
4656 4661
msgstr "Mot de passe modifié"
4657 4662

  
......
4692 4697
msgstr "Instructions de réinitialisation du mot de passe"
4693 4698

  
4694 4699
#: src/authentic2/templates/registration/password_reset_instructions.html:10
4695
#, python-format
4696 4700
msgid ""
4697 4701
"\n"
4698
"    If your email address exists in our database, an email has been sent to "
4699
"%(email)s.\n"
4702
"    If a user account exists in our database with your email address (or "
4703
"your\n"
4704
"    username), an email has been sent to you.\n"
4700 4705
"    "
4701 4706
msgstr ""
4702 4707
"\n"
4703
"    Si votre adresse électronique est présente dans notre base, un courriel "
4704
"a été envoyé à %(email)s.\n"
4708
"    Si un compte utilisateur est présent dans notre base avec votre adresse "
4709
"électronique (ou votre nom d'utilisateur), un courriel vous a été envoyé.\n"
4705 4710
"    "
4706 4711

  
4707
#: src/authentic2/templates/registration/password_reset_instructions.html:15
4712
#: src/authentic2/templates/registration/password_reset_instructions.html:16
4708 4713
msgid ""
4709 4714
"\n"
4710 4715
"    Follow the instructions in this email in order to choose a new "
......
4716 4721
"de passe.\n"
4717 4722
"    "
4718 4723

  
4719
#: src/authentic2/templates/registration/password_reset_instructions.html:21
4724
#: src/authentic2/templates/registration/password_reset_instructions.html:22
4720 4725
#: src/authentic2/templates/registration/registration_complete.html:23
4721 4726
msgid ""
4722 4727
"\n"
......
4729 4734
"    également être considéré comme un pourriel (spam) : n’oubliez pas\n"
4730 4735
"    de regarder dans votre dossier « courriers indésirables ».        "
4731 4736

  
4732
#: src/authentic2/templates/registration/password_reset_instructions.html:27
4737
#: src/authentic2/templates/registration/password_reset_instructions.html:28
4733 4738
#, python-format
4734 4739
msgid ""
4735 4740
"\n"
......
4746 4751
"    puis recommencez la procédure de réinitialisation du mot de passe.\n"
4747 4752
"    "
4748 4753

  
4749
#: src/authentic2/templates/registration/password_reset_instructions.html:35
4754
#: src/authentic2/templates/registration/password_reset_instructions.html:36
4750 4755
msgid "Back to login"
4751 4756
msgstr "Retour à la page de connexion"
4752 4757

  
......
4805 4810
#: src/authentic2/templates/registration/registration_completion_choose.html:5
4806 4811
#: src/authentic2/templates/registration/registration_completion_form.html:5
4807 4812
#: src/authentic2/templates/registration/registration_completion_form.html:10
4808
#: src/authentic2/views.py:800
4813
#: src/authentic2/views.py:801
4809 4814
msgid "Registration"
4810 4815
msgstr "Création d’un compte"
4811 4816

  
......
5000 5005
"Cette page est périmée car vous vous êtes connecté entretemps; nous l’avons "
5001 5006
"rechargée pour vous."
5002 5007

  
5003
#: src/authentic2/views.py:645 src/authentic2/views.py:730
5008
#: src/authentic2/views.py:645 src/authentic2/views.py:731
5004 5009
msgid "Password Reset"
5005 5010
msgstr "Réinitialisation du mot de passe"
5006 5011

  
5007
#: src/authentic2/views.py:681 src/authentic2/views.py:834
5008
#, python-format
5012
#: src/authentic2/views.py:682
5009 5013
msgid ""
5010
"An email has already been sent to %s. Click \"Validate\" again if you really "
5011
"want it to be sent again."
5014
"An email has already been sent to your address. Click \"Validate\" again if "
5015
"you really want it to be sent again."
5012 5016
msgstr ""
5013
"Un courriel a déjà été envoyé à %s. Cliquez sur « Valider » si vous voulez "
5014
"vraiment qu’il soit réenvoyé."
5017
"Un courriel a déjà été envoyé à votre adresse. Cliquez sur « Valider » si "
5018
"vous voulez vraiment qu’il soit réenvoyé."
5015 5019

  
5016
#: src/authentic2/views.py:692 src/authentic2/views.py:844
5020
#: src/authentic2/views.py:693 src/authentic2/views.py:845
5017 5021
msgid ""
5018 5022
"Multiple emails have already been sent to this address. Further attempts are "
5019 5023
"blocked, please check your spam folder or try again later."
......
5022 5026
"envois sont bloqués, vous devriez vérifier votre dossier d’indésirables "
5023 5027
"(spams, pourriels) ou réessayer plus tard."
5024 5028

  
5025
#: src/authentic2/views.py:701
5029
#: src/authentic2/views.py:702
5026 5030
msgid ""
5027 5031
"Multiple password reset attempts have already been made from this IP "
5028 5032
"address. No further email will be sent, please check your spam folder or try "
......
5033 5037
"devriez vérifier votre dossier d’indésirables (spams, pourriels) ou "
5034 5038
"réessayer plus tard."
5035 5039

  
5036
#: src/authentic2/views.py:743
5040
#: src/authentic2/views.py:744
5037 5041
msgid "Password reset token is unknown or expired"
5038 5042
msgstr "Le jeton de réinitialisation de mot de passe est inconnu ou expiré"
5039 5043

  
5040
#: src/authentic2/views.py:746
5044
#: src/authentic2/views.py:747
5041 5045
msgid "Password reset token is invalid"
5042 5046
msgstr "Le jeton de réinitialisation de mot de passe est invalide"
5043 5047

  
5044
#: src/authentic2/views.py:754
5048
#: src/authentic2/views.py:755
5045 5049
msgid "User not found"
5046 5050
msgstr "Utilisateur introuvable"
5047 5051

  
5048
#: src/authentic2/views.py:763
5052
#: src/authentic2/views.py:764
5049 5053
msgid ""
5050 5054
"It's not possible to reset your password. Please contact an administrator."
5051 5055
msgstr ""
5052 5056
"Votre mot de passe n’a pas pu être réinitialisé. Veuillez contacter votre "
5053 5057
"administrateur."
5054 5058

  
5055
#: src/authentic2/views.py:770
5059
#: src/authentic2/views.py:771
5056 5060
msgid "Enter new password"
5057 5061
msgstr "Entrez un nouveau mot de passe"
5058 5062

  
5059
#: src/authentic2/views.py:852
5063
#: src/authentic2/views.py:835
5064
#, python-format
5065
msgid ""
5066
"An email has already been sent to %s. Click \"Validate\" again if you really "
5067
"want it to be sent again."
5068
msgstr ""
5069
"Un courriel a déjà été envoyé à %s. Cliquez sur « Valider » si vous voulez "
5070
"vraiment qu’il soit réenvoyé."
5071

  
5072
#: src/authentic2/views.py:853
5060 5073
msgid ""
5061 5074
"Multiple registration attempts have already been made from this IP address. "
5062 5075
"No further email will be sent, please check your spam folder or try again "
......
5067 5080
"vérifier votre dossier d’indésirables (spams, pourriels) ou réessayer plus "
5068 5081
"tard."
5069 5082

  
5070
#: src/authentic2/views.py:921
5083
#: src/authentic2/views.py:922
5071 5084
msgid "Your activation key is unknown or expired"
5072 5085
msgstr "Votre clé d’activation est inconnue ou a expiré"
5073 5086

  
5074
#: src/authentic2/views.py:924
5087
#: src/authentic2/views.py:925
5075 5088
msgid "Activation failed"
5076 5089
msgstr "Échec à l’activation du compte"
5077 5090

  
5078
#: src/authentic2/views.py:1186
5091
#: src/authentic2/views.py:1187
5079 5092
msgid "Request account deletion"
5080 5093
msgstr "Demande de suppression de compte"
5081 5094

  
5082
#: src/authentic2/views.py:1198
5095
#: src/authentic2/views.py:1199
5083 5096
msgid ""
5084 5097
"An account deletion validation email has been sent to your email address."
5085 5098
msgstr ""
5086 5099
"Un message pour valider la suppression du compte a été envoyé à votre "
5087 5100
"adresse électronique."
5088 5101

  
5089
#: src/authentic2/views.py:1209
5102
#: src/authentic2/views.py:1210
5090 5103
msgid "Confirm account deletion"
5091 5104
msgstr "Confirmation de la suppression du compte"
5092 5105

  
5093
#: src/authentic2/views.py:1221 src/authentic2/views.py:1235
5106
#: src/authentic2/views.py:1222 src/authentic2/views.py:1236
5094 5107
msgid "This account has previously been deleted."
5095 5108
msgstr "Ce compte a déjà été supprimé."
5096 5109

  
5097
#: src/authentic2/views.py:1224
5110
#: src/authentic2/views.py:1225
5098 5111
msgid "This account is inactive, it cannot be deleted."
5099 5112
msgstr "Ce compte est désactivé, il ne peut plus être supprimé."
5100 5113

  
5101
#: src/authentic2/views.py:1227
5114
#: src/authentic2/views.py:1228
5102 5115
msgid "The account deletion request is too old, try again"
5103 5116
msgstr "La demande de suppression de compte est expirée."
5104 5117

  
5105
#: src/authentic2/views.py:1229
5118
#: src/authentic2/views.py:1230
5106 5119
msgid "The account deletion request is invalid, try again"
5107 5120
msgstr "La demande de suppression de compte n’est pas valide."
5108 5121

  
5109
#: src/authentic2/views.py:1231
5122
#: src/authentic2/views.py:1232
5110 5123
msgid "The account deletion request was not on this site, try again"
5111 5124
msgstr ""
5112 5125
"Votre demande de suppression de compte vient d’un autre site que celui-ci."
5113 5126

  
5114
#: src/authentic2/views.py:1255
5127
#: src/authentic2/views.py:1256
5115 5128
msgid "Deletion performed."
5116 5129
msgstr "Suppression effectuée."
5117 5130

  
5118
#: src/authentic2/views.py:1280
5131
#: src/authentic2/views.py:1281
5119 5132
msgid "Password Change"
5120 5133
msgstr "Changement de mot de passe"
5121 5134

  
5122
#: src/authentic2/views.py:1291
5135
#: src/authentic2/views.py:1292
5123 5136
msgid "Password change is forbidden"
5124 5137
msgstr "Changement de mot de passe interdit"
5125 5138

  
5126
#: src/authentic2/views.py:1336
5139
#: src/authentic2/views.py:1337
5127 5140
msgid "Consent Management"
5128 5141
msgstr "Gestion des autorisations"
src/authentic2/templates/registration/password_reset_instructions.html
7 7

  
8 8
{% block content %}
9 9
  <p><strong>
10
    {% blocktrans with email=request.session.reset_email %}
11
    If your email address exists in our database, an email has been sent to {{ email }}.
10
    {% blocktrans %}
11
    If a user account exists in our database with your email address (or your
12
    username), an email has been sent to you.
12 13
    {% endblocktrans %}
13 14
  </strong></p>
14 15
  <p><strong>
src/authentic2/utils/__init__.py
804 804
        user.save()
805 805
    lifetime = settings.PASSWORD_RESET_TIMEOUT_DAYS * 3600 * 24
806 806
    # invalidate any token associated with this user
807
    Token.objects.filter(kind='pw-reset', content__user=user.pk, content__email=user.email).delete()
808
    token = Token.create('pw-reset', {'user': user.pk, 'email': user.email}, duration=lifetime)
807
    Token.objects.filter(kind='pw-reset', content__user=user.pk, content__email=user.email, content__username=user.username).delete()
808
    token = Token.create('pw-reset', {'user': user.pk, 'email': user.email, 'username': user.username}, duration=lifetime)
809 809
    reset_url = make_url(
810 810
        'password_reset_confirm',
811 811
        kwargs={'token': token.uuid_b64url},
src/authentic2/views.py
667 667
        return ctx
668 668

  
669 669
    def form_valid(self, form):
670
        email = form.cleaned_data['email']
670
        email_or_username = form.cleaned_data['email_or_username']
671 671

  
672 672
        # if an email has already been sent, warn once before allowing resend
673 673
        token = models.Token.objects.filter(
674
            kind='pw-reset', content__email=email, expires__gt=timezone.now()
674
            Q(content__email=email_or_username) | Q(content__username=email_or_username),
675
            kind='pw-reset', expires__gt=timezone.now()
675 676
        ).exists()
676 677
        resend_key = 'pw-reset-allow-resend'
677 678
        if app_settings.A2_TOKEN_EXISTS_WARNING and token and not self.request.session.get(resend_key):
678 679
            self.request.session[resend_key] = True
679 680
            form.add_error(
680
                'email',
681
                _('An email has already been sent to %s. Click "Validate" again if '
682
                  'you really want it to be sent again.') % email
681
                'email_or_username',
682
                _('An email has already been sent to your address. Click "Validate" again if '
683
                  'you really want it to be sent again.')
683 684
            )
684 685
            return self.form_invalid(form)
685 686
        self.request.session[resend_key] = False
686 687

  
687
        if is_ratelimited(self.request, key='post:email', group='pw-reset-email',
688
        if is_ratelimited(self.request, key='post:email_or_username', group='pw-reset-email-or-username',
688 689
                          rate=app_settings.A2_EMAILS_ADDRESS_RATELIMIT, increment=True):
689
            self.request.journal.record('user.password.reset.failure', email=email)
690
            self.request.journal.record('user.password.reset.failure', email_or_username=email_or_username)
690 691
            form.add_error(
691
                'email',
692
                'email_or_username',
692 693
                _('Multiple emails have already been sent to this address. Further attempts are '
693 694
                  'blocked, please check your spam folder or try again later.')
694 695
            )
695 696
            return self.form_invalid(form)
696
        if is_ratelimited(self.request, key='ip', group='pw-reset-email',
697
        if is_ratelimited(self.request, key='ip', group='pw-reset-email-or-username',
697 698
                          rate=app_settings.A2_EMAILS_IP_RATELIMIT, increment=True):
698
            self.request.journal.record('user.password.reset.failure', email=email)
699
            self.request.journal.record('user.password.reset.failure', email_or_username=email_or_username)
699 700
            form.add_error(
700
                'email',
701
                'email_or_username',
701 702
                _('Multiple password reset attempts have already been made from this IP address. No '
702 703
                  'further email will be sent, please check your spam folder or try again later.')
703 704
            )
704 705
            return self.form_invalid(form)
705 706

  
706 707
        form.save()
707
        self.request.session['reset_email'] = email
708
        self.request.session['reset_email_or_username'] = email_or_username
708 709
        return super(PasswordResetView, self).form_valid(form)
709 710

  
710 711
password_reset = PasswordResetView.as_view()
tests/auth_fc/test_auth_fc.py
211 211
    # No FC account, forbidden to set a password
212 212
    response = app.get('/login/')
213 213
    response = response.click('Reset it!').maybe_follow()
214
    response.form['email'] = user.email
214
    response.form['email_or_username'] = user.email
215 215
    assert len(mailoutbox) == 0
216 216
    response = response.form.submit()
217 217
    assert len(mailoutbox) == 1
......
224 224
    models.FcAccount.objects.create(user=user, sub='xxx', token='aaa')
225 225
    response = app.get('/login/')
226 226
    response = response.click('Reset it!').maybe_follow()
227
    response.form['email'] = user.email
227
    response.form['email_or_username'] = user.email
228 228
    assert len(mailoutbox) == 1
229 229
    response = response.form.submit()
230 230
    assert len(mailoutbox) == 2
tests/test_ldap.py
705 705
    else:
706 706
        response = response.maybe_follow()
707 707
    response = response.click('Reset it!')
708
    response.form['email'] = EMAIL
708
    response.form['email_or_username'] = EMAIL
709 709
    assert len(mail.outbox) == 0
710 710
    response = response.form.submit().maybe_follow()
711 711
    assert len(mail.outbox) == 1
tests/test_password_reset.py
43 43
    utils.assert_event('user.password.reset', user=simple_user, session=app.session)
44 44

  
45 45

  
46
def test_view(app, simple_user, mailoutbox, settings):
46
def test_view_with_email(app, simple_user, mailoutbox, settings):
47 47
    url = reverse('password_reset')
48 48
    resp = app.get(url, status=200)
49
    resp.form.set('email', simple_user.email)
49
    resp.form.set('email_or_username', simple_user.email)
50
    assert len(mailoutbox) == 0
51
    settings.DEFAULT_FROM_EMAIL = 'show only addr <noreply@example.net>'
52
    resp = resp.form.submit()
53
    utils.assert_event('user.password.reset.request', user=simple_user, email=simple_user.email)
54
    assert resp['Location'].endswith('/instructions/')
55
    resp = resp.follow()
56
    assert '"noreply@example.net"' in resp.text
57
    assert 'show only addr' not in resp.text
58
    assert len(mailoutbox) == 1
59
    url = utils.get_link_from_mail(mailoutbox[0])
60
    relative_url = url.split('testserver')[1]
61
    resp = app.get(relative_url, status=200)
62
    resp.form.set('new_password1', '1234==aA')
63
    resp.form.set('new_password2', '1234==aA')
64
    resp = resp.form.submit()
65
    # verify user is logged
66
    assert str(app.session['_auth_user_id']) == str(simple_user.pk)
67

  
68
    with override_settings(A2_USER_CAN_RESET_PASSWORD=False):
69
        url = reverse('password_reset')
70
        app.get(url, status=404)
71

  
72

  
73
def test_view_with_username(app, simple_user, mailoutbox, settings):
74
    url = reverse('password_reset')
75
    resp = app.get(url, status=200)
76
    resp.form.set('email_or_username', simple_user.username)
50 77
    assert len(mailoutbox) == 0
51 78
    settings.DEFAULT_FROM_EMAIL = 'show only addr <noreply@example.net>'
52 79
    resp = resp.form.submit()
53 80
    utils.assert_event('user.password.reset.request', user=simple_user, email=simple_user.email)
54 81
    assert resp['Location'].endswith('/instructions/')
55 82
    resp = resp.follow()
56
    assert simple_user.email in resp.text
57 83
    assert '"noreply@example.net"' in resp.text
58 84
    assert 'show only addr' not in resp.text
59 85
    assert len(mailoutbox) == 1
......
76 102

  
77 103
    url = reverse('password_reset')
78 104
    resp = app.get(url, status=200)
79
    resp.form.set('email', simple_user.email)
105
    resp.form.set('email_or_username', simple_user.email)
80 106
    assert len(mailoutbox) == 0
81 107
    resp = resp.form.submit()
82 108
    assert len(mailoutbox) == 0
......
87 113

  
88 114
    url = reverse('password_reset')
89 115
    resp = app.get(url, status=200)
90
    resp.form.set('email', simple_user.email)
116
    resp.form.set('email_or_username', simple_user.email)
91 117
    assert len(mailoutbox) == 0
92 118
    resp = resp.form.submit()
93 119
    assert len(mailoutbox) == 0
tests/test_views.py
181 181
    settings.A2_EMAILS_ADDRESS_RATELIMIT = '3/d'
182 182
    users = [User.objects.create(email='test%s@test.com' % i) for i in range(8)]
183 183

  
184
    email_field = 'email_or_username' if view_name == 'password_reset' else 'email'
185

  
184 186
    # reach email limit
185 187
    for _ in range(3):
186 188
        response = app.get(reverse(view_name))
187
        response.form.set('email', simple_user.email)
189
        response.form.set(email_field, simple_user.email)
188 190
        response = response.form.submit()
189 191
    assert len(mailoutbox) == 3
190 192

  
191 193
    response = app.get(reverse(view_name))
192
    response.form.set('email', simple_user.email)
194
    response.form.set(email_field, simple_user.email)
193 195
    response = response.form.submit()
194 196
    assert len(mailoutbox) == 3
195 197
    assert 'try again later' in response.text
196 198
    if view_name == 'password_reset':
197
        assert_event('user.password.reset.failure', email=simple_user.email)
199
        assert_event('user.password.reset.failure', email_or_username=simple_user.email)
198 200

  
199 201
    # reach ip limit
200 202
    for i in range(7):
201 203
        response = app.get(reverse(view_name))
202
        response.form.set('email', users[i].email)
204
        response.form.set(email_field, users[i].email)
203 205
        response = response.form.submit()
204 206
    assert len(mailoutbox) == 10
205 207

  
206 208
    response = app.get(reverse(view_name))
207
    response.form.set('email', users[i + 1].email)
209
    response.form.set(email_field, users[i + 1].email)
208 210
    response = response.form.submit()
209 211
    assert len(mailoutbox) == 10
210 212
    assert 'try again later' in response.text
......
212 214
    # ip ratelimits are lifted after an hour
213 215
    freezer.tick(datetime.timedelta(hours=1))
214 216
    response = app.get(reverse(view_name))
215
    response.form.set('email', users[0].email)
217
    response.form.set(email_field, users[0].email)
216 218
    response = response.form.submit()
217 219
    assert len(mailoutbox) == 11
218 220

  
219 221
    # email ratelimits are lifted after a day
220 222
    response = app.get(reverse(view_name))
221
    response.form.set('email', simple_user.email)
223
    response.form.set(email_field, simple_user.email)
222 224
    response = response.form.submit()
223 225
    assert len(mailoutbox) == 11
224 226
    assert 'try again later' in response.text
225 227

  
226 228
    freezer.tick(datetime.timedelta(days=1))
227 229
    response = app.get(reverse(view_name))
228
    response.form.set('email', simple_user.email)
230
    response.form.set(email_field, simple_user.email)
229 231
    response = response.form.submit()
230 232
    assert len(mailoutbox) == 12
231 233

  
......
234 236
def test_views_email_token_resend(app, simple_user, settings, mailoutbox, view_name):
235 237
    settings.A2_TOKEN_EXISTS_WARNING = True
236 238

  
239
    email_field = 'email_or_username' if view_name == 'password_reset' else 'email'
240

  
237 241
    response = app.get(reverse(view_name))
238
    response.form.set('email', simple_user.email)
242
    response.form.set(email_field, simple_user.email)
239 243
    response = response.form.submit()
240 244
    assert len(mailoutbox) == 1
241 245

  
242 246
    # warn user token has already been sent
243 247
    response = app.get(reverse(view_name))
244
    response.form.set('email', simple_user.email)
248
    response.form.set(email_field, simple_user.email)
245 249
    response = response.form.submit()
246 250
    assert 'email has already been sent' in response.text
247 251
    assert len(mailoutbox) == 1
248
-