From e0e6960b53e24a40ca28bff10fd476727fedba57 Mon Sep 17 00:00:00 2001
From: Bryan Brancotte <bryan.brancotte@pasteur.fr>
Date: Mon, 20 May 2019 11:05:18 +0200
Subject: [PATCH] Using Django's lost password workflow, using app templates,
 adding quick start indication and example in the test project

---
 README.md                                     |  4 ++-
 README.rst                                    |  4 ++-
 .../templates/registration/login.html         |  1 +
 .../registration/password_reset_complete.html |  9 ++++++
 .../registration/password_reset_confirm.html  |  3 ++
 .../registration/password_reset_done.html     |  9 ++++++
 .../registration/password_reset_email.html    | 14 +++++++++
 .../registration/password_reset_form.html     |  3 ++
 basetheme_bootstrap/urls.py                   | 29 +++++++++++++++++--
 setup.py                                      |  2 +-
 tests/settings.py                             |  7 ++++-
 tests/urls.py                                 |  2 ++
 12 files changed, 81 insertions(+), 6 deletions(-)
 create mode 100644 basetheme_bootstrap/templates/registration/password_reset_complete.html
 create mode 100644 basetheme_bootstrap/templates/registration/password_reset_confirm.html
 create mode 100644 basetheme_bootstrap/templates/registration/password_reset_done.html
 create mode 100644 basetheme_bootstrap/templates/registration/password_reset_email.html
 create mode 100644 basetheme_bootstrap/templates/registration/password_reset_form.html

diff --git a/README.md b/README.md
index 971451a..2758b58 100644
--- a/README.md
+++ b/README.md
@@ -7,13 +7,15 @@ A module handling basic fonctionnality needed in django project such as base.htm
 
 # Quick start
 
-1. Add "basetheme_bootstrap" to your INSTALLED_APPS setting like this (while not forgetting `crispy_forms`)
+1. Add "basetheme_bootstrap" to your INSTALLED_APPS setting like this (while not forgetting `crispy_forms`). Note that basetheme_bootstrap have to be before django.contrib.admin to override the default template for password reset.
 
 ```python
 INSTALLED_APPS = [
     ...
     'crispy_forms',
     'basetheme_bootstrap',
+    ...
+    'django.contrib.admin',
 ]
 ```
 
diff --git a/README.rst b/README.rst
index 9d4095d..551a964 100644
--- a/README.rst
+++ b/README.rst
@@ -9,12 +9,14 @@ Detailed documentation is in the "docs" directory.
 Quick start
 -----------
 
-1. Add "basetheme_bootstrap" to your INSTALLED_APPS setting like this (while not forgetting `crispy_forms`) ::
+1. Add "basetheme_bootstrap" to your INSTALLED_APPS setting like this (while not forgetting `crispy_forms`). Note that basetheme_bootstrap have to be before django.contrib.admin to override the default template for password reset. ::
 
     INSTALLED_APPS = [
         ...
         'crispy_forms',
         'basetheme_bootstrap',
+        ...
+        'django.contrib.admin',
     ]
 
 2. Add the context_processors::
diff --git a/basetheme_bootstrap/templates/registration/login.html b/basetheme_bootstrap/templates/registration/login.html
index 1738c78..fb8d1c8 100644
--- a/basetheme_bootstrap/templates/registration/login.html
+++ b/basetheme_bootstrap/templates/registration/login.html
@@ -16,5 +16,6 @@
     <br/>
     <hr/>
     <a href="{% url 'basetheme_bootstrap:signup' %}" role="button" class="btn btn-default btn-outline-primary full-width">{%trans "Create account"%}</a>
+    <a href="{% url 'basetheme_bootstrap:password_reset' %}" role="button" class="btn btn-default btn-outline-primary full-width pull-right float-right">{%trans "Reset my password"%}</a>
 </div>
 {% endblock %}
\ No newline at end of file
diff --git a/basetheme_bootstrap/templates/registration/password_reset_complete.html b/basetheme_bootstrap/templates/registration/password_reset_complete.html
new file mode 100644
index 0000000..52a69a9
--- /dev/null
+++ b/basetheme_bootstrap/templates/registration/password_reset_complete.html
@@ -0,0 +1,9 @@
+{% extends 'basetheme_bootstrap/simple_message_page.html' %}
+{% load i18n %}
+
+{% block title %}{{ title }}{% endblock %}
+{% block page_title %}{{ title }}{% endblock %}
+{% block sub_message%}
+{% trans "Your password has been set.  You may go ahead and log in now." %}
+<a href="{{ login_url }}">{% trans 'Log in' %}</a>
+{% endblock %}
\ No newline at end of file
diff --git a/basetheme_bootstrap/templates/registration/password_reset_confirm.html b/basetheme_bootstrap/templates/registration/password_reset_confirm.html
new file mode 100644
index 0000000..e6ec0c3
--- /dev/null
+++ b/basetheme_bootstrap/templates/registration/password_reset_confirm.html
@@ -0,0 +1,3 @@
+{% load i18n %}
+{% trans 'Change my password' as submit_text %}
+{%include 'registration/small_form_host.html' with title=title submit_text=submit_text form=form%}
\ No newline at end of file
diff --git a/basetheme_bootstrap/templates/registration/password_reset_done.html b/basetheme_bootstrap/templates/registration/password_reset_done.html
new file mode 100644
index 0000000..c13013f
--- /dev/null
+++ b/basetheme_bootstrap/templates/registration/password_reset_done.html
@@ -0,0 +1,9 @@
+{% extends 'basetheme_bootstrap/simple_message_page.html' %}
+{% load i18n %}
+
+{% block title %}{{ title }}{% endblock %}
+{% block page_title %}{{ title }}{% endblock %}
+{% block sub_message%}
+<p>{% trans "We've emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly." %}</p>
+<p>{% trans "If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder." %}</p>
+{% endblock %}
\ No newline at end of file
diff --git a/basetheme_bootstrap/templates/registration/password_reset_email.html b/basetheme_bootstrap/templates/registration/password_reset_email.html
new file mode 100644
index 0000000..09633f7
--- /dev/null
+++ b/basetheme_bootstrap/templates/registration/password_reset_email.html
@@ -0,0 +1,14 @@
+{% load i18n %}{% autoescape off %}
+{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
+
+{% trans "Please go to the following page and choose a new password:" %}
+{% block reset_link %}
+{{ protocol }}://{{ domain }}{% url 'basetheme_bootstrap:password_reset_confirm' uidb64=uid token=token %}
+{% endblock %}
+{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
+
+{% trans "Thanks for using our site!" %}
+
+{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
+
+{% endautoescape %}
diff --git a/basetheme_bootstrap/templates/registration/password_reset_form.html b/basetheme_bootstrap/templates/registration/password_reset_form.html
new file mode 100644
index 0000000..5594efb
--- /dev/null
+++ b/basetheme_bootstrap/templates/registration/password_reset_form.html
@@ -0,0 +1,3 @@
+{% load i18n %}
+{% trans 'Reset my password' as submit_text %}
+{%include 'registration/small_form_host.html' with title=title submit_text=submit_text form=form%}
\ No newline at end of file
diff --git a/basetheme_bootstrap/urls.py b/basetheme_bootstrap/urls.py
index fafb61d..8d6cba9 100644
--- a/basetheme_bootstrap/urls.py
+++ b/basetheme_bootstrap/urls.py
@@ -1,12 +1,14 @@
 from django.conf.urls import url
 from django.contrib.auth import views as auth_views
-from django.contrib.auth.decorators import login_required
-from django.views.generic import TemplateView
+from django.urls import reverse_lazy
 
 from basetheme_bootstrap import views
 
 app_name = 'basetheme_bootstrap'
 urlpatterns = [
+    ################################################################################
+    # Account management
+    ################################################################################
     url(r'^accounts/$', views.account_detail, name='account'),
     url(r'^accounts/login/$', auth_views.LoginView.as_view(), name='login'),
     url(r'^accounts/logout/$', auth_views.LogoutView.as_view(next_page='/'), name='logout'),
@@ -14,5 +16,28 @@ urlpatterns = [
     url(r'^accounts/signup/$', views.signup, name='signup'),
     url(r'^accounts/edit/$', views.user_update, name='user-update'),
     url(r'^accounts/remove/$', views.user_delete, name='user-delete'),
+    ################################################################################
+    # About page
+    ################################################################################
     url(r'^about/$', views.about_page, name='about_page'),
+    ################################################################################
+    # Lost password
+    ################################################################################
+    url(r'^accounts/password_reset/$',
+        auth_views.PasswordResetView.as_view(
+            success_url=reverse_lazy("basetheme_bootstrap:password_reset_done"),
+        ),
+        name='password_reset'),
+    url(r'^accounts/password_reset/done/$',
+        auth_views.PasswordResetDoneView.as_view(),
+        name='password_reset_done'),
+    url(r'^accounts/password/reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
+        auth_views.PasswordResetConfirmView.as_view(
+            success_url=reverse_lazy("basetheme_bootstrap:password_reset_complete"),
+        ),
+        name='password_reset_confirm'),
+    url(r'^accounts/password/reset/done/$',
+        auth_views.PasswordResetCompleteView.as_view(),
+        name='password_reset_complete'),
+    ################################################################################
 ]
diff --git a/setup.py b/setup.py
index 8f4f2c6..0881b43 100644
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,7 @@ readme = open('README.rst').read()
 
 setup(
     name='django-basetheme-bootstrap',
-    version='0.0.8',
+    version='0.0.9',
     description='Django Basetheme Bootstrap',
     long_description=readme,
     author='Bryan Brancotte',
diff --git a/tests/settings.py b/tests/settings.py
index 07fd217..374509b 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -32,7 +32,6 @@ ALLOWED_HOSTS = ['*']
 # Application definition
 
 INSTALLED_APPS = [
-    'django.contrib.admin',
     'django.contrib.auth',
     'django.contrib.contenttypes',
     'django.contrib.sessions',
@@ -41,6 +40,7 @@ INSTALLED_APPS = [
     'crispy_forms',
     'basetheme_bootstrap',
     'test_app_1',
+    'django.contrib.admin',
 ]
 
 MIDDLEWARE = [
@@ -138,3 +138,8 @@ BASETHEME_BOOTSTRAP_USER_PREFERENCE_MODEL_LOCATION_APP = "test_app_1"
 BASETHEME_BOOTSTRAP_USER_PREFERENCE_MODEL_NAME = "MyUserPreferences"
 
 ################################################################################
+# Various debug stuff
+################################################################################
+EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
+
+################################################################################
\ No newline at end of file
diff --git a/tests/urls.py b/tests/urls.py
index 7361222..dc758db 100644
--- a/tests/urls.py
+++ b/tests/urls.py
@@ -1,6 +1,7 @@
 from django.http import HttpResponse
 from django.urls import path, include
 from django.views.generic import TemplateView
+from django.contrib import admin
 
 
 def blabla(request):
@@ -8,6 +9,7 @@ def blabla(request):
 
 
 urlpatterns = [
+    path('admin/', admin.site.urls),
     path('', TemplateView.as_view(template_name='basetheme_bootstrap/base4.html'), name='home'),
     path('', include('basetheme_bootstrap.urls')),
 ]
-- 
GitLab