From c628816435f43caf5f96dad8ce495ec289a586b7 Mon Sep 17 00:00:00 2001 From: Gregory Trullemans Date: Mon, 8 May 2023 10:12:15 +0200 Subject: [PATCH] Implementation of combination feature --- jarvis/objective/models.py | 27 +++++- .../templates/combinations/compose.html | 8 +- .../templates/combinations/details.html | 2 +- .../templates/combinations/list.html | 2 +- .../objective/templates/skills/details.html | 23 +++-- jarvis/objective/tests_urls.py | 2 +- jarvis/objective/urls.py | 4 +- jarvis/objective/views.py | 87 ++++++++++++++----- jarvis/people/views.py | 16 +++- 9 files changed, 126 insertions(+), 45 deletions(-) diff --git a/jarvis/objective/models.py b/jarvis/objective/models.py index f769c0d..cf43b92 100644 --- a/jarvis/objective/models.py +++ b/jarvis/objective/models.py @@ -1,5 +1,5 @@ from django.db import models -from django.db.models import Q, Count +from django.db.models import Q from jarvis.tools.models import Markdownizable, max_even_if_none @@ -265,7 +265,17 @@ class Routine(Educative): return f"{self.long_label} ({self.short_label})" def compute_informations(self): - """Calcule les informations (rank, niveau, ages, …) d'une routine.""" + """Cette fonction a pour but d'assurer la cohérence des informations d'une combinaison. + La fonction vérifie : + - les âges pour les filles et garçons, + - le rang, + - le niveau, + - la difficulté + - si c'est une routine (série) + - si c'est une routine (série) de compétition + A chaque fois qu'on le peut, on garde les informations entrées par les utilisateurs néanmoins on vérifie qu'il + n'a pas encodé n'importe quoi. + """ rank = 0 level = 0 age_boy_with_help = 0 @@ -277,7 +287,8 @@ class Routine(Educative): age_boy_masterised = 0 age_girl_masterised = 0 difficulty = 0 - is_competitive = True + is_routine = False + is_competitive = False for skill_link in self.skill_links.all(): skill = skill_link.skill @@ -315,8 +326,16 @@ class Routine(Educative): skill.age_girl_masterised, age_girl_masterised ) - if self.skill_links.all().count() != 10: + if self.skill_links.all().count() < 5: + is_routine = False is_competitive = False + elif self.skill_links.all().count() != 10: + is_competitive = False + + if not self.is_routine: + is_competitive = False + + self.is_routine = is_routine self.is_competitive = is_competitive self.difficulty = difficulty diff --git a/jarvis/objective/templates/combinations/compose.html b/jarvis/objective/templates/combinations/compose.html index 1bc95ed..b9f66b4 100644 --- a/jarvis/objective/templates/combinations/compose.html +++ b/jarvis/objective/templates/combinations/compose.html @@ -63,11 +63,11 @@ $('body').on('click', '#minusButton', function(event){ $.ajax({ - url: "{% url 'unlink_skill_from_routine' %}", + url: "{% url 'unlink_skill_from_combination' %}", method: "POST", data: { - routine_id: {{ routine.id }}, - order: number_of_skill, + combination_id: {{ routine.id }}, + rank: number_of_skill, csrfmiddlewaretoken: '{{ csrf_token }}' }, }).done(function() { @@ -112,7 +112,7 @@ url: "{% url 'link_skill_to_combination' %}", method: "POST", data: { - routine_id: {{ routine.id }}, + combination_id: {{ routine.id }}, skill_id: ui.item.skillid, rank: number_of_skill, csrfmiddlewaretoken: '{{ csrf_token }}' diff --git a/jarvis/objective/templates/combinations/details.html b/jarvis/objective/templates/combinations/details.html index 095770b..39e8b99 100644 --- a/jarvis/objective/templates/combinations/details.html +++ b/jarvis/objective/templates/combinations/details.html @@ -51,7 +51,7 @@ {% endif %} diff --git a/jarvis/objective/templates/skills/details.html b/jarvis/objective/templates/skills/details.html index f675c3d..df2bc15 100644 --- a/jarvis/objective/templates/skills/details.html +++ b/jarvis/objective/templates/skills/details.html @@ -59,7 +59,7 @@

Educatives

-
    - {% if skill.educatives.all %} - {% for educatives in skill.educatives.all %} -
  • {{ educatives.short_label }}
  • +
      + {% if educative_skill or combination_dict %} + {% for skill in educative_skill %} +
    • + {{ skill.short_label }} +
    • + {% endfor %} + {% for name, skill_list in combination_dict.items %} +
    • + {% for skill in skill_list %} + {{ skill.skill.short_label }} + {% if forloop.last %} + {% else %} + - + {% endif %} + {% endfor %} +
    • {% endfor %} {% else %}

      No educative defined.

      diff --git a/jarvis/objective/tests_urls.py b/jarvis/objective/tests_urls.py index 487ab01..261ebb3 100644 --- a/jarvis/objective/tests_urls.py +++ b/jarvis/objective/tests_urls.py @@ -51,7 +51,7 @@ class URLTestCase(TestCase): ) self.assertEqual( resolve("/objective/combination/compose/unlink_skill/").view_name, - "unlink_skill_from_routine", + "unlink_skill_from_combination", ) self.assertEqual( resolve("/combination/competition_routine/").view_name, diff --git a/jarvis/objective/urls.py b/jarvis/objective/urls.py index 8f7357d..e1dc0c0 100644 --- a/jarvis/objective/urls.py +++ b/jarvis/objective/urls.py @@ -51,8 +51,8 @@ urlpatterns = [ ), path( r"combination/compose/unlink_skill/", - views.unlink_skill_from_routine, - name="unlink_skill_from_routine", + views.unlink_skill_from_combination, + name="unlink_skill_from_combination", ), path( r"combination/gymnast//", diff --git a/jarvis/objective/views.py b/jarvis/objective/views.py index 7f7bbaa..8f1b6dd 100644 --- a/jarvis/objective/views.py +++ b/jarvis/objective/views.py @@ -24,8 +24,7 @@ from .models import ( @require_http_methods(["POST"]) def skill_lookup(request): """ - Récupère la liste des skill à la volée suivant des caractères de - recherche entrés. (min 3 caractères) + Récupère la liste des skill à la volée suivant des caractères de recherche entrés. (min 3 caractères) """ results = [] pattern = request.POST.get("pattern", None) @@ -48,7 +47,7 @@ def skill_lookup(request): @require_http_methods(["GET"]) def skill_without_prerequisite_listing(request): """ - Récupère la liste des skills suivant un pattern si celui-ci est définit. + Récupère la liste des skills n'ayant aucun prérequis. """ skill_list = Skill.objects.filter(prerequisites=None) context = {"skill_list": skill_list} @@ -60,6 +59,12 @@ def skill_without_prerequisite_listing(request): def skill_listing(request, field=None, expression=None, value=None, level=None): """ Récupère la liste des skills suivant un pattern si celui-ci est définit. + + Args: + field champ sur lequel doit être effectué la recherche + expression expression de comparaison : le, leq, ge, geq, … + value valeur de la recherche + level niveau requis pour les skills cherchés. """ pattern = None @@ -86,7 +91,11 @@ def skill_listing(request, field=None, expression=None, value=None, level=None): @login_required @require_http_methods(["GET"]) def skill_tree(request, skill_id): - """ """ + """Récupère tout l'arbre des prérequis pour une saut passé en paramètre + + Args: + skill_id identifiant de la classe Skill + """ skill = get_object_or_404(Skill, pk=skill_id) node_dict = {} skill_closure = PrerequisiteClosure.objects.filter(descendant=skill) @@ -105,10 +114,8 @@ def skill_details(request, skill_id): La méthode en profite pour vérifier les champs level, rank, age_boy et age_girl par rapport aux pré-requis. - :param skill_id: id d'un `skill` - :type skill_id: int - - :return: skill + Args: + skill_id identifiant de la classe Skill """ skill = get_object_or_404(Skill, pk=skill_id) @@ -142,7 +149,22 @@ def skill_details(request, skill_id): skill.save() - context = {"skill": skill} + # Je sépare les educatifs de type "skill" et les éducatifs de type "combination" pour mieux gérer l'affichage + # Du code bien dégueulasse ! + # QTF : une idée pour faire ca de manière plus propre, plus élégante ? + combination_dict = {} + educative_skill = skill.educatives.filter(id__in=(Skill.objects.all())) + for educative in skill.educatives.filter(id__in=(Routine.objects.all())): + combination = Routine.objects.get(pk=educative.id) + combination_dict[combination] = [] + for educ_skill in combination.routine.skill_links.all(): + combination_dict[combination].append(educ_skill) + + context = { + "skill": skill, + "combination_dict": combination_dict, + "educative_skill": educative_skill, + } return render(request, "skills/details.html", context) @@ -177,11 +199,15 @@ def skill_create_or_update(request, skill_id=None): @login_required @require_http_methods(["GET"]) def competition_routine_listing(request, gymnast_id=None): - """Récupère la liste des routines suivant un pattern si celui-ci est défini""" + """Récupère la liste des routines (séries) de compétition suivant un pattern si celui-ci est défini + + Args: + gymnast_id identifiant de la classe Gymnast + """ gymnast = None pattern = request.GET.get("pattern", None) - if pattern: + if pattern is not None and len(pattern) > 2: routine_list = Routine.objects.filter( is_routine=True, is_competitive=True ).filter(Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern)) @@ -206,11 +232,15 @@ def competition_routine_listing(request, gymnast_id=None): @login_required @require_http_methods(["GET"]) def routine_listing(request, gymnast_id=None): - """Récupère la liste des routines suivant un pattern si celui-ci est défini""" + """Récupère la liste des routines (série) suivant un pattern si celui-ci est défini + + Args: + gymnast_id identifiant de la classe Gymnast + """ gymnast = None pattern = request.GET.get("pattern", None) - if pattern: + if pattern is not None and len(pattern) > 2: routine_list = Routine.objects.filter(is_routine=True).filter( Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern) ) @@ -235,11 +265,15 @@ def routine_listing(request, gymnast_id=None): @login_required @require_http_methods(["GET"]) def educative_combination_listing(request, gymnast_id=None): - """Récupère la liste des routines suivant un pattern si celui-ci est défini""" + """Récupère la liste des educatifs suivant un pattern si celui-ci est défini + + Args: + gymnast_id identifiant de la classe Gymnast + """ gymnast = None pattern = request.GET.get("pattern", None) - if pattern: + if pattern is not None and len(pattern) > 2: routine_list = Routine.objects.filter(is_routine=False).filter( Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern) ) @@ -264,11 +298,15 @@ def educative_combination_listing(request, gymnast_id=None): @login_required @require_http_methods(["GET"]) def combination_listing(request, gymnast_id=None): - """Récupère la liste des routines suivant un pattern si celui-ci est défini""" + """Récupère la liste des combinaisons suivant un pattern si celui-ci est défini + + Args: + gymnast_id identifiant de la classe Gymnast + """ gymnast = None pattern = request.GET.get("pattern", None) - if pattern: + if pattern is not None and len(pattern) > 2: routine_list = Routine.objects.filter( Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern) ) @@ -292,11 +330,11 @@ def combination_listing(request, gymnast_id=None): @require_http_methods(["POST"]) def routine_lookup(request): """ - Récupère la liste des lieux à la volée suivant des caractères de recherche entrés. + Récupère la liste des combinaison à la volée suivant des caractères de recherche entrés. """ pattern = request.POST.get("pattern", None) - if pattern is not None and len(pattern) >= 3: + if pattern is not None and len(pattern) > 2: results = Routine.objects.filter( Q(long_label__icontains=pattern) | Q(short_label__icontains=pattern) ) @@ -306,12 +344,13 @@ def routine_lookup(request): @login_required +@require_http_methods(["GET"]) def combination_details(request, combination_id): """ - Récupère toutes les informations d'une routine (série). + Récupère toutes les informations d'une combinaison. Args: - combination_id int identifiant d'une routine + combination_id identifiant d'une routine """ routine = get_object_or_404(Routine, pk=combination_id) @@ -403,13 +442,13 @@ def link_skill_to_combination(request): @require_http_methods(["POST"]) -def unlink_skill_from_routine(request): +def unlink_skill_from_combination(request): """ Recoit dans request deux informations permettant d'enlever un skill d'une routine : - - order numéro de place du skill dans la routine + - rank numéro de place du skill dans la routine - combination_id identifiant d'un object de classe """ - rank = request.POST.get("order", None) + rank = request.POST.get("rank", None) combination_id = request.POST.get("combination_id", None) combination = get_object_or_404(Routine, pk=combination_id) try: diff --git a/jarvis/people/views.py b/jarvis/people/views.py index 803edae..7208d94 100644 --- a/jarvis/people/views.py +++ b/jarvis/people/views.py @@ -70,7 +70,7 @@ def gymnast_lookup(request): results = [] pattern = request.POST.get("pattern", None) - if pattern is not None and len(pattern) > 3: + if pattern is not None and len(pattern) > 2: model_results = Gymnast.objects.filter( Q(last_name__icontains=pattern) | Q(first_name__icontains=pattern) ) @@ -331,6 +331,9 @@ def gymnast_display_mindstate(request, gymnast_id): def gymnast_display_routine_statistics(request, gymnast_id): """ Tag affichant les statistiques et informations de séries d'un gymnaste. + + Args: + gymnast_id identifiant de la classe Gymnast """ gymnast = get_object_or_404(Gymnast, pk=gymnast_id) ghr_list = gymnast.has_routine.prefetch_related("routine").filter( @@ -369,7 +372,11 @@ def gymnast_display_routine_statistics(request, gymnast_id): @login_required @require_http_methods(["GET", "POST"]) def link_routine_to_gymnast(request, gymnast_id=None): - """ """ + """Lie une série à un gymnaste + + Args: + gymnast_id identifiant de la classe Gymnast + """ if gymnast_id: gymnast = get_object_or_404(Gymnast, pk=gymnast_id) @@ -423,7 +430,10 @@ def link_routine_to_gymnast(request, gymnast_id=None): @require_http_methods(["GET", "POST"]) def gymnast_create_or_update(request, gymnast_id=None): """ - Formulaire de creation et modification d'un gymnaste. + Formulaire de création et modification d'un gymnaste. + + Args: + gymnast_id Identifiant de la classe Gymnast """ if gymnast_id: