From 2b8f81c94bbd3c453b0ebafcd7749f3459f3e85a Mon Sep 17 00:00:00 2001 From: Basile Clement Date: Sun, 25 Nov 2018 17:05:55 +0100 Subject: [PATCH] =?UTF-8?q?[petitscours]=20Extrait=20la=20proposition=20de?= =?UTF-8?q?=20profs=20dans=20une=20m=C3=A9thode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ce patch simplifie le code (dupliqué) de calcul des proposition de profs pour une demande dans une méthode du modèle`Demande`, et l'utilise. Il s'agit d'un préparatif pour #208; ce code devra être réutilisé dans le nouveau système. J'en ai également profité pour nettoyer deux vues de `petitscours`, `retraitement` et `demande_raw`, qui dupliquaient les vues `traitement` et `demande`, en utilisant des arguments nommés. petitscours/ * models.py: Définition de `get_proposals` pour calculer les propositions de profs pour une demande. * views.py: Utilise `get_proposals` à la place du code copié-collé. La fonction `_finalize_traitement` est maintenant responsable du calcul des `proposed_for` et `attribdata` à fournir aux templates. * urls.py: Passe directement les arguments aux vues plutôt que de faire deux fonctions séparées. --- petitscours/models.py | 43 ++++++++++++ petitscours/urls.py | 10 ++- petitscours/views.py | 154 ++++++++---------------------------------- 3 files changed, 78 insertions(+), 129 deletions(-) diff --git a/petitscours/models.py b/petitscours/models.py index 50f8910e..da911830 100644 --- a/petitscours/models.py +++ b/petitscours/models.py @@ -3,6 +3,7 @@ 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.functional import cached_property from django.utils.translation import ugettext_lazy as _ @@ -55,6 +56,12 @@ class PetitCoursAbility(models.Model): self.user.username, self.matiere, self.niveau ) + @cached_property + def counter(self) -> int: + """Le compteur d'attribution associé au professeur pour cette matière.""" + + return PetitCoursAttributionCounter.get_uptodate(self.user, self.matiere).count + class PetitCoursDemande(models.Model): name = models.CharField(_("Nom/prénom"), max_length=200) @@ -128,6 +135,42 @@ class PetitCoursDemande(models.Model): candidates = candidates.order_by("?").select_related().all() yield (matiere, candidates) + def get_proposals(self, *, max_candidates: int = None, redo: bool = False): + """Calcule une proposition de profs pour la demande. + + Args: + max_candidates (optionnel; défaut: `None`): Le nombre maximum de + candidats à proposer par demande. Si `None` ou non spécifié, + il n'y a pas de limite. + + redo (optionel; défaut: `False`): Détermine si on re-calcule les + propositions pour la demande (les professeurs à qui on a déjà + proposé cette demande sont exclus). + + Returns: + proposals: Le dictionnaire qui associe à chaque matière la liste + des professeurs proposés. Les matières pour lesquelles aucun + professeur n'est disponible ne sont pas présentes dans + `proposals`. + unsatisfied: La liste des matières pour lesquelles aucun + professeur n'est disponible. + """ + + proposals = {} + unsatisfied = [] + for matiere, candidates in self.get_candidates(redo=redo): + if not candidates: + unsatisfied.append(matiere) + else: + proposals[matiere] = matiere_proposals = [] + + candidates = sorted(candidates, key=lambda c: c.counter) + candidates = candidates[:max_candidates] + for candidate in candidates[:max_candidates]: + matiere_proposals.append(candidate.user) + + return proposals, unsatisfied + class Meta: app_label = "gestioncof" verbose_name = "Demande de petits cours" diff --git a/petitscours/urls.py b/petitscours/urls.py index 19f54ed9..767e0f8f 100644 --- a/petitscours/urls.py +++ b/petitscours/urls.py @@ -7,7 +7,12 @@ from gestioncof.decorators import buro_required urlpatterns = [ url(r"^inscription$", views.inscription, name="petits-cours-inscription"), url(r"^demande$", views.demande, name="petits-cours-demande"), - url(r"^demande-raw$", views.demande_raw, name="petits-cours-demande-raw"), + url( + r"^demande-raw$", + views.demande, + kwargs={"raw": True}, + name="petits-cours-demande-raw", + ), url( r"^demandes$", buro_required(DemandeListView.as_view()), @@ -25,7 +30,8 @@ urlpatterns = [ ), url( r"^demandes/(?P\d+)/retraitement$", - views.retraitement, + views.traitement, + kwargs={"redo": True}, name="petits-cours-demande-retraitement", ), ] diff --git a/petitscours/views.py b/petitscours/views.py index dfebac24..b6974a8f 100644 --- a/petitscours/views.py +++ b/petitscours/views.py @@ -53,64 +53,27 @@ def traitement(request, demande_id, redo=False): return _traitement_other(request, demande, redo) if request.method == "POST": return _traitement_post(request, demande) - proposals = {} - proposed_for = {} - unsatisfied = [] - attribdata = {} - for matiere, candidates in demande.get_candidates(redo): - if candidates: - tuples = [] - for candidate in candidates: - user = candidate.user - tuples.append( - ( - candidate, - PetitCoursAttributionCounter.get_uptodate(user, matiere), - ) - ) - tuples = sorted(tuples, key=lambda c: c[1].count) - candidates, _ = zip(*tuples) - candidates = candidates[0 : min(3, len(candidates))] - attribdata[matiere.id] = [] - proposals[matiere] = [] - for candidate in candidates: - user = candidate.user - proposals[matiere].append(user) - attribdata[matiere.id].append(user.id) - if user not in proposed_for: - proposed_for[user] = [matiere] - else: - proposed_for[user].append(matiere) - else: - unsatisfied.append(matiere) - return _finalize_traitement( - request, demande, proposals, proposed_for, unsatisfied, attribdata, redo - ) - - -@buro_required -def retraitement(request, demande_id): - return traitement(request, demande_id, redo=True) + proposals, unsatisfied = demande.get_proposals(redo=redo, max_candidates=3) + return _finalize_traitement(request, demande, proposals, unsatisfied, redo) def _finalize_traitement( - request, - demande, - proposals, - proposed_for, - unsatisfied, - attribdata, - redo=False, - errors=None, + request, demande, proposals, unsatisfied, redo=False, errors=None ): - proposals = proposals.items() - proposed_for = proposed_for.items() - attribdata = list(attribdata.items()) + attribdata = [ + (matiere.id, [user.id for user in users]) + for matiere, users in proposals.items() + ] + proposed_for = {} + for matiere, users in proposals.items(): + for user in users: + proposed_for.setdefault(user, []).append(matiere) + proposed_mails = _generate_eleve_email(demande, proposed_for) mainmail = render_custom_mail( "petits-cours-mail-demandeur", { - "proposals": proposals, + "proposals": proposals.items(), "unsatisfied": unsatisfied, "extra": '