From 00d0184bad02018a9b12fa81f3b4f0588a3fb6bd Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 6 Jul 2017 23:09:35 -0400 Subject: [PATCH] Add support for requesting a password reset email. Signed-off-by: Roberto Rosario --- .../templates/appearance/login.html | 6 +- .../password_reset_complete.html | 21 +++++ .../password_reset_confirm.html | 37 ++++++++ .../authentication/password_reset_done.html | 18 ++++ .../authentication/password_reset_email.html | 6 ++ .../authentication/password_reset_form.html | 37 ++++++++ .../authentication/password_reset_subject.txt | 1 + mayan/apps/authentication/urls.py | 41 ++++----- mayan/apps/authentication/views.py | 86 +++++++++++++++++-- 9 files changed, 217 insertions(+), 36 deletions(-) create mode 100644 mayan/apps/appearance/templates/authentication/password_reset_complete.html create mode 100644 mayan/apps/appearance/templates/authentication/password_reset_confirm.html create mode 100644 mayan/apps/appearance/templates/authentication/password_reset_done.html create mode 100644 mayan/apps/appearance/templates/authentication/password_reset_email.html create mode 100644 mayan/apps/appearance/templates/authentication/password_reset_form.html create mode 100644 mayan/apps/appearance/templates/authentication/password_reset_subject.txt diff --git a/mayan/apps/appearance/templates/appearance/login.html b/mayan/apps/appearance/templates/appearance/login.html index 787a4a538c..bc1254e2c6 100644 --- a/mayan/apps/appearance/templates/appearance/login.html +++ b/mayan/apps/appearance/templates/appearance/login.html @@ -49,12 +49,14 @@
{% include 'appearance/generic_form_instance.html' %} -
- +
+
+ {% trans 'Forgot your password?' %} +
diff --git a/mayan/apps/appearance/templates/authentication/password_reset_complete.html b/mayan/apps/appearance/templates/authentication/password_reset_complete.html new file mode 100644 index 0000000000..8ff6913fb8 --- /dev/null +++ b/mayan/apps/appearance/templates/authentication/password_reset_complete.html @@ -0,0 +1,21 @@ +{% extends 'appearance/base.html' %} + +{% load i18n %} +{% load static %} + +{% load common_tags %} + +{% block base_title %}{% trans 'Password reset' %}{% endblock %} + +{% block project_name %}{% endblock %} + +{% block content_plain %} +
+
+ + + +
+
+ +{% endblock content_plain %} diff --git a/mayan/apps/appearance/templates/authentication/password_reset_confirm.html b/mayan/apps/appearance/templates/authentication/password_reset_confirm.html new file mode 100644 index 0000000000..12c16ce80b --- /dev/null +++ b/mayan/apps/appearance/templates/authentication/password_reset_confirm.html @@ -0,0 +1,37 @@ +{% extends 'appearance/base.html' %} + +{% load i18n %} +{% load static %} + +{% load common_tags %} + +{% block base_title %}{% trans 'Password reset' %}{% endblock %} + +{% block project_name %}{% endblock %} + +{% block content_plain %} +
+
+
+
+

 

+
+
+

{% trans 'Password reset' %}

+
+ +
+
+
+{% endblock content_plain %} diff --git a/mayan/apps/appearance/templates/authentication/password_reset_done.html b/mayan/apps/appearance/templates/authentication/password_reset_done.html new file mode 100644 index 0000000000..887e7e0bba --- /dev/null +++ b/mayan/apps/appearance/templates/authentication/password_reset_done.html @@ -0,0 +1,18 @@ +{% extends 'appearance/base.html' %} + +{% load i18n %} +{% load static %} + +{% load common_tags %} + +{% block base_title %}{% trans 'Password reset' %}{% endblock %} + +{% block project_name %}{% endblock %} + +{% block content_plain %} +
+
+ +
+
+{% endblock content_plain %} diff --git a/mayan/apps/appearance/templates/authentication/password_reset_email.html b/mayan/apps/appearance/templates/authentication/password_reset_email.html new file mode 100644 index 0000000000..adc7d21d40 --- /dev/null +++ b/mayan/apps/appearance/templates/authentication/password_reset_email.html @@ -0,0 +1,6 @@ +Hello {{ user.full_name|default:user }}, + +We received a request to reset your {{ project_title }} password. +Click the link below to choose a new one: + +{{ project_website }}{% url 'authentication:password_reset_confirm_view' uid token %} diff --git a/mayan/apps/appearance/templates/authentication/password_reset_form.html b/mayan/apps/appearance/templates/authentication/password_reset_form.html new file mode 100644 index 0000000000..12c16ce80b --- /dev/null +++ b/mayan/apps/appearance/templates/authentication/password_reset_form.html @@ -0,0 +1,37 @@ +{% extends 'appearance/base.html' %} + +{% load i18n %} +{% load static %} + +{% load common_tags %} + +{% block base_title %}{% trans 'Password reset' %}{% endblock %} + +{% block project_name %}{% endblock %} + +{% block content_plain %} +
+
+
+
+

 

+
+
+

{% trans 'Password reset' %}

+
+ +
+
+
+{% endblock content_plain %} diff --git a/mayan/apps/appearance/templates/authentication/password_reset_subject.txt b/mayan/apps/appearance/templates/authentication/password_reset_subject.txt new file mode 100644 index 0000000000..e52a0499fb --- /dev/null +++ b/mayan/apps/appearance/templates/authentication/password_reset_subject.txt @@ -0,0 +1 @@ +{{ project_title }} password reset link diff --git a/mayan/apps/authentication/urls.py b/mayan/apps/authentication/urls.py index a5acaa9067..93443bea2d 100644 --- a/mayan/apps/authentication/urls.py +++ b/mayan/apps/authentication/urls.py @@ -2,12 +2,13 @@ from __future__ import unicode_literals from django.conf import settings from django.conf.urls import url -from django.contrib.auth.views import ( - logout, password_reset, password_reset_confirm, password_reset_complete, - password_reset_done -) +from django.contrib.auth.views import logout -from .views import login_view, password_change_done, password_change_view +from .views import ( + login_view, password_change_done, password_change_view, + password_reset_complete_view, password_reset_confirm_view, + password_reset_done_view, password_reset_view +) urlpatterns = [ @@ -20,35 +21,23 @@ urlpatterns = [ r'^password/change/$', password_change_view, name='password_change_view' ), -] - -urlpatterns += [ url( r'^logout/$', logout, {'next_page': settings.LOGIN_REDIRECT_URL}, name='logout_view' ), url( - r'^password/reset/$', password_reset, { - 'email_template_name': 'appearance/password_reset_email.html', - 'template_name': 'appearance/password_reset_form.html', - 'post_reset_redirect': '/password/reset/done' - }, name='password_reset_view' + r'^password/reset/$', password_reset_view, name='password_reset_view' ), url( - r'^password/reset/confirm/(?P[0-9A-Za-z]+)-(?P.+)/$', - password_reset_confirm, { - 'template_name': 'appearance/password_reset_confirm.html', - 'post_reset_redirect': '/password/reset/complete/' - }, name='password_reset_confirm_view' + r'^password/reset/confirm/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', + password_reset_confirm_view, name='password_reset_confirm_view' ), url( - r'^password/reset/complete/$', - password_reset_complete, { - 'template_name': 'appearance/password_reset_complete.html' - }, name='password_reset_complete_view'), + r'^password/reset/complete/$', password_reset_complete_view, + name='password_reset_complete_view' + ), url( - r'^password/reset/done/$', - password_reset_done, { - 'template_name': 'appearance/password_reset_done.html' - }, name='password_reset_done_view'), + r'^password/reset/done/$', password_reset_done_view, + name='password_reset_done_view' + ), ] diff --git a/mayan/apps/authentication/views.py b/mayan/apps/authentication/views.py index 81c974cd5a..50d3b45f4f 100644 --- a/mayan/apps/authentication/views.py +++ b/mayan/apps/authentication/views.py @@ -2,12 +2,14 @@ from __future__ import absolute_import, unicode_literals from django.conf import settings from django.contrib import messages -from django.contrib.auth.views import login, password_change +from django.contrib.auth.views import ( + login, password_change, password_reset, password_reset_confirm, + password_reset_complete, password_reset_done +) from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect from django.shortcuts import redirect from django.utils.translation import ugettext_lazy as _ - from stronghold.decorators import public from .forms import EmailAuthenticationForm, UsernameAuthenticationForm @@ -28,9 +30,9 @@ def login_view(request): kwargs['authentication_form'] = UsernameAuthenticationForm if not request.user.is_authenticated(): - context = {'appearance_type': 'plain'} + extra_context = {'appearance_type': 'plain'} - result = login(request, extra_context=context, **kwargs) + result = login(request, extra_context=extra_context, **kwargs) if request.method == 'POST': form = kwargs['authentication_form'](request, data=request.POST) if form.is_valid(): @@ -49,11 +51,10 @@ def password_change_view(request): """ Password change wrapper for better control """ - context = {'title': _('Current user password change')} + extra_context = {'title': _('Current user password change')} return password_change( - request, - extra_context=context, + request, extra_context=extra_context, template_name='appearance/generic_form.html', post_change_redirect=reverse('authentication:password_change_done'), ) @@ -63,8 +64,77 @@ def password_change_done(request): """ View called when the new user password has been accepted """ - messages.success( request, _('Your password has been successfully changed.') ) return redirect('common:current_user_details') + + +@public +def password_reset_complete_view(request): + extra_context = { + 'appearance_type': 'plain' + } + + kwargs = { + 'template_name': 'authentication/password_reset_complete.html' + } + + return password_reset_complete( + request, extra_context=extra_context, **kwargs + ) + + +@public +def password_reset_confirm_view(request, uidb64=None, token=None): + extra_context = { + 'appearance_type': 'plain' + } + + kwargs = { + 'template_name': 'authentication/password_reset_confirm.html', + 'post_reset_redirect': reverse('authentication:password_reset_complete_view'), + 'uidb64': uidb64, + 'token': token + } + + return password_reset_confirm( + request, extra_context=extra_context, **kwargs + ) + + +@public +def password_reset_done_view(request): + extra_context = { + 'appearance_type': 'plain' + } + + kwargs = { + 'template_name': 'authentication/password_reset_done.html' + } + + return password_reset_done(request, extra_context=extra_context, **kwargs) + + +@public +def password_reset_view(request): + extra_context = { + 'appearance_type': 'plain' + } + + kwargs = { + 'email_template_name': 'authentication/password_reset_email.html', + 'extra_email_context': { + 'project_title': settings.PROJECT_TITLE, + 'project_website': settings.PROJECT_WEBSITE, + 'project_copyright': settings.PROJECT_COPYRIGHT, + 'project_license': settings.PROJECT_LICENSE, + }, + 'subject_template_name': 'authentication/password_reset_subject.txt', + 'template_name': 'authentication/password_reset_form.html', + 'post_reset_redirect': reverse( + 'authentication:password_reset_done_view' + ) + } + + return password_reset(request, extra_context=extra_context, **kwargs)