kpsul/gestioncof/petits_cours_models.py
2018-10-06 13:15:33 +02:00

191 lines
6.7 KiB
Python

from functools import reduce
from django.contrib.auth.models import User
from django.db import models
from django.db.models import Min
from django.utils.translation import ugettext_lazy as _
def choices_length(choices):
return reduce(lambda m, choice: max(m, len(choice[0])), choices, 0)
LEVELS_CHOICES = (
("college", _("Collège")),
("lycee", _("Lycée")),
("prepa1styear", _("Prépa 1ère année / L1")),
("prepa2ndyear", _("Prépa 2ème année / L2")),
("licence3", _("Licence 3")),
("other", _("Autre (préciser dans les commentaires)")),
)
class PetitCoursSubject(models.Model):
name = models.CharField(_("Matière"), max_length=30)
users = models.ManyToManyField(
User, related_name="petits_cours_matieres", through="PetitCoursAbility"
)
class Meta:
verbose_name = "Matière de petits cours"
verbose_name_plural = "Matières des petits cours"
def __str__(self):
return self.name
class PetitCoursAbility(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
matiere = models.ForeignKey(
PetitCoursSubject, on_delete=models.CASCADE, verbose_name=_("Matière")
)
niveau = models.CharField(
_("Niveau"), choices=LEVELS_CHOICES, max_length=choices_length(LEVELS_CHOICES)
)
agrege = models.BooleanField(_("Agrégé"), default=False)
class Meta:
verbose_name = "Compétence petits cours"
verbose_name_plural = "Compétences des petits cours"
def __str__(self):
return "{:s} - {!s} - {:s}".format(
self.user.username, self.matiere, self.niveau
)
class PetitCoursDemande(models.Model):
name = models.CharField(_("Nom/prénom"), max_length=200)
email = models.CharField(_("Adresse email"), max_length=300)
phone = models.CharField(_("Téléphone (facultatif)"), max_length=20, blank=True)
quand = models.CharField(
_("Quand ?"),
help_text=_(
"Indiquez ici la période désirée pour les petits"
" cours (vacances scolaires, semaine, week-end)."
),
max_length=300,
blank=True,
)
freq = models.CharField(
_("Fréquence"),
help_text=_(
"Indiquez ici la fréquence envisagée "
"(hebdomadaire, 2 fois par semaine, ...)"
),
max_length=300,
blank=True,
)
lieu = models.CharField(
_("Lieu (si préférence)"),
help_text=_("Si vous avez avez une préférence sur le lieu."),
max_length=300,
blank=True,
)
matieres = models.ManyToManyField(
PetitCoursSubject, verbose_name=_("Matières"), related_name="demandes"
)
agrege_requis = models.BooleanField(_("Agrégé requis"), default=False)
niveau = models.CharField(
_("Niveau"),
default="",
choices=LEVELS_CHOICES,
max_length=choices_length(LEVELS_CHOICES),
)
remarques = models.TextField(_("Remarques et précisions"), blank=True)
traitee = models.BooleanField(_("Traitée"), default=False)
traitee_par = models.ForeignKey(
User, on_delete=models.CASCADE, blank=True, null=True
)
processed = models.DateTimeField(_("Date de traitement"), blank=True, null=True)
created = models.DateTimeField(_("Date de création"), auto_now_add=True)
def get_candidates(self, redo=False):
"""
Donne la liste des profs disponibles pour chaque matière de la demande.
- On ne donne que les agrégés si c'est demandé
- Si ``redo`` vaut ``True``, cela signifie qu'on retraite la demande et
il ne faut pas proposer à nouveau des noms qui ont déjà été proposés
"""
for matiere in self.matieres.all():
candidates = PetitCoursAbility.objects.filter(
matiere=matiere,
niveau=self.niveau,
user__profile__is_cof=True,
user__profile__petits_cours_accept=True,
)
if self.agrege_requis:
candidates = candidates.filter(agrege=True)
if redo:
attrs = self.petitcoursattribution_set.filter(matiere=matiere)
already_proposed = [attr.user for attr in attrs]
candidates = candidates.exclude(user__in=already_proposed)
candidates = candidates.order_by("?").select_related().all()
yield (matiere, candidates)
class Meta:
verbose_name = "Demande de petits cours"
verbose_name_plural = "Demandes de petits cours"
def __str__(self):
return "Demande {:d} du {:s}".format(self.id, self.created.strftime("%d %b %Y"))
class PetitCoursAttribution(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
demande = models.ForeignKey(
PetitCoursDemande, on_delete=models.CASCADE, verbose_name=_("Demande")
)
matiere = models.ForeignKey(
PetitCoursSubject, on_delete=models.CASCADE, verbose_name=_("Matière")
)
date = models.DateTimeField(_("Date d'attribution"), auto_now_add=True)
rank = models.IntegerField("Rang dans l'email")
selected = models.BooleanField(_("Sélectionné par le demandeur"), default=False)
class Meta:
verbose_name = "Attribution de petits cours"
verbose_name_plural = "Attributions de petits cours"
def __str__(self):
return "Attribution de la demande {:d} à {:s} pour {!s}".format(
self.demande.id, self.user.username, self.matiere
)
class PetitCoursAttributionCounter(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
matiere = models.ForeignKey(
PetitCoursSubject, on_delete=models.CASCADE, verbose_name=_("Matiere")
)
count = models.IntegerField("Nombre d'envois", default=0)
@classmethod
def get_uptodate(cls, user, matiere):
"""
Donne le compteur de l'utilisateur pour cette matière. Si le compteur
n'existe pas encore, il est initialisé avec le minimum des valeurs des
compteurs de tout le monde.
"""
counter, created = cls.objects.get_or_create(user=user, matiere=matiere)
if created:
mincount = (
cls.objects.filter(matiere=matiere)
.exclude(user=user)
.aggregate(Min("count"))["count__min"]
)
counter.count = mincount or 0
counter.save()
return counter
class Meta:
verbose_name = "Compteur d'attribution de petits cours"
verbose_name_plural = "Compteurs d'attributions de petits cours"
def __str__(self):
return "{:d} demandes envoyées à {:s} pour {!s}".format(
self.count, self.user.username, self.matiere
)