From 7c1d4e23ea3a07fe547e10141d19b14b387714a6 Mon Sep 17 00:00:00 2001 From: Dorian Lesbre <dorian.lesbre@gmail.com> Date: Mon, 8 Mar 2021 18:29:12 +0100 Subject: [PATCH] Added password reset option --- .../activation.html} | 3 ++ .../{change_email.html => email/change.html} | 3 ++ accounts/templates/email/password_reset.html | 10 +++++ accounts/templates/email/password_reset.txt | 1 + accounts/templates/login.html | 4 +- accounts/templates/password_reset.html | 15 +++++++ .../templates/password_reset_confirm.html | 23 ++++++++++ accounts/tokens.py | 2 +- accounts/urls.py | 6 +++ accounts/views.py | 44 ++++++++++++++++--- interludes/settings.py | 5 ++- 11 files changed, 107 insertions(+), 9 deletions(-) rename accounts/templates/{activation_email.html => email/activation.html} (90%) rename accounts/templates/{change_email.html => email/change.html} (90%) create mode 100644 accounts/templates/email/password_reset.html create mode 100644 accounts/templates/email/password_reset.txt create mode 100644 accounts/templates/password_reset.html create mode 100644 accounts/templates/password_reset_confirm.html diff --git a/accounts/templates/activation_email.html b/accounts/templates/email/activation.html similarity index 90% rename from accounts/templates/activation_email.html rename to accounts/templates/email/activation.html index 16b2d3a..475f3d9 100644 --- a/accounts/templates/activation_email.html +++ b/accounts/templates/email/activation.html @@ -4,4 +4,7 @@ Bonjour {{ user.first_name }} {{ user.last_name }}, Veuillez suivre le lien ci-dessous pour valider votre compte : http://{{ domain }}{% url 'accounts:activate' uidb64=uid token=token %} + +-- +L'équipe Interludes {% endautoescape %} diff --git a/accounts/templates/change_email.html b/accounts/templates/email/change.html similarity index 90% rename from accounts/templates/change_email.html rename to accounts/templates/email/change.html index 1e2a2b0..4aa492d 100644 --- a/accounts/templates/change_email.html +++ b/accounts/templates/email/change.html @@ -4,4 +4,7 @@ Bonjour {{ user.first_name }} {{ user.last_name }}, Veuillez suivre le lien ci dessous pour valider le changement d'adresse email : http://{{ domain }}{% url 'accounts:activate' uidb64=uid token=token %} + +-- +L'équipe Interludes {% endautoescape %} diff --git a/accounts/templates/email/password_reset.html b/accounts/templates/email/password_reset.html new file mode 100644 index 0000000..d6740c2 --- /dev/null +++ b/accounts/templates/email/password_reset.html @@ -0,0 +1,10 @@ +{% autoescape off %} +Bonjour {{ user.first_name }} {{ user.last_name }}, + +Pour réinitialiser votre mot de passe sur le site interludes, veuillez suivre le lien suivant : + +{{ protocol }}://{{ domain }}{% url 'accounts:password_reset_confirm' uidb64=uid token=token %} + +-- +L'équipe Interludes +{% endautoescape %} \ No newline at end of file diff --git a/accounts/templates/email/password_reset.txt b/accounts/templates/email/password_reset.txt new file mode 100644 index 0000000..002315a --- /dev/null +++ b/accounts/templates/email/password_reset.txt @@ -0,0 +1 @@ +Mot de passe oublié site Interludes \ No newline at end of file diff --git a/accounts/templates/login.html b/accounts/templates/login.html index 249ac46..1976409 100644 --- a/accounts/templates/login.html +++ b/accounts/templates/login.html @@ -33,8 +33,8 @@ <td>{{ form.password }}</td> </tr> </table> - <br> - + <a href="{% url 'accounts:password_reset' %}">Mot de passe oublié ?</a> + <br><br> <div class="flex"> <input type="submit" value="Connexion"> {% if settings.registrations_open %} diff --git a/accounts/templates/password_reset.html b/accounts/templates/password_reset.html new file mode 100644 index 0000000..a1a6ebc --- /dev/null +++ b/accounts/templates/password_reset.html @@ -0,0 +1,15 @@ +{% extends 'base.html' %} + +{% block "content" %} + <h2>Mot de passe oublié ?</h2> + <p>Saissisez votre adresse email ci-dessous pour recevoir un lien de réinitialisation du mot de passe.</p> + + <form method="POST"> + {% csrf_token %} + {{ form.as_p }} + <div class="flex"> + <input type="submit" value="Valider"> + <a class="button" href="{% url 'accounts:login' %}">Annuler</a> + </div> + </form> +{% endblock %} diff --git a/accounts/templates/password_reset_confirm.html b/accounts/templates/password_reset_confirm.html new file mode 100644 index 0000000..f7e901e --- /dev/null +++ b/accounts/templates/password_reset_confirm.html @@ -0,0 +1,23 @@ +{% extends 'base.html' %} + +{% block "content" %} + +{% if validlink %} + +<h2>Saissisez un nouveau mot de passe</h2> +<form method="POST"> + {% csrf_token %} + {{ form.as_p }} + <input type="submit" value="Change my password"> +</form> + +{% else %} + +<h2>Lien invalide</h2> + +<p>Le lien de réinitialisation est invalide, peut-être a-t-il déjà été utilisé. + Veuillez <a href="{% url 'accounts:password_reset' %}">demander un nouveau lien</a>. +</p> + +{% endif %} +{% endblock %} \ No newline at end of file diff --git a/accounts/tokens.py b/accounts/tokens.py index ce2abb2..4b1f76b 100644 --- a/accounts/tokens.py +++ b/accounts/tokens.py @@ -12,7 +12,7 @@ class EmailVerificationTokenGenerator: Strategy object used to generate and check tokens for the email verification mechanism. """ - key_salt = "shared.EmailVerificationTokenGenerator" + key_salt = "accounts.EmailVerificationTokenGenerator" secret = settings.SECRET_KEY def make_token(self, user): diff --git a/accounts/urls.py b/accounts/urls.py index fd0184a..518cadb 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -12,4 +12,10 @@ urlpatterns = [ path("update/", views.UpdateAccountView.as_view(), name="update"), path("change_password/", views.UpdatePasswordView.as_view(), name="change_password"), path('activate/<uidb64>/<token>/', views.ActivateAccountView.as_view(), name='activate'), + path("password_reset/", views.ResetPasswordView.as_view(), name="password_reset"), + path( + "password_reset/<uidb64>/<token>/", + views.ResetPasswordConfirmView.as_view(), + name="password_reset_confirm" + ), ] diff --git a/accounts/views.py b/accounts/views.py index 6e72ce0..a1aaafa 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,12 +1,12 @@ from django.contrib import messages from django.contrib.auth import login, logout from django.contrib.auth.mixins import LoginRequiredMixin -from django.contrib.auth.views import LoginView as DjangoLoginView +from django.contrib.auth import views as auth_views from django.contrib.sites.shortcuts import get_current_site from django.http import Http404 from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode -from django.urls import reverse +from django.urls import reverse, reverse_lazy from django.template.loader import render_to_string from django.views.generic import FormView, RedirectView, TemplateView, UpdateView, View from django.shortcuts import render, redirect @@ -28,7 +28,7 @@ def send_validation_email(request, user, subject, template): user.email_user(subject, message) -class LoginView(DjangoLoginView): +class LoginView(auth_views.LoginView): """Vue pour se connecter""" template_name = "login.html" redirect_authenticated_user = "accounts:profile" @@ -57,6 +57,7 @@ class CreateAccountView(View): """Vue pour la creation de compte""" form_class = CreateAccountForm template_name = 'create_account.html' + email_template = 'email/activation.html' @staticmethod def check_creation_allowed(): @@ -85,7 +86,7 @@ class CreateAccountView(View): user.email_confirmed = False user.save() - send_validation_email(request, user, "Activer votre compte Interludes", "activation_email.html") + send_validation_email(request, user, "Activer votre compte Interludes", self.email_template) messages.info(request, 'Un lien vous a été envoyé par mail. Utilisez le pour finaliser la création de compte.') @@ -125,10 +126,16 @@ class ActivateAccountView(RedirectView): return reverse(self.success_pattern_name) +# ============================== +# Update personal info +# ============================== + + class UpdateAccountView(LoginRequiredMixin, UpdateView): """Vue pour la mise à jour des infos personnelles""" template_name = "update.html" form_class = UpdateAccountForm + email_template = "email/change.html" def get_object(self): return self.request.user @@ -146,7 +153,7 @@ class UpdateAccountView(LoginRequiredMixin, UpdateView): send_validation_email( self.request, self.request.user, "Valider le changement d'email de votre compte Interludes", - "change_email.html" + self.email_template ) messages.info(self.request, 'Un lien vous a été envoyé par mail. Utilisez le pour valider la mise à jour.') @@ -181,3 +188,30 @@ class UpdatePasswordView(LoginRequiredMixin, FormView): messages.success(self.request, "Mot de passe mis à jour") login(self.request, self.request.user) return redirect("accounts:profile") + + +# ============================== +# Reset password +# ============================== + + +class ResetPasswordView(auth_views.PasswordResetView): + """Vue pour le gestion du mot de passe oublié""" + email_template_name = 'email/password_reset.html' + subject_template_name = 'email/password_reset.txt' + success_url = reverse_lazy('accounts:login') + template_name = 'password_reset.html' + + def form_valid(self, form): + messages.info(self.request, "Un email vous a été envoyé avec un lien de réinitialisation") + return super().form_valid(form) + + +class ResetPasswordConfirmView(auth_views.PasswordResetConfirmView): + """Vue demandant de saisir un nouveau mot de passe""" + success_url = reverse_lazy('accounts:login') + template_name = "password_reset_confirm.html" + + def form_valid(self, form): + messages.success(self.request, "Votre mot de passe a été enregistré") + return super().form_valid(form) diff --git a/interludes/settings.py b/interludes/settings.py index d9009f9..25e9b60 100644 --- a/interludes/settings.py +++ b/interludes/settings.py @@ -114,6 +114,8 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] +# Session time in seconds +SESSION_COOKIE_AGE = 3600 # Internationalization # https://docs.djangoproject.com/en/3.0/topics/i18n/ @@ -138,5 +140,6 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'static') LOGIN_URL = "accounts:login" LOGIN_REDIRECT_URL = "accounts:profile" -# This will display email in Console. +# This will display emails in Console. +# FIXME: remove in production EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' -- GitLab