From f3516ffaf84c1a19daf06f422c4068431192c37b Mon Sep 17 00:00:00 2001
From: Dorian Lesbre <dorian.lesbre@gmail.com>
Date: Sun, 7 Mar 2021 15:50:18 +0100
Subject: [PATCH] Functionnal activity choice

---
 home/forms.py                        | 20 +++++++++
 home/static/css/style.css            |  2 +-
 home/templates/inscription/form.html | 12 +++--
 home/views.py                        | 65 +++++++++++++++++-----------
 4 files changed, 69 insertions(+), 30 deletions(-)

diff --git a/home/forms.py b/home/forms.py
index a6cb16a..a0ba31c 100644
--- a/home/forms.py
+++ b/home/forms.py
@@ -1,4 +1,5 @@
 from django import forms
+from django.core.exceptions import ValidationError
 
 from home.models import ActivityList, InterludesParticipant
 from shared.forms import FormRenderMixin
@@ -30,3 +31,22 @@ class ActivityForm(FormRenderMixin, forms.ModelForm):
 	class Meta:
 		model = ActivityList
 		fields = ("activity",)
+
+class BaseActivityFormSet(forms.BaseFormSet):
+	"""Form set that fails if duplicate activities"""
+	def clean(self):
+		"""Checks for duplicate activities"""
+		if any(self.errors):
+			# Don't bother validating the formset unless each form is valid on its own
+			return
+		activities = []
+		for form in self.forms:
+			if self.can_delete and self._should_delete_form(form):
+				continue
+			activity = form.cleaned_data.get('activity')
+			if activity is None:
+				continue
+			if activity in activities:
+				print(activity)
+				raise ValidationError("Vous ne pouvez pas sélectionner une même activtté plusieurs fois")
+			activities.append(activity)
diff --git a/home/static/css/style.css b/home/static/css/style.css
index bef1b44..bd20b34 100644
--- a/home/static/css/style.css
+++ b/home/static/css/style.css
@@ -9,7 +9,6 @@
 html, body {
 	background-color: #dddddd;
 	color: #333;
-	font-size: 18px;
 	font-weight: 300;
 	line-height: 1.5;
 	font-family: Arial, Roboto, Helvetica, sans-serif;
@@ -174,6 +173,7 @@ span.helptext {
 .button, .button:link, .button:visited, input[type=submit] {
 	color: white;
 	text-decoration: none;
+	font-size: 1em;
 	background-color: var(--color_bg_1);
 	padding: 7px 10px;
 	margin: 5px;
diff --git a/home/templates/inscription/form.html b/home/templates/inscription/form.html
index a75b84b..7a0b252 100644
--- a/home/templates/inscription/form.html
+++ b/home/templates/inscription/form.html
@@ -3,10 +3,6 @@
 
 {% block nav_inscription %}current{% endblock %}
 
-{% block "head" %}
-	<!--<script src="{% static 'js/formset.js' %}"></script>-->
-{% endblock %}
-
 {% block "content" %}
 	<h2>Inscriptions</h2>
 	<form id="main_form" method="post" action="{% url 'inscription' %}">
@@ -14,6 +10,13 @@
 		{{ form.as_p }}
 
 		<h3>Choix d'activités</h3>
+
+		<p>Saissisez les activités auquelles vous voulez vous inscrire, par ordre de préférence.</p>
+
+		{% if formset.non_form_errors %}
+		{{ formset.non_form_errors }}
+		{% endif %}
+
 		{{ formset.management_data }}
 		{{ formset.management_form }}
 		{% for form in formset %}
@@ -50,6 +53,7 @@ function add_new_form(event) {
 	new_form.innerHTML = new_form.innerHTML.replace(form_regex, `form-${form_count}-`);
 	// add it and increment form total
 	main_form.insertBefore(new_form, button_add_activity);
+	new_form.querySelector("select").value = "";
 	total_forms.setAttribute("value", `${form_count+1}`);
 }
 
diff --git a/home/views.py b/home/views.py
index b2f6b73..e127793 100644
--- a/home/views.py
+++ b/home/views.py
@@ -1,13 +1,13 @@
 from django.contrib import messages
 from django.contrib.auth.mixins import LoginRequiredMixin
 from django.contrib.sitemaps import Sitemap
-from django.forms import modelformset_factory
+from django.forms import formset_factory
 from django.shortcuts import redirect, render
 from django.urls import reverse
 from django.views.generic import UpdateView, TemplateView, View
 
 from home.models import ActivityList, InterludesActivity
-from home.forms import ActivityForm, InscriptionForm
+from home.forms import ActivityForm, BaseActivityFormSet, InscriptionForm
 from site_settings.models import SiteSettings
 
 
@@ -41,35 +41,50 @@ class RegisterSignIn(TemplateView):
 	l'utilisateur n'est pas connecté"""
 	template_name = "inscription/signin.html"
 
-class RegisterUpdateView(LoginRequiredMixin, UpdateView):
+class RegisterUpdateView(LoginRequiredMixin, TemplateView):
 	"""Vue pour s'inscrire et modifier son inscription"""
 	template_name = "inscription/form.html"
 	form_class = InscriptionForm
-	formset = modelformset_factory(ActivityList, form=ActivityForm, extra=3)
+	formset_class = formset_factory(form=ActivityForm, extra=3, formset=BaseActivityFormSet)
+
+	@staticmethod
+	def get_activities(participant):
+		activities = ActivityList.objects.filter(participant=participant).order_by("priority")
+		return [{"activity": act.activity} for act in activities]
+
+	@staticmethod
+	def set_activities(participant, formset):
+		# delete old activites
+		ActivityList.objects.filter(participant=participant).delete()
+
+		priority = 0
+		for form in formset:
+			data = form.cleaned_data
+			if data:
+				activity = data["activity"]
+				ActivityList(priority=priority, participant=participant, activity=activity).save()
+				priority += 1
+
+	def get(self, request, *args, **kwargs):
+		participant = request.user.profile
+		activities = self.get_activities(participant)
+		form = self.form_class(instance=participant)
+		formset = self.formset_class(initial=activities)
+		context = {"form": form, "formset": formset}
+		return render(request, self.template_name, context)
 
-	def get_context_data(self, **kwargs):
-		context = super().get_context_data(**kwargs)
-		context["formset"] = self.formset(queryset=ActivityList.objects.none())
-		return context
-
-	def get_object(self):
-		return self.request.user.profile
-
-	def get_success_url(self):
-		return reverse("accounts:profile")
+	def post(self, request, *args, **kwargs):
+		form = self.form_class(request.POST, instance=request.user.profile)
+		formset = self.formset_class(request.POST)
+		if not (form.is_valid() and formset.is_valid()):
+			context = {"form": form, "formset": formset}
+			return render(request, self.template_name, context)
 
-	def form_valid(self, form):
-		messages.success(self.request, "Votre inscription a été enregistrée")
-		return super().form_valid(form)
+		form.save()
+		self.set_activities(request.user.profile, formset)
 
-	def post(self, request, *args, **kwargs):
-		form = self.form_class(request.POST)
-		formset = self.formset(request.POST)
-		if formset.is_valid():
-			print("\n\n{} {}\n\n".format(len(formset), formset))
-		else:
-			print("\n\nInvalid\n\n")
-		return super().post(request, *args, **kwargs)
+		messages.success(request, "Votre inscription a bien été enregistrée")
+		return redirect("accounts:profile", permanent=False)
 
 class RegisterView(View):
 	"""Vue pour l'inscription
-- 
GitLab