Add a user password change form.

This commit is contained in:
Christopher Charbonneau Wells 2017-12-02 16:20:15 -05:00
parent cd91f66d6a
commit 0c57e21c02
6 changed files with 77 additions and 3 deletions

View File

@ -2,6 +2,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django import forms from django import forms
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth.models import User from django.contrib.auth.models import User
from .models import Settings from .models import Settings
@ -13,6 +14,11 @@ class UserForm(forms.ModelForm):
fields = ['first_name', 'last_name', 'email'] fields = ['first_name', 'last_name', 'email']
class UserPasswordForm(PasswordChangeForm):
class Meta:
fields = ['old_password', 'new_password1', 'new_password2']
class UserSettingsForm(forms.ModelForm): class UserSettingsForm(forms.ModelForm):
class Meta: class Meta:
model = Settings model = Settings

View File

@ -175,6 +175,7 @@
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="nav-user-menu-link"> <div class="dropdown-menu dropdown-menu-right" aria-labelledby="nav-user-menu-link">
<h6 class="dropdown-header">User</h6> <h6 class="dropdown-header">User</h6>
<a href="{% url 'user-settings' %}" class="dropdown-item">Settings</a> <a href="{% url 'user-settings' %}" class="dropdown-item">Settings</a>
<a href="{% url 'user-password' %}" class="dropdown-item">Password</a>
<a href="{% url 'logout' %}" class="dropdown-item">Logout</a> <a href="{% url 'logout' %}" class="dropdown-item">Logout</a>
<h6 class="dropdown-header">Site</h6> <h6 class="dropdown-header">Site</h6>
<a href="{% url 'api:api-root' %}" <a href="{% url 'api:api-root' %}"

View File

@ -0,0 +1,14 @@
{% extends 'babybuddy/page.html' %}
{% load widget_tweaks %}
{% block title %}Change Password{% endblock %}
{% block breadcrumbs %}
<li class="breadcrumb-item">User</li>
<li class="breadcrumb-item active">Change Password</li>
{% endblock %}
{% block content %}
<h1>Change Password</h1>
{% include 'babybuddy/form.html' %}
{% endblock %}

View File

@ -27,9 +27,37 @@ class FormsTestCase(TestCase):
cls.user = User.objects.create_user( cls.user = User.objects.create_user(
is_superuser=True, **cls.credentials) is_superuser=True, **cls.credentials)
cls.c.login(**cls.credentials) def test_change_password(self):
self.c.login(**self.credentials)
page = self.c.get('/user/password/')
self.assertEqual(page.status_code, 200)
params = {
'old_password': 'wrong',
'new_password1': 'mynewpassword',
'new_password2': 'notmynewpassword'
}
page = self.c.post('/user/password/', params)
self.assertEqual(page.status_code, 200)
self.assertFormError(page, 'form', 'old_password',
'Your old password was entered incorrectly. '
'Please enter it again.')
params['old_password'] = self.credentials['password']
page = self.c.post('/user/password/', params)
self.assertEqual(page.status_code, 200)
self.assertFormError(page, 'form', 'new_password2',
"The two password fields didn't match.")
params['new_password2'] = 'mynewpassword'
page = self.c.post('/user/password/', params)
self.assertEqual(page.status_code, 302)
def test_user_settings(self): def test_user_settings(self):
self.c.login(**self.credentials)
params = { params = {
'first_name': 'User', 'first_name': 'User',
'last_name': 'Name', 'last_name': 'Name',

View File

@ -21,6 +21,8 @@ urlpatterns = [
url(r'^welcome/$', views.Welcome.as_view(), name='welcome'), url(r'^welcome/$', views.Welcome.as_view(), name='welcome'),
url(r'^user/settings/$', views.UserSettings.as_view(), url(r'^user/settings/$', views.UserSettings.as_view(),
name='user-settings'), name='user-settings'),
url(r'^user/password/$', views.UserPassword.as_view(),
name='user-password'),
url(r'', include('api.urls', namespace='api')), url(r'', include('api.urls', namespace='api')),
url(r'', include('core.urls')), url(r'', include('core.urls')),
@ -28,7 +30,7 @@ urlpatterns = [
url(r'', include('reports.urls', namespace='reports')), url(r'', include('reports.urls', namespace='reports')),
] ]
if settings.DEBUG: if settings.DEBUG: # pragma: no cover
urlpatterns += static( urlpatterns += static(
settings.MEDIA_URL, settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT document_root=settings.MEDIA_ROOT

View File

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.urls import reverse from django.urls import reverse
@ -8,7 +10,7 @@ from django.urls import reverse
from django.views.generic import View from django.views.generic import View
from django.views.generic.base import TemplateView, RedirectView from django.views.generic.base import TemplateView, RedirectView
from .forms import UserForm, UserSettingsForm from .forms import UserForm, UserPasswordForm, UserSettingsForm
from core.models import Child from core.models import Child
@ -30,6 +32,27 @@ class RootRouter(LoginRequiredMixin, RedirectView):
return super(RootRouter, self).get_redirect_url(self, *args, **kwargs) return super(RootRouter, self).get_redirect_url(self, *args, **kwargs)
class UserPassword(LoginRequiredMixin, View):
"""
Handles user password changes.
"""
form_class = UserPasswordForm
template_name = 'babybuddy/user_password_form.html'
def get(self, request):
return render(request, self.template_name, {
'form': self.form_class(request.user)
})
def post(self, request):
form = PasswordChangeForm(request.user, request.POST)
if form.is_valid():
user = form.save()
update_session_auth_hash(request, user)
return redirect('/')
return render(request, self.template_name, {'form': form})
class UserSettings(LoginRequiredMixin, View): class UserSettings(LoginRequiredMixin, View):
""" """
Handles both the User and Settings models. Handles both the User and Settings models.