Add the possibility for users to change their own password

This functionality required to add a settings panel.
This commit is contained in:
Rodolphe Breard 2018-11-08 14:18:24 +01:00
parent 571a70162c
commit a0e80623cf
10 changed files with 170 additions and 18 deletions

View file

@ -41,6 +41,7 @@
<div class="navbar-item has-dropdown is-hoverable"> <div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">{% trans "my_account"|capfirst %}</a> <a class="navbar-link">{% trans "my_account"|capfirst %}</a>
<div class="navbar-dropdown"> <div class="navbar-dropdown">
<a class="navbar-item" href="{% url "settings" %}">{% trans "settings"|capfirst %}</a>
{% if user.is_superuser %} {% if user.is_superuser %}
<a class="navbar-item" href="{% url "admin:index" %}">{% trans "administration"|capfirst %}</a> <a class="navbar-item" href="{% url "admin:index" %}">{% trans "administration"|capfirst %}</a>
{% endif %} {% endif %}

View file

@ -1,5 +1,9 @@
from django.contrib.auth.password_validation import validate_password
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.forms import UserCreationForm
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
from django.contrib import messages
from django import forms
from .models import NelUser from .models import NelUser
@ -7,3 +11,27 @@ class RegistrationForm(UserCreationForm):
class Meta: class Meta:
model = NelUser model = NelUser
fields = (NelUser.EMAIL_FIELD,) fields = (NelUser.EMAIL_FIELD,)
class ChangePasswordForm(forms.Form):
current_password = forms.CharField(label=_('current_password'), widget=forms.PasswordInput)
new_password = forms.CharField(label=_('new_password'), widget=forms.PasswordInput)
new_password_confirm = forms.CharField(label=_('new_password_confirm'), widget=forms.PasswordInput)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
return super().__init__(*args, **kwargs)
def clean(self):
cleaned_data = super().clean()
old_pass = cleaned_data.get('current_password')
new_pass = cleaned_data.get('new_password')
new_pass_confirm = cleaned_data.get('new_password_confirm')
user = self.request.user
if new_pass != new_pass_confirm:
raise forms.ValidationError(_('The new password does not match its confirmation.'))
try:
validate_password(new_pass, user=user)
except ValidationError as error:
raise forms.ValidationError(error)
if not user.check_password(old_pass):
raise forms.ValidationError(_('The current password is incorrect.'))

View file

@ -2,7 +2,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 1.0\n" "Project-Id-Version: 1.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-03 23:12+0200\n" "POT-Creation-Date: 2018-11-08 14:17+0100\n"
"PO-Revision-Date: 2018-02-04 01:03+0100\n" "PO-Revision-Date: 2018-02-04 01:03+0100\n"
"Last-Translator: Khaganat <assoc@khaganat.net>\n" "Last-Translator: Khaganat <assoc@khaganat.net>\n"
"Language-Team: Khaganat <assoc@khaganat.net>\n" "Language-Team: Khaganat <assoc@khaganat.net>\n"
@ -12,6 +12,26 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:16
msgid "current_password"
msgstr "Please provide your current password"
#: forms.py:17
msgid "new_password"
msgstr "Please set a new password"
#: forms.py:18
msgid "new_password_confirm"
msgstr "Please confirm the new password"
#: forms.py:31
msgid "The new password does not match its confirmation."
msgstr ""
#: forms.py:37
msgid "The current password is incorrect."
msgstr ""
#: models.py:40 #: models.py:40
msgid "email" msgid "email"
msgstr "" msgstr ""
@ -120,6 +140,7 @@ msgid "set_new_password"
msgstr "Please set a new password" msgstr "Please set a new password"
#: templates/neluser/password_reset_confirm.html:13 #: templates/neluser/password_reset_confirm.html:13
#: templates/neluser/settings/security/password.html:11
msgid "change_my_password" msgid "change_my_password"
msgstr "change my password" msgstr "change my password"
@ -172,3 +193,11 @@ msgstr ""
#: templates/neluser/register_done.html:9 #: templates/neluser/register_done.html:9
msgid "take_me_home" msgid "take_me_home"
msgstr "Take me home" msgstr "Take me home"
#: templates/neluser/settings/base.html:8
msgid "security"
msgstr ""
#: templates/neluser/settings/security/password.html:5
msgid "Password"
msgstr ""

View file

@ -2,7 +2,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 1.0\n" "Project-Id-Version: 1.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-03 23:12+0200\n" "POT-Creation-Date: 2018-11-08 14:17+0100\n"
"PO-Revision-Date: 2018-02-04 01:03+0100\n" "PO-Revision-Date: 2018-02-04 01:03+0100\n"
"Last-Translator: Khaganat <assoc@khaganat.net>\n" "Last-Translator: Khaganat <assoc@khaganat.net>\n"
"Language-Team: Khaganat <assoc@khaganat.net>\n" "Language-Team: Khaganat <assoc@khaganat.net>\n"
@ -12,6 +12,26 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: forms.py:16
msgid "current_password"
msgstr "Veuillez indiquer votre mot de passe actuel"
#: forms.py:17
msgid "new_password"
msgstr "Veuillez indiquer un nouveau mot de passe"
#: forms.py:18
msgid "new_password_confirm"
msgstr "Veuillez confirmer le nouveau mot de passe"
#: forms.py:31
msgid "The new password does not match its confirmation."
msgstr "Le nouveau mot de passe ne correspond pas avec sa confirmation."
#: forms.py:37
msgid "The current password is incorrect."
msgstr "Le mot de passe actuel est incorrect."
#: models.py:40 #: models.py:40
msgid "email" msgid "email"
msgstr "adresse électronique" msgstr "adresse électronique"
@ -122,6 +142,7 @@ msgid "set_new_password"
msgstr "Veuillez indiquer un nouveau mot de passe" msgstr "Veuillez indiquer un nouveau mot de passe"
#: templates/neluser/password_reset_confirm.html:13 #: templates/neluser/password_reset_confirm.html:13
#: templates/neluser/settings/security/password.html:11
msgid "change_my_password" msgid "change_my_password"
msgstr "Modifier mon mot de passe" msgstr "Modifier mon mot de passe"
@ -178,6 +199,14 @@ msgstr ""
msgid "take_me_home" msgid "take_me_home"
msgstr "Retour à l'accueil" msgstr "Retour à l'accueil"
#: templates/neluser/settings/base.html:8
msgid "security"
msgstr "sécurité"
#: templates/neluser/settings/security/password.html:5
msgid "Password"
msgstr "Mot de passe"
#~ msgid "NSFW content" #~ msgid "NSFW content"
#~ msgstr "Contenu sensible" #~ msgstr "Contenu sensible"

View file

@ -0,0 +1,13 @@
{% extends "khaganat/base.html" %}
{% load bulma_tags %}
{% load i18n %}
{% block content %}
<div class="tabs">
<ul>
<!-- {% trans "security" %} -->
{% include "neluser/settings/tab.html" with tabname="security" lnk="password_change" %}
</ul>
</div>
{% block pannel %}{% endblock %}
{% endblock %}

View file

@ -0,0 +1,5 @@
{% extends "neluser/settings/base.html" %}
{% block pannel %}
{% block inner_pannel %}{% endblock %}
{% endblock %}

View file

@ -0,0 +1,13 @@
{% extends "neluser/settings/security/base.html" %}
{% load bulma_tags %}
{% load i18n %}
{% block title %}{% trans "Password"|capfirst %}{% endblock %}
{% block inner_pannel %}
<form action="" method="post">
{% csrf_token %}
{{ form|bulma }}
<button type="submit" class="button is-link">{% trans "change_my_password"|capfirst %}</button>
</form>
{% endblock %}

View file

@ -0,0 +1,5 @@
{% load i18n %}
<li{% if tab == tabname %} class="is-active"{% endif %}>
<a href="{% url lnk %}">{% trans tabname|capfirst %}</a>
</li>

View file

@ -4,7 +4,7 @@ from . import views
urlpatterns = [ urlpatterns = [
# login/logout # Login and logout
path( path(
'login/', 'login/',
auth_views.LoginView.as_view(template_name='neluser/login.html'), auth_views.LoginView.as_view(template_name='neluser/login.html'),
@ -16,20 +16,11 @@ urlpatterns = [
name='logout' name='logout'
), ),
# account activation # Account activation
path('register/', views.register, name='register'), path('register/', views.register, name='register'),
path('activate/<uidb64>/<token>/', views.activate, name='activate'), path('activate/<uidb64>/<token>/', views.activate, name='activate'),
# settings # Forgotten password
path('settings/', views.profile, name='settings'),
path('settings/password/', views.profile, name='password_change'),
path(
'settings/password/change/done/',
views.profile,
name='password_change_done'
),
# forgotten_password
path( path(
'forgotten_password/', 'forgotten_password/',
auth_views.PasswordResetView.as_view( auth_views.PasswordResetView.as_view(
@ -61,4 +52,12 @@ urlpatterns = [
), ),
name='password_reset_complete' name='password_reset_complete'
), ),
# --------
# Settings
# --------
path('settings/', views.settings_default, name='settings'),
# Security
path('settings/security/password/', views.ChangePasswordView.as_view(), name='password_change'),
] ]

View file

@ -1,18 +1,48 @@
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.shortcuts import render, get_object_or_404 from django.shortcuts import redirect, render, get_object_or_404
from django.contrib.auth.tokens import default_token_generator from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.shortcuts import get_current_site from django.contrib.sites.shortcuts import get_current_site
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.core.mail import EmailMultiAlternatives from django.core.mail import EmailMultiAlternatives
from django.views.generic.edit import FormView
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
from django.conf import settings from django.conf import settings
from .forms import RegistrationForm from django.urls import reverse_lazy
from .forms import RegistrationForm, ChangePasswordForm
from .models import NelUser from .models import NelUser
def profile(request): @login_required
return HttpResponse('<h1>lol</h1>') def settings_default(request):
next_page = reverse_lazy('password_change')
return redirect(next_page)
class ChangePasswordView(LoginRequiredMixin, FormView):
template_name = 'neluser/settings/security/password.html'
form_class = ChangePasswordForm
success_url = reverse_lazy('password_change')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['tab'] = 'security'
context['block'] = 'password'
return context
def get_form_kwargs(self):
kw = super().get_form_kwargs()
kw['request'] = self.request
return kw
def form_valid(self, form):
new_password = form.cleaned_data['new_password']
user = self.request.user
user.set_password(new_password)
user.save()
return super().form_valid(form)
def send_activation_email(request, user): def send_activation_email(request, user):