From 3c9c26809188cb2632f1415ef9acf215715b4f71 Mon Sep 17 00:00:00 2001
From: Dorian Lesbre <dorian.lesbre@gmail.com>
Date: Tue, 9 Mar 2021 18:50:15 +0100
Subject: [PATCH] Fix #4

---
 accounts/forms.py  | 24 +++++++++++++++++-------
 accounts/models.py |  3 ++-
 accounts/views.py  | 14 ++++++++------
 shared/models.py   |  6 ++++--
 4 files changed, 31 insertions(+), 16 deletions(-)

diff --git a/accounts/forms.py b/accounts/forms.py
index 6c1189a..3974a42 100644
--- a/accounts/forms.py
+++ b/accounts/forms.py
@@ -1,10 +1,11 @@
 from django import forms
 from django.contrib.auth import authenticate, password_validation
-from django.contrib.auth.forms import UserCreationForm
+from django.contrib.auth.forms import AuthenticationForm, UserCreationForm, PasswordResetForm
 from django.utils.safestring import mark_safe
 
 from accounts.models import EmailUser
 from shared.forms import FormRenderMixin
+from shared.models import normalize_email
 
 def password_criterions_html():
 	"""Wraps password criterions into nice html used by other forms"""
@@ -22,6 +23,13 @@ def password_criterions_html():
 	return mark_safe(criterions_html)
 
 
+class LoginForm(AuthenticationForm):
+	"""Form used when loging in"""
+	def clean(self, *args, **kwargs):
+		self.cleaned_data["username"] = normalize_email(self.cleaned_data.get("username"))
+		return super().clean(*args, **kwargs)
+
+
 class CreateAccountForm(FormRenderMixin, UserCreationForm):
 	"""Form used to register a new user"""
 	class Meta:
@@ -36,17 +44,12 @@ class UpdateAccountForm(FormRenderMixin, forms.ModelForm):
 		fields = ('email', 'first_name', 'last_name')
 		help_texts = {"email": "Si vous la changez, il faudra confirmer la nouvelle adresse",}
 
-	@staticmethod
-	def normalize_email(email):
-		""" Returns a normalized email """
-		return email.lower()
-
 	def clean_email(self):
 		""" Check email uniqueness """
 		email = self.cleaned_data["email"]
 		if email == self.instance.email:
 				return email
-		norm_email = self.normalize_email(email)
+		norm_email = normalize_email(email)
 		if EmailUser.objects.filter(email=norm_email).count() > 0:
 			raise forms.ValidationError(
 					"Un autre compte avec cette adresse mail existe déjà."
@@ -112,3 +115,10 @@ class UpdatePasswordForm(FormRenderMixin, forms.Form):
 		""" Apply the password change, assuming validation was already passed """
 		self.user.set_password(self.cleaned_data["password"])
 		self.user.save()
+
+
+class PasswordResetEmailForm(PasswordResetForm):
+	"""Form used when asking email to send password reset linkk"""
+	def clean(self, *args, **kwargs):
+		self.cleaned_data["email"] = normalize_email(self.cleaned_data.get("email"))
+		return super().clean(*args, **kwargs)
diff --git a/accounts/models.py b/accounts/models.py
index 150a868..17a4cc3 100644
--- a/accounts/models.py
+++ b/accounts/models.py
@@ -2,6 +2,7 @@ from django.db import models
 from django.contrib.auth.base_user import BaseUserManager
 from django.contrib.auth.models import AbstractUser
 
+from shared.models import normalize_email
 
 class EmailUserManager(BaseUserManager):
 	"""User model manager that replaces username with email"""
@@ -9,7 +10,7 @@ class EmailUserManager(BaseUserManager):
 		"""Create and save a User with the given email and password."""
 		if not email:
 			raise ValueError("Creating user with no email")
-		email = self.normalize_email(email)
+		email = normalize_email(email)
 		user = self.model(email=email, **extra_fields)
 		user.set_password(password)
 		user.save()
diff --git a/accounts/views.py b/accounts/views.py
index 9da367c..14047c0 100644
--- a/accounts/views.py
+++ b/accounts/views.py
@@ -11,7 +11,7 @@ from django.template.loader import render_to_string
 from django.views.generic import FormView, RedirectView, TemplateView, UpdateView, View
 from django.shortcuts import render, redirect
 
-from accounts.forms import CreateAccountForm, UpdateAccountForm, UpdatePasswordForm
+from accounts import forms
 from accounts.models import EmailUser
 from accounts.tokens import email_token_generator
 from home.models import ActivityList
@@ -33,6 +33,7 @@ class LoginView(auth_views.LoginView):
 	"""Vue pour se connecter"""
 	template_name = "login.html"
 	redirect_authenticated_user = "accounts:profile"
+	form_class = forms.LoginForm
 
 
 class LogoutView(RedirectView):
@@ -71,7 +72,7 @@ class ProfileView(LoginRequiredMixin, TemplateView):
 
 class CreateAccountView(View):
 	"""Vue pour la creation de compte"""
-	form_class = CreateAccountForm
+	form_class = forms.CreateAccountForm
 	template_name = 'create_account.html'
 	email_template = 'email/activation.html'
 
@@ -150,7 +151,7 @@ class ActivateAccountView(RedirectView):
 class UpdateAccountView(LoginRequiredMixin, UpdateView):
 	"""Vue pour la mise à jour des infos personnelles"""
 	template_name = "update.html"
-	form_class = UpdateAccountForm
+	form_class = forms.UpdateAccountForm
 	email_template = "email/change.html"
 
 	def get_object(self):
@@ -159,7 +160,7 @@ class UpdateAccountView(LoginRequiredMixin, UpdateView):
 	def get_context_data(self, **kwargs):
 		context = super().get_context_data(**kwargs)
 		context["update_form"] = context["form"]
-		context["password_form"] = UpdatePasswordForm(
+		context["password_form"] = forms.UpdatePasswordForm(
 			user=self.request.user
 		)
 		return context
@@ -186,12 +187,12 @@ class UpdatePasswordView(LoginRequiredMixin, FormView):
 	""" Change a user's password """
 
 	template_name = "update.html"
-	form_class = UpdatePasswordForm
+	form_class = forms.UpdatePasswordForm
 
 	def get_context_data(self, **kwargs):
 		context = super().get_context_data(**kwargs)
 		context["password_form"] = context["form"]
-		context["update_form"] = UpdateAccountForm(instance=self.request.user)
+		context["update_form"] = forms.UpdateAccountForm(instance=self.request.user)
 		return context
 
 	def get_form_kwargs(self):
@@ -217,6 +218,7 @@ class ResetPasswordView(auth_views.PasswordResetView):
 	subject_template_name = 'email/password_reset.txt'
 	success_url = reverse_lazy('accounts:login')
 	template_name = 'password_reset.html'
+	form_class = forms.PasswordResetEmailForm
 
 	def form_valid(self, form):
 		messages.info(self.request, "Un email vous a été envoyé avec un lien de réinitialisation")
diff --git a/shared/models.py b/shared/models.py
index 71a8362..07b2863 100644
--- a/shared/models.py
+++ b/shared/models.py
@@ -1,3 +1,5 @@
-from django.db import models
+from django.contrib.auth.base_user import BaseUserManager
 
-# Create your models here.
+def normalize_email(email: str) -> str:
+	"""Normalizes an email address"""
+	return BaseUserManager.normalize_email(email)
-- 
GitLab