Ticket #14918: password-reset-with-username.patch

File password-reset-with-username.patch, 9.2 KB (added by Jonas H., 13 years ago)

(against 14922)

  • django/contrib/admin/templates/registration/password_reset_form.html

    commit 585445ffe1b35fc05255cc504afde4f115469caa
    Author: Jonas Haag <jonas@lophus.org>
    Date:   Sat Dec 18 14:25:32 2010 +0100
    
        Make password reset possible with username or e-mail, not only e-mail.
    
    diff --git a/django/contrib/admin/templates/registration/password_reset_form.html b/django/contrib/admin/templates/registration/password_reset_form.html
    index d3a1284..ec7502f 100644
    a b  
    99
    1010<h1>{% trans "Password reset" %}</h1>
    1111
    12 <p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll e-mail instructions for setting a new one." %}</p>
     12<p>{% trans "Forgotten your password? Enter your username or e-mail address below, and we'll e-mail instructions for setting a new one." %}</p>
    1313
    1414<form action="" method="post">{% csrf_token %}
    1515{{ form.email.errors }}
    16 <p><label for="id_email">{% trans 'E-mail address:' %}</label> {{ form.email }} <input type="submit" value="{% trans 'Reset my password' %}" /></p>
     16<p><label for="id_email_or_username">{% trans 'E-mail address:' %}</label> {{ form.email }} <input type="submit" value="{% trans 'Reset my password' %}" /></p>
    1717</form>
    1818
    1919{% endblock %}
  • django/contrib/auth/forms.py

    diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
    index 7473279..658eee3 100644
    a b  
     1import re
     2from django.core.validators import validate_email
    13from django.contrib.auth.models import User
    24from django.contrib.auth import authenticate
    35from django.contrib.auth.tokens import default_token_generator
    from django import forms  
    79from django.utils.translation import ugettext_lazy as _
    810from django.utils.http import int_to_base36
    911
     12USERNAME_RE = re.compile(r'^[\w.@+-]+$')
     13
     14def guess_is_email(string):
     15    if not USERNAME_RE.match(string):
     16        # can't be a username
     17        return True
     18    try:
     19        validate_email(string)
     20        return True
     21    except forms.ValidationError:
     22        return False
     23
    1024class UserCreationForm(forms.ModelForm):
    1125    """
    1226    A form that creates a user, with no privileges, from the given username and password.
    1327    """
    14     username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^[\w.@+-]+$',
     28    username = forms.RegexField(label=_("Username"), max_length=30, regex=USERNAME_RE,
    1529        help_text = _("Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only."),
    1630        error_messages = {'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")})
    1731    password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
    class AuthenticationForm(forms.Form):  
    105119        return self.user_cache
    106120
    107121class PasswordResetForm(forms.Form):
    108     email = forms.EmailField(label=_("E-mail"), max_length=75)
     122    email_or_username = forms.CharField(label=_("E-mail or username"), max_length=75)
    109123
    110     def clean_email(self):
     124    def clean_email_or_username(self):
    111125        """
    112         Validates that a user exists with the given e-mail address.
     126        Validates that a user exists with the given e-mail address or username.
    113127        """
    114         email = self.cleaned_data["email"]
    115         self.users_cache = User.objects.filter(email__iexact=email)
     128        identifier = self.cleaned_data["email_or_username"]
     129        if guess_is_email(identifier):
     130            self.users_cache = User.objects.filter(email__iexact=identifier)
     131        else:
     132            self.users_cache = User.objects.filter(username=identifier)
    116133        if len(self.users_cache) == 0:
    117             raise forms.ValidationError(_("That e-mail address doesn't have an associated user account. Are you sure you've registered?"))
    118         return email
     134            raise forms.ValidationError(_("Unknown username or e-mail. Are you sure you've registered?"))
     135        return identifier
    119136
    120137    def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
    121138             use_https=False, token_generator=default_token_generator, from_email=None, request=None):
  • django/contrib/auth/tests/forms.py

    diff --git a/django/contrib/auth/tests/forms.py b/django/contrib/auth/tests/forms.py
    index 5aa49e0..09db43b 100644
    a b class PasswordResetFormTest(TestCase):  
    219219
    220220    fixtures = ['authtestdata.json']
    221221
    222     def test_invalid_email(self):
    223         data = {'email':'not valid'}
    224         form = PasswordResetForm(data)
    225         self.assertFalse(form.is_valid())
    226         self.assertEqual(form['email'].errors,
    227                          [u'Enter a valid e-mail address.'])
    228 
    229222    def test_nonexistant_email(self):
    230223        # Test nonexistant email address
    231         data = {'email':'foo@bar.com'}
     224        data = {'email_or_username':'foo@bar.com'}
    232225        form = PasswordResetForm(data)
    233226        self.assertFalse(form.is_valid())
    234227        self.assertEqual(form.errors,
    235                          {'email': [u"That e-mail address doesn't have an associated user account. Are you sure you've registered?"]})
     228                         {'email_or_username': [u"Unknown username or e-mail. Are you sure you've registered?"]})
    236229
    237230    def test_cleaned_data(self):
    238231        # Regression test
    239232        user = User.objects.create_user("jsmith3", "jsmith3@example.com", "test123")
    240         data = {'email':'jsmith3@example.com'}
     233        data = {'email_or_username':'jsmith3@example.com'}
    241234        form = PasswordResetForm(data)
    242235        self.assertTrue(form.is_valid())
    243         self.assertEqual(form.cleaned_data['email'], u'jsmith3@example.com')
     236        self.assertEqual(form.cleaned_data['email_or_username'], u'jsmith3@example.com')
    244237
    245238
    246239    def test_bug_5605(self):
  • django/contrib/auth/tests/views.py

    diff --git a/django/contrib/auth/tests/views.py b/django/contrib/auth/tests/views.py
    index 014c819..ebe4283 100644
    a b class AuthViewsTestCase(TestCase):  
    4747class PasswordResetTest(AuthViewsTestCase):
    4848
    4949    def test_email_not_found(self):
    50         "Error is raised if the provided email address isn't currently registered"
     50        "Error is raised if the provided username/email address isn't currently registered"
    5151        response = self.client.get('/password_reset/')
    5252        self.assertEquals(response.status_code, 200)
    53         response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'})
    54         self.assertContains(response, "That e-mail address doesn&#39;t have an associated user account")
    55         self.assertEquals(len(mail.outbox), 0)
     53        for identifier in ['not_a_real_username', 'not_a_real_email@email.com']:
     54            response = self.client.post('/password_reset/', {'email_or_username': identifier})
     55            self.assertContains(response, "Unknown username or e-mail.")
     56            self.assertEquals(len(mail.outbox), 0)
    5657
    5758    def test_email_found(self):
    58         "Email is sent if a valid email address is provided for password reset"
    59         response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
    60         self.assertEquals(response.status_code, 302)
    61         self.assertEquals(len(mail.outbox), 1)
    62         self.assert_("http://" in mail.outbox[0].body)
    63         self.assertEquals(settings.DEFAULT_FROM_EMAIL, mail.outbox[0].from_email)
     59        "Email is sent if a valid username/email address is provided for password reset"
     60        for i, identifier in enumerate(['staff', 'staffmember@example.com'], 1):
     61            response = self.client.post('/password_reset/', {'email_or_username' : identifier})
     62            self.assertEquals(response.status_code, 302)
     63            self.assertEquals(len(mail.outbox), i)
     64            self.assert_("http://" in mail.outbox[0].body)
     65            self.assertEquals(settings.DEFAULT_FROM_EMAIL, mail.outbox[0].from_email)
    6466
    6567    def test_email_found_custom_from(self):
    66         "Email is sent if a valid email address is provided for password reset when a custom from_email is provided."
    67         response = self.client.post('/password_reset_from_email/', {'email': 'staffmember@example.com'})
    68         self.assertEquals(response.status_code, 302)
    69         self.assertEquals(len(mail.outbox), 1)
    70         self.assertEquals("staffmember@example.com", mail.outbox[0].from_email)
     68        "Email is sent if a valid username/email address is provided for password reset when a custom from_email is provided."
     69        for i, identifier in enumerate(['staff', 'staffmember@example.com'], 1):
     70            response = self.client.post('/password_reset_from_email/', {'email_or_username': identifier})
     71            self.assertEquals(response.status_code, 302)
     72            self.assertEquals(len(mail.outbox), i)
     73            self.assertEquals("staffmember@example.com", mail.outbox[0].from_email)
    7174
    7275    def _test_confirm_start(self):
    7376        # Start by creating the email
    74         response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
     77        response = self.client.post('/password_reset/', {'email_or_username': 'staffmember@example.com'})
    7578        self.assertEquals(response.status_code, 302)
    7679        self.assertEquals(len(mail.outbox), 1)
    7780        return self._read_signup_email(mail.outbox[0])
Back to Top