diff --git a/opentech/apply/urls.py b/opentech/apply/urls.py index a7487aaf5f3d029ec18b832ce8b329a2f6c32052..4624990d07ee3a1c64946e9dc6ab25ea614d4217 100644 --- a/opentech/apply/urls.py +++ b/opentech/apply/urls.py @@ -5,5 +5,5 @@ from .users import urls as users_urls urlpatterns = [ url(r'^apply/', include(funds_urls)), - url(r'^user/', include(users_urls)) + url(r'^account/', include(users_urls, namespace='users')), ] diff --git a/opentech/apply/users/templates/users/account.html b/opentech/apply/users/templates/users/account.html new file mode 100644 index 0000000000000000000000000000000000000000..725d615316bb18d3700f3dc45ed61a22253c7ad1 --- /dev/null +++ b/opentech/apply/users/templates/users/account.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block title %}Account{% endblock %} + +{% block content %} +<h2>Welcome {{ user }}</h2> + +{% if show_change_password %} + <a href="{% url 'users:password_change' %}">{% trans "Change password" %}</a> +{% endif %} +{% endblock %} diff --git a/opentech/apply/users/templates/users/change_password.html b/opentech/apply/users/templates/users/change_password.html new file mode 100644 index 0000000000000000000000000000000000000000..26799c69da341f713f390e9eb7139740fbbb8c1a --- /dev/null +++ b/opentech/apply/users/templates/users/change_password.html @@ -0,0 +1,39 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block title %}{% trans "Change password" %}{% endblock %} + + +{% block content %} + {% if form.non_field_errors %} + <div class="messages"> + <ul> + {% for error in form.non_field_errors %} + <li class="error">{{ error }}</li> + {% endfor %} + </ul> + </div> + {% endif %} + + {% if form.errors %} + <div class="messages"> + {% blocktrans count counter=form.errors.items|length %} + Please correct the error below. + {% plural %} + Please correct the errors below. + {% endblocktrans %} + </div> + {% endif %} + + <form action="{% url 'users:password_change' %}" method="POST" novalidate> + {% csrf_token %} + + {% for field in form %} + {{ field.errors }} + {{ field.label_tag }} + {{ field }} + {% endfor %} + + <button type="submit">{% trans 'Reset password' %}</button> + </form> +{% endblock %} diff --git a/opentech/apply/users/templates/users/password_reset/complete.html b/opentech/apply/users/templates/users/password_reset/complete.html new file mode 100644 index 0000000000000000000000000000000000000000..00740fd926d8ee3539dabbe12f556a5bfd0b9a84 --- /dev/null +++ b/opentech/apply/users/templates/users/password_reset/complete.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block title %}{% trans "Reset password" %}{% endblock %} {% block content %} + <h1>{% trans "Password change successful" %}</h1> + <p> + <a href="{% url 'users:login' %}">{% trans "Log in" %}</a> + </p> +{% endblock %} diff --git a/opentech/apply/users/templates/users/password_reset/confirm.html b/opentech/apply/users/templates/users/password_reset/confirm.html new file mode 100644 index 0000000000000000000000000000000000000000..6371c4593494ca9a49e6bae1d0523b4965e9527a --- /dev/null +++ b/opentech/apply/users/templates/users/password_reset/confirm.html @@ -0,0 +1,25 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} + <form method="post" novalidate> + {% csrf_token %} + <h1>{% trans "Set your new password" %}</h1> + + <ul class="fields"> + <li> + <div class="field"> + {{ form.new_password1.label_tag }} {{ form.new_password1 }} + </div> + </li> + <li> + <div class="field"> + {{ form.new_password2.label_tag }} {{ form.new_password2 }} + </div> + </li> + <li class="submit"> + <button type="submit">{% trans 'Reset password' %}</button> + </li> + </ul> + </form> +{% endblock %} diff --git a/opentech/apply/users/templates/users/password_reset/done.html b/opentech/apply/users/templates/users/password_reset/done.html new file mode 100644 index 0000000000000000000000000000000000000000..8773bd7acb1b6669ca18489f65aa05c6160c9905 --- /dev/null +++ b/opentech/apply/users/templates/users/password_reset/done.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block title %}{% trans "Reset password" %}{% endblock %} + +{% block content %} + <h1>{% trans "Check your email" %}</h1> + <p>{% trans "A link to reset your password has been emailed to you." %}</p> +{% endblock %} diff --git a/opentech/apply/users/templates/users/password_reset/email.txt b/opentech/apply/users/templates/users/password_reset/email.txt new file mode 100644 index 0000000000000000000000000000000000000000..30d6aa5aa9ad5f0525d97894a2e11b8e4dbd7c53 --- /dev/null +++ b/opentech/apply/users/templates/users/password_reset/email.txt @@ -0,0 +1,7 @@ +{% load i18n wagtailadmin_tags %}{% base_url_setting as base_url %} +{% trans "Please follow the link below to reset your password:" %} +{% if base_url %}{{ base_url }}{% else %}{{ protocol }}://{{ domain }}{% endif %}{% url 'users:password_reset_confirm' uidb64=uid token=token %} + +{% if user.USERNAME_FIELD != "email" %} +{% trans "Your username (in case you've forgotten):" %} {{ user.get_username }} +{% endif %} diff --git a/opentech/apply/users/templates/users/password_reset/form.html b/opentech/apply/users/templates/users/password_reset/form.html new file mode 100644 index 0000000000000000000000000000000000000000..e75567ab59e313c9a4715da9b782351b03cacd3a --- /dev/null +++ b/opentech/apply/users/templates/users/password_reset/form.html @@ -0,0 +1,25 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block title %}{% trans "Reset password" %}{% endblock %} + + +{% block content %} + {% if form.non_field_errors %} + <div class="messages"> + <ul> + {% for error in form.non_field_errors %} + <li class="error">{{ error }}</li> + {% endfor %} + </ul> + </div> + {% endif %} + + <form method="post"> + {% csrf_token %} + {{ form.email.label_tag }} + {{ form.email }} + + <button type="submit">{% trans 'Reset password' %}</button> + </form> +{% endblock %} diff --git a/opentech/apply/users/urls.py b/opentech/apply/users/urls.py index 0185992fa6f5f2f327ac83fbd46abfdb7c4e5c8f..4942e2dada305c2d44cd8b4df19f80b9d882ab6b 100644 --- a/opentech/apply/users/urls.py +++ b/opentech/apply/users/urls.py @@ -1,16 +1,56 @@ from django.conf.urls import url - from django.contrib.auth import views as auth_views +from django.urls import reverse_lazy + +from opentech.apply.users.views import account urlpatterns = [ - # TODO replace with dashboard view with a login_required decorator - url(r'^$', auth_views.login, { - 'template_name': 'users/login.html' - }, name='user'), - url(r'^login$', auth_views.login, { - 'template_name': 'users/login.html' - }, name='login'), + url(r'^$', account, name='account'), + url( + r'^login/$', + auth_views.LoginView.as_view( + template_name='users/login.html', + redirect_authenticated_user=True + ), + name='login' + ), # Log out - url(r'^logout/$', auth_views.logout, {'next_page': '/'}, name='logout'), + url(r'^logout/$', auth_views.LogoutView.as_view(next_page='/'), name='logout'), + + # Password change + url( + r'^password/$', + auth_views.PasswordChangeView.as_view( + template_name="users/change_password.html", + success_url=reverse_lazy('users:account') + ), + name='password_change', + ), + + # Password reset + url(r'^reset/$', auth_views.PasswordResetView.as_view( + template_name='users/password_reset/form.html', + email_template_name='users/password_reset/email.txt', + success_url=reverse_lazy('users:password_reset_done') + )), + url( + r'^reset/done/$', + auth_views.PasswordResetDoneView.as_view(template_name='users/password_reset/done.html'), + name='password_reset_done' + ), + url( + r'^reset/confirm/(?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( + template_name='users/password_reset/confirm.html', + post_reset_login=True, + success_url=reverse_lazy('users:account') + ), + name='password_reset_confirm' + ), + url( + r'^reset/complete/$', + auth_views.PasswordResetCompleteView.as_view(template_name='users/password_reset/complete.html'), + name='password_reset_complete' + ), ] diff --git a/opentech/apply/users/views.py b/opentech/apply/users/views.py index f4f3c02cd9caaa6853a8e00baf606135d4a5edd8..c531b183ae221c1441c401f0f17f36ff2fe32980 100644 --- a/opentech/apply/users/views.py +++ b/opentech/apply/users/views.py @@ -1 +1,14 @@ -# Views placeholder. +from django.contrib.auth.decorators import login_required +from django.shortcuts import render +from django.urls import reverse_lazy + +from wagtail.wagtailadmin.views.account import password_management_enabled + + +@login_required(login_url=reverse_lazy('users:login')) +def account(request): + "Account page placeholder view" + + return render(request, 'users/account.html', { + 'show_change_password': password_management_enabled() and request.user.has_usable_password(), + }) diff --git a/opentech/settings/base.py b/opentech/settings/base.py index 5aaf1a75957fd821d8260707e8c2c7982ee6919b..2693c88cb6f15773507c3866d5e099a9c793f205 100644 --- a/opentech/settings/base.py +++ b/opentech/settings/base.py @@ -181,6 +181,7 @@ MEDIA_URL = '/media/' AUTH_USER_MODEL = 'users.User' # TODO populate me with the dashboard URL when ready +LOGIN_URL = 'users:login' LOGIN_REDIRECT_URL = '/' # Logging