From 35f1b0af7e8adca35aca894b7a95b04c16b46e70 Mon Sep 17 00:00:00 2001
From: Dorian Lesbre <dorian.lesbre@gmail.com>
Date: Sat, 6 Mar 2021 10:12:54 +0100
Subject: [PATCH] Added option to update account info

---
 accounts/admin.py               |  2 +-
 accounts/forms.py               | 39 ++++++++++++++++++++++++++--
 accounts/templates/profile.html |  2 +-
 accounts/templates/update.html  | 12 +++++++++
 accounts/urls.py                |  1 +
 accounts/views.py               | 46 ++++++++++++++++++++++++++-------
 6 files changed, 88 insertions(+), 14 deletions(-)
 create mode 100644 accounts/templates/update.html

diff --git a/accounts/admin.py b/accounts/admin.py
index f9e5b89..0558e42 100644
--- a/accounts/admin.py
+++ b/accounts/admin.py
@@ -12,7 +12,7 @@ class EmailUserAdmin(admin.ModelAdmin):
 	list_display = ("email", "last_name", "first_name", "is_superuser", "is_active", "email_confirmed",)
 	list_filter = ("is_superuser","is_active", "email_confirmed",)
 	list_editable = ("is_superuser","is_active")
-	fields = ("email", "last_name", "first_name", "is_superuser",
+	fields = ("email", "last_name", "first_name", "is_superuser", "is_active", "email_confirmed",
 		("date_joined", "last_login",),
 	)
 	ordering = ("last_name", "first_name")
diff --git a/accounts/forms.py b/accounts/forms.py
index ddbef68..345e9c9 100644
--- a/accounts/forms.py
+++ b/accounts/forms.py
@@ -1,9 +1,9 @@
+from django import forms
 from django.contrib.auth.forms import UserCreationForm
+from django.utils.safestring import mark_safe
 
 from accounts.models import EmailUser
 
-from django.utils.safestring import mark_safe
-
 
 class FormRenderMixin:
 	""" A mixin that can be included in any form to make it render to html as we want
@@ -131,3 +131,38 @@ class CreateAccountForm(FormRenderMixin, UserCreationForm):
 	class Meta:
 		model = EmailUser
 		fields = ('email', 'first_name', 'last_name', 'password1', 'password2',)
+
+class UpdateAccountForm(FormRenderMixin, forms.ModelForm):
+	"""Form used to update name/email"""
+	class Meta:
+		model = EmailUser
+		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)
+		if EmailUser.objects.filter(email=norm_email).count() > 0:
+			raise forms.ValidationError(
+					"Un autre compte avec cette adresse mail existe déjà."
+			)
+		return norm_email
+
+	def save(self, *args, commit=True, **kwargs):
+		email = self.cleaned_data["email"]
+		email_changed = email != self.instance.username
+		user = super().save(*args, commit=False, **kwargs)
+		user.username = email
+		if email_changed:
+			user.email_confirmed = False
+		if commit:
+			user.save()
+		return user
diff --git a/accounts/templates/profile.html b/accounts/templates/profile.html
index c814ad4..c2bfd73 100644
--- a/accounts/templates/profile.html
+++ b/accounts/templates/profile.html
@@ -14,7 +14,7 @@
 
 <p><a href="{% url 'inscription' %}">M'insrire à l'événement</a></p>
 
-<p><a href="TODO">Modifier mes informations</a></p>
+<p><a href="{% url 'accounts:update' %}">Modifier mes informations</a></p>
 
 <p><a href="TODO">Changer mom mot de passe</a></p>
 
diff --git a/accounts/templates/update.html b/accounts/templates/update.html
new file mode 100644
index 0000000..d3c41e8
--- /dev/null
+++ b/accounts/templates/update.html
@@ -0,0 +1,12 @@
+{% extends "base.html" %}
+
+{% block "content" %}
+	<h2>Changer mes informations</h2>
+
+	<form method="post" action="{% url 'accounts:update' %}">
+		{% csrf_token %}
+		{{ form.as_html }}
+		<br>
+		<input type="submit" value="Valider">
+	</form>
+{% endblock %}
diff --git a/accounts/urls.py b/accounts/urls.py
index 34f4b39..c59f5fc 100644
--- a/accounts/urls.py
+++ b/accounts/urls.py
@@ -9,5 +9,6 @@ urlpatterns = [
 	path("logout/", views.LogoutView.as_view(), name="logout"),
 	path("profile/", views.ProfileView.as_view(), name="profile"),
 	path("create/", views.CreateAccountView.as_view(), name="create"),
+	path("update/", views.UpdateAccountView.as_view(), name="update"),
 	path('activate/<uidb64>/<token>/', views.ActivateAccountView.as_view(), name='activate'),
 ]
diff --git a/accounts/views.py b/accounts/views.py
index 9c680b6..48c5499 100644
--- a/accounts/views.py
+++ b/accounts/views.py
@@ -8,10 +8,10 @@ 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.template.loader import render_to_string
-from django.views.generic import RedirectView, TemplateView, View
+from django.views.generic import RedirectView, TemplateView, UpdateView, View
 from django.shortcuts import render, redirect
 
-from accounts.forms import CreateAccountForm
+from accounts.forms import CreateAccountForm, UpdateAccountForm
 from accounts.models import EmailUser
 from accounts.tokens import email_token_generator
 from site_settings.models import SiteSettings
@@ -69,10 +69,11 @@ class CreateAccountView(View):
 		user = form.save()
 		user.is_active = False # can't login until email validation
 		user.email_confirmed = False
+		user.save()
 
 		current_site = get_current_site(request)
 		subject = 'Activation de votre compte Interludes'
-		message = render_to_string('registration/activation_email.html', {
+		message = render_to_string('activation_email.html', {
 			'user': user,
 			'domain': current_site.domain,
 			'uid': urlsafe_base64_encode(force_bytes(user.pk)),
@@ -80,9 +81,7 @@ class CreateAccountView(View):
 		})
 		user.email_user(subject, message)
 
-		user.save()
-
-		messages.success(request, ('Please Confirm your email to complete registration.'))
+		messages.info(request, 'Un lien vous a été envoyé par mail. Utilisez le pour finaliser la création de compte.')
 
 		return redirect('accounts:login')
 
@@ -90,6 +89,8 @@ class CreateAccountView(View):
 class ActivateAccountView(RedirectView):
 	"""Vue d'activation de compte (lien envoyé par mail)"""
 	permanent = False
+	success_pattern_name = "accounts:profile"
+	failure_pattern_name = "home"
 
 	def get_redirect_url(self, uidb64, token, *args, **kwargs):
 		try:
@@ -101,18 +102,43 @@ class ActivateAccountView(RedirectView):
 				"Le lien de confirmation d'adresse mail ne correspond à aucun·e "
 				"utilisateur·ice inscrit·e",
 			)
-			return reverse("home")
+			return reverse(self.failure_pattern_name)
 
 		if not email_token_generator.check_token(user, token):
 			messages.error(
 				self.request,
 				"Le lien de confirmation d'adresse mail est invalide ou déjà utilisé",
 			)
-			return reverse("home")
+			return reverse(self.failure_pattern_name)
 
 		user.is_active = True
 		user.email_confirmed = True
 		user.save()
 		login(self.request, user)
-		messages.info(self.request, "Votre adresse email a bien été confirmée.")
-		return reverse("home")
+		messages.success(self.request, "Votre adresse email a bien été confirmée.")
+		return reverse(self.success_pattern_name)
+
+
+class UpdateAccountView(LoginRequiredMixin, UpdateView):
+	"""Vue pour la mise à jour des infos personnelles"""
+	template_name = "update.html"
+	form_class = UpdateAccountForm
+
+	def get_object(self):
+		return self.request.user
+
+	# def get_context_data(self, **kwargs):
+	# 	context = super().get_context_data(**kwargs)
+	# 	context["change_password_form"] = registration_forms.UpdatePasswordForm(
+	# 		user=self.request.user
+	# 	)
+	# 	return context
+
+	def get_success_url(self):
+		# if not self.request.user.email_confirmed:
+			# return reverse("registration:email_confirmation_needed")
+		return reverse("accounts:profile")
+
+	def form_valid(self, form):
+		messages.success(self.request, "Informations personnelles mises à jour")
+		return super().form_valid(form)
-- 
GitLab