Skip to content
Snippets Groups Projects
Commit f2d98156 authored by Dorian Lesbre's avatar Dorian Lesbre
Browse files

Validation de la répartition de mails

parent 35d40dea
No related branches found
No related tags found
No related merge requests found
......@@ -42,7 +42,9 @@ class InterludesActivity(models.Model):
"Nombre minimum de participants"
)
display = models.BooleanField("afficher dans la liste d'activités", default=False)
must_subscribe = models.BooleanField("sur inscription", default=False)
must_subscribe = models.BooleanField("sur inscription", default=False,
help_text="Une activité doit être affichée dans la liste également pour que l'on puisse si inscrire"
)
host_name = models.CharField("nom de l'organisateur", max_length=50)
host_email = models.EmailField("email de l'organisateur")
description = models.TextField("description", max_length=2000)
......@@ -82,6 +84,14 @@ class InterludesActivity(models.Model):
def pretty_type(self) -> str:
return self.Types(self.act_type).label
def conflicts(self, other: "InterludesActivity") -> bool:
"""Check whether these activites overlap"""
if self.end is None or other.end is None:
return False
if self.start <= other.start:
return other.start <= self.end
return self.start <= other.end
def __str__(self):
return self.title
......
......@@ -355,7 +355,7 @@ ul.messagelist li.info:before {
// Location
// =========================== */
#mailing-address {
.centered {
font-size: 1.5rem;
text-align: center;
}
......@@ -421,7 +421,7 @@ ul.messagelist li.info:before {
}
@media (max-width: 800px) {
#mailing-address {
.centered {
font-size: 1.2rem;
}
#public-transport-info {
......
......@@ -107,4 +107,32 @@
<div class="nb_small">{{ metrics.granted }}</div>
</div>
</div>
<h2>Répartition des activités</h2>
<p>La répartition se fait depuis la <a href="{% url 'admin:index' %}">page d'administration de django</a>,
dans la rebrique "Choix d'activités" via la colonne "obtenue".</p>
{{ validations|safe }}
<script type="text/javascript">
function mail_inscrits() {
if (confirm(
`Cette action va envoyer 20 emails.\nÊtes-vous sur de vouloir continuer ?`
))
window.location = "{% url 'home' %}";
}
function mail_orgas() {
if (confirm(
`Cette action va envoyer 20 emails.\nÊtes-vous sur de vouloir continuer ?`
))
window.location = "{% url 'home' %}";
}
</script>
<p class="centered"><strong>N'ENVOYER LES EMAILS QUE SI VOUS ÊTES SUR DE VOUS !</strong></p>
<div class="flex wrap">
<button class="button" onclick="mail_inscrits();">Email aux inscrits</button>
<button class="button" onclick="mail_inscrits();">Email aux orgas</button>
</div>
{% endblock %}
\ No newline at end of file
......@@ -33,7 +33,7 @@
<h2>Comment se rendre à l'ENS Ulm ?</h2>
<div>
<p id="mailing-address">
<p class="centered">
<i class="fas fa-map-marker-alt"></i>
45 rue d'Ulm, 75005 Paris
</p>
......
......@@ -3,6 +3,7 @@ from datetime import timedelta
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.sitemaps import Sitemap
from django.db.models import Count
from django.forms import formset_factory
from django.shortcuts import redirect, render
from django.urls import reverse
......@@ -164,11 +165,95 @@ class AdminView(SuperuserRequiredMixin, TemplateView):
wish = wishes.count()
granted = wishes.filter(accepted=True).count()
# validation de la repartition des activités
accepted = wishes.filter(accepted=True)
# order_by is useless but required
counts = accepted.values("activity").annotate(total=Count("id")).order_by("activity")
return metrics
def validate_activity_participant_nb(self):
""" Vérifie que le nombre de participant inscrit
à chaque activité est compris entre le min et le max"""
activities = InterludesActivity.objects.filter(must_subscribe=True, display=True)
min_fails = ""
max_fails = ""
for act in activities:
total = ActivityList.objects.filter(
activity=act, accepted=True, participant__is_registered=True
).aggregate(total=Count("id"))["total"]
max = act.max_participants
min = act.min_participants
if max != 0 and max < total:
max_fails += "<br> &bullet;&ensp;{}: {} inscrits (maximum {})".format(
act.title, total, max
)
if min > total:
min_fails += "<br> &bullet;&ensp;{}: {} inscrits (minimum {})".format(
act.title, total, max
)
message = ""
if min_fails:
message += '<li class="error">Activités en sous-effectif : {}</li>'.format(min_fails)
else:
message += '<li class="success">Aucune activité en sous-effectif</li>'
if max_fails:
message += '<li class="error">Activités en sur-effectif : {}</li>'.format(max_fails)
else:
message += '<li class="success">Aucune activité en sur-effectif</li>'
return message
def validate_activity_conflicts(self):
"""Vérifie que personne n'est inscrit à des activités simultanées"""
activities = InterludesActivity.objects.filter(must_subscribe=True, display=True)
conflicts = []
for i, act1 in enumerate(activities):
for act2 in activities[i+1:]:
if act1.conflicts(act2):
conflicts.append((act1, act2))
base_qs = ActivityList.objects.filter(accepted=True, participant__is_registered=True)
errors = ""
for act1, act2 in conflicts:
participants1 = base_qs.filter(activity=act1).values("participant")
participants2 = base_qs.filter(activity=act1).values("participant")
intersection = participants1 & participants2
if intersection:
print(intersection)
errors += '<br> &bullet;&ensp; {} participe(nt) à la fois à "{}" et à "{}"'.format(
",".join(str(InterludesParticipant.objects.get(id=x["participant"])) for x in intersection),
act1.title, act2.title
)
if errors:
return '<li class="error">Des participants ont plusieurs activités au même moment :{}</li>'.format(
errors
)
return '<li class="success">Aucun inscrit à plusieurs activités simultanées</li>'
def validate_activity_allocation(self):
settings = SiteSettings.load()
validations = '<ul class="messagelist">'
# validate global settings
if not settings.inscriptions_open:
validations += '<li class="success">Les inscriptions sont fermées</li>'
else:
validations += '<li class="error">Les inscriptions sont encores ouvertes</li>'
if settings.activities_allocated:
validations += '<li class="success">La répartition est marquée comme effectuée</li>'
else:
validations += '<li class="error">La répartition n\'est pas marquée comme effectuée</li>'
# longer validations
validations += self.validate_activity_participant_nb()
validations += self.validate_activity_conflicts()
validations += '</ul>'
return validations
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context["metrics"] = self.get_metrics()
context["validations"] = self.validate_activity_allocation()
return context
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment