Browse Source

Fix broken URL regex for resetting password

With complete webtest for password resetting story.
master
David Winterbottom 13 years ago
parent
commit
64a3e4e74d

+ 6
- 4
oscar/app.py View File

14
 
14
 
15
 class Shop(Application):
15
 class Shop(Application):
16
     name = None
16
     name = None
17
-    
17
+
18
     catalogue_app = catalogue_app
18
     catalogue_app = catalogue_app
19
     customer_app = customer_app
19
     customer_app = customer_app
20
     basket_app = basket_app
20
     basket_app = basket_app
23
     search_app = search_app
23
     search_app = search_app
24
     dashboard_app = dashboard_app
24
     dashboard_app = dashboard_app
25
     offer_app = offer_app
25
     offer_app = offer_app
26
-    
26
+
27
     def get_urls(self):
27
     def get_urls(self):
28
         urlpatterns = patterns('',
28
         urlpatterns = patterns('',
29
             (r'^products/', include(self.catalogue_app.urls)),
29
             (r'^products/', include(self.catalogue_app.urls)),
39
             # from working.
39
             # from working.
40
             url(r'^password-reset/$', auth_views.password_reset, name='password-reset'),
40
             url(r'^password-reset/$', auth_views.password_reset, name='password-reset'),
41
             url(r'^password-reset/done/$', auth_views.password_reset_done, name='password-reset-done'),
41
             url(r'^password-reset/done/$', auth_views.password_reset_done, name='password-reset-done'),
42
-            url(r'^password-reset/confirm/$', auth_views.password_reset_confirm, name='password-reset-confirm'),
42
+            url(r'^password-reset/confirm/(?P<uidb36>[0-9A-Za-z]{1,13})-(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
43
+                auth_views.password_reset_confirm, name='password-reset-confirm'),
43
             url(r'^password-reset/complete/$', auth_views.password_reset_complete, name='password-reset-complete'),
44
             url(r'^password-reset/complete/$', auth_views.password_reset_complete, name='password-reset-complete'),
44
 
45
 
45
             (r'', include(self.promotions_app.urls)),
46
             (r'', include(self.promotions_app.urls)),
46
         )
47
         )
47
         return urlpatterns
48
         return urlpatterns
48
-    
49
+
50
+
49
 # 'shop' kept for legacy projects - 'application' is a better name
51
 # 'shop' kept for legacy projects - 'application' is a better name
50
 shop = application = Shop()
52
 shop = application = Shop()

+ 1
- 0
oscar/templates/oscar/customer/login_registration.html View File

24
             <h2>{% trans 'Log In' %}</h2>
24
             <h2>{% trans 'Log In' %}</h2>
25
             {% csrf_token %}
25
             {% csrf_token %}
26
             {% include "partials/form_fields.html" with form=login_form %}
26
             {% include "partials/form_fields.html" with form=login_form %}
27
+			<p><a href="{% url password-reset %}">{% trans "I've forgotten my password" %}</a></p>
27
             <button name="login_submit" type="submit" value="Log In" class="btn btn-large btn-primary">{% trans 'Log In' %}</button>
28
             <button name="login_submit" type="submit" value="Log In" class="btn btn-large btn-primary">{% trans 'Log In' %}</button>
28
         </form>
29
         </form>
29
     </div>
30
     </div>

+ 1
- 1
oscar/templates/oscar/dashboard/layout.html View File

8
 	<link rel="stylesheet" href="{{ STATIC_URL }}oscar/css/dashboard.css" />
8
 	<link rel="stylesheet" href="{{ STATIC_URL }}oscar/css/dashboard.css" />
9
 {% endblock %}
9
 {% endblock %}
10
 
10
 
11
-{% block extrahead %} {%endblock extrahead %}
11
+{% block extrahead %} {% endblock extrahead %}
12
 
12
 
13
 {% block title %}
13
 {% block title %}
14
 {% trans "Dashboard" %} | {{ block.super }}
14
 {% trans "Dashboard" %} | {{ block.super }}

+ 1
- 1
oscar/templates/oscar/layout.html View File

18
             {% include "partials/nav_primary.html" %}
18
             {% include "partials/nav_primary.html" %}
19
         {% endblock %}
19
         {% endblock %}
20
     </header>
20
     </header>
21
-    <div class="container-fluid page">
21
+	<div class="container-fluid page">
22
         {% block header %}{% endblock %}
22
         {% block header %}{% endblock %}
23
         <div class="page_inner">
23
         <div class="page_inner">
24
             {% block breadcrumbs %}{% endblock %}
24
             {% block breadcrumbs %}{% endblock %}

+ 11
- 1
oscar/templates/oscar/registration/password_reset_complete.html View File

3
 
3
 
4
 {% block title %}{% trans 'Password reset complete' %} | {{ block.super }}{% endblock %}
4
 {% block title %}{% trans 'Password reset complete' %} | {{ block.super }}{% endblock %}
5
 
5
 
6
+{% block breadcrumbs %}
7
+<ul class="breadcrumb">
8
+    <li>
9
+        <a href="{% url promotions:home %}">{% trans 'Home' %}</a>
10
+        <span class="divider">/</span>
11
+    </li>
12
+	<li class="active"><a href=".">{% trans 'Password reset complete' %}</a></li>
13
+</ul>
14
+{% endblock %}
15
+
6
 {% block content %}
16
 {% block content %}
7
 	<h1>{% trans 'Password reset complete' %}</h1>
17
 	<h1>{% trans 'Password reset complete' %}</h1>
8
 	<p>{% trans "Your password has been set.  You may go ahead and log in now." %}</p>
18
 	<p>{% trans "Your password has been set.  You may go ahead and log in now." %}</p>
9
-	<p><a href="{{ login_url }}">{% trans 'Log in' %}</a></p>
19
+	<p><a href="{{ login_url }}" class="btn btn-large btn-primary">{% trans 'Log in' %}</a></p>
10
 {% endblock %}
20
 {% endblock %}

+ 12
- 2
oscar/templates/oscar/registration/password_reset_confirm.html View File

3
 
3
 
4
 {% block title %}{% trans 'Password reset confirm' %} | {{ block.super }}{% endblock %}
4
 {% block title %}{% trans 'Password reset confirm' %} | {{ block.super }}{% endblock %}
5
 
5
 
6
+{% block breadcrumbs %}
7
+<ul class="breadcrumb">
8
+    <li>
9
+        <a href="{% url promotions:home %}">{% trans 'Home' %}</a>
10
+        <span class="divider">/</span>
11
+    </li>
12
+	<li class="active"><a href=".">{% trans 'Enter new password' %}</a></li>
13
+</ul>
14
+{% endblock %}
15
+
6
 {% block content %}
16
 {% block content %}
7
 
17
 
8
 {% if validlink %}
18
 {% if validlink %}
11
 
21
 
12
 <p>{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}</p>
22
 <p>{% trans "Please enter your new password twice so we can verify you typed it in correctly." %}</p>
13
 
23
 
14
-<form action="" method="post">{% csrf_token %}
24
+<form id="password_reset_form" action="" method="post">{% csrf_token %}
15
 {{ form.new_password1.errors }}
25
 {{ form.new_password1.errors }}
16
 <p class="aligned wide"><label for="id_new_password1">{% trans 'New password:' %}</label>{{ form.new_password1 }}</p>
26
 <p class="aligned wide"><label for="id_new_password1">{% trans 'New password:' %}</label>{{ form.new_password1 }}</p>
17
 {{ form.new_password2.errors }}
27
 {{ form.new_password2.errors }}
18
 <p class="aligned wide"><label for="id_new_password2">{% trans 'Confirm password:' %}</label>{{ form.new_password2 }}</p>
28
 <p class="aligned wide"><label for="id_new_password2">{% trans 'Confirm password:' %}</label>{{ form.new_password2 }}</p>
19
-<p><input type="submit" value="{% trans 'Change my password' %}" /></p>
29
+<p><button class="btn btn-primary btn-large" type="submit">{% trans 'Change my password' %}</button></p>
20
 </form>
30
 </form>
21
 
31
 
22
 {% else %}
32
 {% else %}

+ 10
- 0
oscar/templates/oscar/registration/password_reset_done.html View File

3
 
3
 
4
 {% block title %}{% trans 'Password reset successful' %} | {{ block.super }}{% endblock %}
4
 {% block title %}{% trans 'Password reset successful' %} | {{ block.super }}{% endblock %}
5
 
5
 
6
+{% block breadcrumbs %}
7
+<ul class="breadcrumb">
8
+    <li>
9
+        <a href="{% url promotions:home %}">{% trans 'Home' %}</a>
10
+        <span class="divider">/</span>
11
+    </li>
12
+	<li class="active"><a href=".">{% trans 'Password reset sent' %}</a></li>
13
+</ul>
14
+{% endblock %}
15
+
6
 {% block content %}
16
 {% block content %}
7
 
17
 
8
     <h1>{% trans 'Password reset successful' %}</h1>
18
     <h1>{% trans 'Password reset successful' %}</h1>

+ 11
- 1
oscar/templates/oscar/registration/password_reset_form.html View File

3
 
3
 
4
 {% block title %}{% trans 'Password reset' %} | {{ block.super }}{% endblock %}
4
 {% block title %}{% trans 'Password reset' %} | {{ block.super }}{% endblock %}
5
 
5
 
6
+{% block breadcrumbs %}
7
+<ul class="breadcrumb">
8
+    <li>
9
+        <a href="{% url promotions:home %}">{% trans 'Home' %}</a>
10
+        <span class="divider">/</span>
11
+    </li>
12
+	<li class="active"><a href=".">{% trans 'Password reset' %}</a></li>
13
+</ul>
14
+{% endblock %}
15
+
6
 {% block content %}
16
 {% block content %}
7
 
17
 
8
     <div class="sub-header">
18
     <div class="sub-header">
9
         <h2>{% trans "Password reset" %}</h2>
19
         <h2>{% trans "Password reset" %}</h2>
10
     </div>
20
     </div>
11
 
21
 
12
-    <form action="" method="post" class="form-stacked well">
22
+    <form id="password_reset_form" action="" method="post" class="form-stacked well">
13
     {% csrf_token %}
23
     {% csrf_token %}
14
 
24
 
15
         <p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll e-mail instructions for setting a new one." %}</p>
25
         <p>{% trans "Forgotten your password? Enter your e-mail address below, and we'll e-mail instructions for setting a new one." %}</p>

+ 0
- 0
tests/functional/customer/__init__.py View File


+ 49
- 0
tests/functional/customer/auth_tests.py View File

1
+import re
2
+
3
+from django.contrib.auth import models
4
+from django.core.urlresolvers import reverse
5
+from django.core import mail
6
+
7
+from django_webtest import WebTest
8
+
9
+
10
+class TestAUserWhoseForgottenHerPassword(WebTest):
11
+
12
+    def test_can_reset_her_password(self):
13
+        username, email, password = 'lucy', 'lucy@example.com', 'password'
14
+        models.User.objects.create_user(
15
+            username, email, password
16
+        )
17
+
18
+        # Fill in password reset form
19
+        page = self.app.get(reverse('password-reset'))
20
+        form = page.forms['password_reset_form']
21
+        form['email'] = email
22
+        response = form.submit()
23
+
24
+        # Response should be a redirect and an email should have been sent
25
+        self.assertEqual(302, response.status_code)
26
+        self.assertEqual(1, len(mail.outbox))
27
+
28
+        # Extract URL from email
29
+        email_body = mail.outbox[0].body
30
+        urlfinder = re.compile(r"http://example.com(?P<path>[-A-Za-z0-9\/\._]+)")
31
+        matches = urlfinder.search(email_body, re.MULTILINE)
32
+        self.assertTrue('path' in matches.groupdict())
33
+        path = matches.groupdict()['path']
34
+
35
+        # Reset password and check we get redirect
36
+        reset_page = self.app.get(path)
37
+        form = reset_page.forms['password_reset_form']
38
+        form['new_password1'] = 'monkey'
39
+        form['new_password2'] = 'monkey'
40
+        response = form.submit()
41
+        self.assertEqual(302, response.status_code)
42
+
43
+        # Now attempt to login with new password
44
+        url = reverse('customer:login')
45
+        form = self.app.get(url).forms['login_form']
46
+        form['login-username'] = email
47
+        form['login-password'] = 'monkey'
48
+        response = form.submit('login_submit')
49
+        self.assertEqual(302, response.status_code)

Loading…
Cancel
Save