diff --git a/.coverage b/.coverage index f732434..15170c7 100644 Binary files a/.coverage and b/.coverage differ diff --git a/jarvis/objective/admin.py b/jarvis/objective/admin.py index 365a837..aa27276 100644 --- a/jarvis/objective/admin.py +++ b/jarvis/objective/admin.py @@ -221,7 +221,15 @@ class TrainingProgramAdmin(admin.ModelAdmin): "difficulty", # "score", ) - list_display = ("date", "gymnast", "passe", "rank") + list_display = ( + "date", + "gymnast", + "passe", + "rank", + "repetition", + "number_of_skill", + "difficulty", + ) list_filter = ( ("gymnast", RelatedDropdownFilter), ("date", DropdownFilter), diff --git a/jarvis/objective/forms.py b/jarvis/objective/forms.py index 5f72522..e066699 100644 --- a/jarvis/objective/forms.py +++ b/jarvis/objective/forms.py @@ -110,3 +110,12 @@ class PasseForm(forms.ModelForm): # "step": "1", # } # ), + + def clean_regexp(self): + """ """ + cleaned_data = self.clean() + regexp = cleaned_data.get("regexp") + if not Passe.is_valid_regexp(regexp, None, None): + self.add_error("regexp", "Entered regexp not valid.") + + return regexp diff --git a/jarvis/objective/models.py b/jarvis/objective/models.py index a5244df..f1cb435 100644 --- a/jarvis/objective/models.py +++ b/jarvis/objective/models.py @@ -477,54 +477,82 @@ class Passe(Markdownizable): regexp = models.CharField(max_length=50, null=True, blank=True) number_of_skill = models.PositiveSmallIntegerField(default=0) difficulty = models.DecimalField(max_digits=4, decimal_places=1, default=0.0) + # TODO: number_of_skill doit être calculé correctement dans tous les cas. def save(self, *args, **kwargs): - """Sauve les informations de la personne et initialise les champs nettoyés.""" + """Sauve les informations de la personne et initialise les champs nettoyés. + On part du principe que self.regexp est correct. + """ self.difficulty = 0 self.number_of_skill = 0 super().save(*args, **kwargs) + print("Dans le save") - for educative in self.educatives.all(): - is_skill = False - try: - educative = Routine.objects.get(pk=educative) - except Routine.DoesNotExist: - educative = Skill.objects.get(pk=educative) - is_skill = True + if self.educatives.count() == 0: + print("educative is none") + present = False + operation_list = self.regexp.split(" ") + for item in ROUTINE_TYPE_CHOICE: + if item[1] == operation_list[0]: + present = True + break - if is_skill: - self.difficulty += educative.difficulty - self.number_of_skill += 1 - else: - if self.regexp is not None: - regexp = self.regexp.replace("[", "").replace("]", "") - position = regexp.find("-") - - start = regexp[:position] - if start == "": - start = 0 - else: - start = int(start) - - end = regexp[position + 1 :] - if end == "": - end = educative.jumps.all().count() - else: - end = int(end) - - self.number_of_skill += end - (start - 1) - list_of_skill = educative.skill_links.filter( - rank__gte=start, rank__lte=end - ) - # .aggregate(total=Sum("value")) - tmp_difficulty = 0 - for routine_skill in list_of_skill: - tmp_difficulty += routine_skill.skill.difficulty - self.difficulty += tmp_difficulty + if present and len(operation_list) == 2: + print("present") + content = operation_list[1].replace("[", "").replace("]", "") + ranks = content.split("-") + if ranks[0] == "": + self.number_of_skill += int(ranks[1]) + elif ranks[1] == "": + self.number_of_skill += (10 - int(ranks[0])) + 1 else: - self.number_of_skill += educative.jumps.all().count() + self.number_of_skill += (int(ranks[1]) - int(ranks[0])) + 1 + else: + self.number_of_skill += 10 + + else: + for educative in self.educatives.all(): + is_skill = False + try: + educative = Routine.objects.get(pk=educative) + except Routine.DoesNotExist: + educative = Skill.objects.get(pk=educative) + is_skill = True + + if is_skill: self.difficulty += educative.difficulty + self.number_of_skill += 1 + else: + if self.regexp is not None: + regexp = self.regexp.replace("[", "").replace("]", "") + position = regexp.find("-") + + start = regexp[:position] + if start == "": + start = 0 + else: + start = int(start) + + end = regexp[position + 1 :] + if end == "": + end = educative.jumps.all().count() + else: + end = int(end) + + self.number_of_skill += end - (start - 1) + list_of_skill = educative.skill_links.filter( + rank__gte=start, rank__lte=end + ) + # .aggregate(total=Sum("value")) + tmp_difficulty = 0 + for routine_skill in list_of_skill: + tmp_difficulty += routine_skill.skill.difficulty + self.difficulty += tmp_difficulty + + else: + self.number_of_skill += educative.jumps.all().count() + self.difficulty += educative.difficulty super().save(*args, **kwargs) @@ -532,7 +560,63 @@ class Passe(Markdownizable): return f"{self.label} ({self.number_of_skill} | {self.difficulty})" @staticmethod - def check_regexp(regexp, label, educatives_list): + def is_valid_dot(pattern): + """Reçoit une chaine de caratère et vérifie que si elle contient un point (.), il se trouve + soit à la première position soit à la dernière position. + """ + last_place = len(pattern) - 1 + if re.search("\.", pattern): + if pattern[0] != "." and pattern[last_place] != ".": + return False + + return True + + @staticmethod + def is_valid_routine_type(routine_type): + """Recoit une chaine de caractère et vérifie si elle est présente dans une liste.""" + is_valid = False + for item in ROUTINE_TYPE_CHOICE: + if item[1] == routine_type: + is_valid = True + break + + return is_valid + + @staticmethod + def is_valid_subset(subset): + """Reçoit la description d'un subset sous forme de string et vérifie qu'elle est conforme. + + Format attendu : [X-Y] + X ou Y peuvent être vide mais pas en même temps. + X est un entier >= 2 + Y est un entier >= 2 OU Y > X si X est non vide + + Exemples : + - [2-8] True + - [-5] True + - [3-] True + - [8-2] False + - [-] False + - [1-] False + - [-1] False + - [4] False + - [6-6] False + """ + if re.match(r"^\[[2-9]*\-[2-9]*\]$", subset): + value = subset.replace("[", "").replace("]", "") + if len(value) > 1: + ranks = value.split("-") + + if ranks[0] == "" or ranks[1] == "": + return True + + if int(ranks[0]) < int(ranks[1]): + return True + + return False + + @staticmethod + def is_valid_regexp(regexp): """Vérifie le champ regexp Type de string pris en compte : @@ -546,14 +630,84 @@ class Passe(Markdownizable): - Q1R1 True (si educatives.count() vide) - Q1R2 [2-8] True (si educatives.count() vide) - Q1R1 [8-2] False - - Q2R3 [-5] True (si educatives.count() vide) + - Q1R1 [-] False (not working) + - Q2R1 [-5] True (si educatives.count() vide) - SF [6-] True (si educatives.count() vide) - FS [3-7] True (si educatives.count() vide) + - Q1R1. True (si educatives.count() == 1) (NOT WOKRING) + - .Q1R2 True (si educatives.count() == 1) (NOT WOKRING) - WC True (si educatives.count() >= 2) - - 1| True (si educatives.count() >= 2) + - 1| True (si educatives.count() >= 1) """ + operation_list = regexp.split(" ") + + if len(operation_list) >= 3: + return False + + if len(operation_list) == 2: + if not Passe.is_valid_dot(operation_list[0]): + return False + + value = operation_list[0].replace(".", "") + is_valid_routine = Passe.is_valid_routine_type(value) + + if is_valid_routine: + return Passe.is_valid_subset(operation_list[1]) + else: + if operation_list[0] == "WC": + return True + + if re.match(r"[1-9]+\|", operation_list[0]): + return True + + if not Passe.is_valid_dot(operation_list[0]): + return False + + value = operation_list[0].replace(".", "") + is_valid_routine = Passe.is_valid_routine_type(value) + + if is_valid_routine: + return True + + return Passe.is_valid_subset(operation_list[0]) + + return False + + @staticmethod + def is_valid_regexp_extended(regexp, label, educatives_list): + """Vérifie le champ regexp + + Type de string pris en compte : + - Toutes les valeurs de ROUTINE_TYPE_CHOICE (Educative vide !) + - avec [x-y] (avec X ou Y vide mais pas les deux en même temps) + - [x-y] (avec X ou Y vide mais pas les deux en même temps) (EDUCATIVE non vide !!!) + - WC + - x| (x entier) + + Exemples : + - Q1R1 True (si educatives.count() vide) + - Q1R2 [2-8] True (si educatives.count() vide) + - Q1R1 [8-2] False + - Q1R1 [-] False + - Q2R1 [-5] True (si educatives.count() vide) + - SF [6-] True (si educatives.count() vide) + - FS [3-7] True (si educatives.count() vide) + - Q1R1. True (si educatives.count() vide) + - .Q1R2 True (si educatives.count() vide) + - Q1R1. [-4] True (si educatives.count() vide) + - .Q1R2 [4-] True (si educatives.count() vide) + - .FS [3-7] True (si educatives.count() vide) + - [2-8] True (si educative.count() == 1 et educative est une routine >= 8 sauts) + - [8-2] False + - [-] False + - [-5] True (si educative.count() == 1 et educative est une routine >= 8 sauts) + - WC True (si educatives.count() >= 2) + - 1| True (si educatives.count() >= 1) + """ + # devrait être en dehors de cette fonction --> if label is None and educatives_list is None and regexp is None: return False + # <-- operation_list = regexp.split(" ") @@ -561,27 +715,36 @@ class Passe(Markdownizable): return False if len(operation_list) == 2: - if operation_list[0] in ROUTINE_TYPE_CHOICE: - if re.match(r"\[[1-9]*\-[1-9]*\]", operation_list[1]): - content = operation_list[1].replace("[", "").replace("]", "") - ranks = content.split("-") - if ranks.count() > 1: - if ranks[1] > ranks[1]: - return True - else: - return False - return True - else: - return False - else: + if not Passe.is_valid_dot(operation_list[0]): return False + + value = operation_list[0].replace(".", "") + is_valid_routine = Passe.is_valid_routine_type(value) + + if is_valid_routine: + return Passe.is_valid_subset(operation_list[1]) else: - if operation_list[0] == "WC" and len(educatives_list) == 2: + if ( + operation_list[0] == "WC" + and educatives_list is not None + and len(educatives_list) == 2 + ): return True if re.match(r"[1-9]+\|", operation_list[0]) and len(educatives_list) >= 1: return True + if not Passe.is_valid_dot(operation_list[0]): + return False + + value = operation_list[0].replace(".", "") + is_valid_routine = Passe.is_valid_routine_type(value) + + if is_valid_routine: + return True + + return Passe.is_valid_subset(operation_list[0]) + return False diff --git a/jarvis/objective/templates/passes/details.html b/jarvis/objective/templates/passes/details.html index 187065d..4a83193 100644 --- a/jarvis/objective/templates/passes/details.html +++ b/jarvis/objective/templates/passes/details.html @@ -10,7 +10,7 @@

Passe details

-
{{ passe.label }}{% if passe.regexp %}{{ passe.regexp }}{% endif %}   {{ passe.repetition }}
+
{{ passe.label }} {% if passe.regexp %}{{ passe.regexp }}{% endif %}   {{ passe.repetition }}
@@ -27,16 +27,24 @@
- {% if passe.regexp %} + {% if passe.regexp and passe.regexp != passe.label %}
- +
{{ passe.regexp }}
@@ -46,7 +54,7 @@
- {{ number_of_skill }} + {{ number_of_educative }}
diff --git a/jarvis/objective/templates/trainingprograms/details.html b/jarvis/objective/templates/trainingprograms/details.html index 17dc15f..36a69d1 100644 --- a/jarvis/objective/templates/trainingprograms/details.html +++ b/jarvis/objective/templates/trainingprograms/details.html @@ -12,14 +12,14 @@ - + {% for trainingprogram in trainingprogram_list %} - + {% if request.user|has_group:"trainer" %} diff --git a/jarvis/objective/tests.py b/jarvis/objective/tests.py index 92189e9..64793a5 100644 --- a/jarvis/objective/tests.py +++ b/jarvis/objective/tests.py @@ -132,7 +132,7 @@ class PasseTestCase(TestCase): educ_1 = Educative.objects.get(long_label="1/2 vrille") educatives_list.append(educ_1) regexp = "1|" - self.assertEqual(Passe.check_regexp(regexp, label, educatives_list), False) + self.assertEqual(Passe.check_regexp(regexp, label, educatives_list), True) educ_3 = Educative.objects.get(long_label="4 pattes") educatives_list.append(educ_3) self.assertEqual(Passe.check_regexp(regexp, label, educatives_list), True) diff --git a/jarvis/objective/urls.py b/jarvis/objective/urls.py index bec4be4..d3c550e 100644 --- a/jarvis/objective/urls.py +++ b/jarvis/objective/urls.py @@ -92,7 +92,11 @@ urlpatterns = [ # # PASSES # - path(r"passe//", views.passe_details, name="passe_details"), + path( + r"passe//gymnast//date//", + views.passe_details, + name="passe_details", + ), path(r"passe/", views.passe_listing, name="passe_listing"), path( r"passe/add/", diff --git a/jarvis/objective/views.py b/jarvis/objective/views.py index d7d2532..c0824ea 100644 --- a/jarvis/objective/views.py +++ b/jarvis/objective/views.py @@ -7,7 +7,9 @@ from django.urls import reverse import pendulum +from jarvis.core.global_vars import ROUTINE_TYPE_CHOICE from jarvis.people.models import Gymnast +from jarvis.followup.models import GymnastHasRoutine from .forms import ( SkillForm, @@ -521,19 +523,66 @@ def passe_listing(request): @login_required @require_http_methods(["GET"]) -def passe_details(request, passe_id): +def passe_details(request, passe_id, gymnast_id, date): """Détails d'un passage.""" is_skill = False passe = get_object_or_404(Passe, pk=passe_id) educative_list = passe.educatives.all() # TODO: décryptage de la regexp - number_of_educative = educative_list.count() + regexp = passe.regexp + routine = None + skill_link_list = None + + if regexp is not None: + operation_list = regexp.split(" ") + routine_type = None + + for item in ROUTINE_TYPE_CHOICE: + if item[1] == operation_list[0]: + routine_type = item[0] + break + + if routine_type is not None: + # Récupération de la série + ghr = GymnastHasRoutine.objects.filter( + gymnast=gymnast_id, + date_begin__lte=date, + # date_end__gte=date, + routine_type=routine_type, + ) + + print(ghr.query) + + if ghr.count() > 1: + print("Plus d'une série trouvée...") + + print(ghr) + + routine = ghr.first().routine + skill_link_list = routine.skill_links.all() + if len(operation_list) == 2: + content = operation_list[1].replace("[", "").replace("]", "") + ranks = content.split("-") + + if ranks[0] != "": + skill_link_list = skill_link_list.filter(rank__gte=ranks[0]) + + if ranks[1] != "": + skill_link_list = skill_link_list.filter(rank__lte=ranks[1]) + + number_of_educative = skill_link_list.count() + print(number_of_educative) + + else: + number_of_educative = educative_list.count() context = { "passe": passe, "is_skill": is_skill, "educative_list": educative_list, + "routine": routine, + "skill_link_list": skill_link_list, "difficulty": passe.difficulty, "number_of_skill": passe.number_of_skill, "number_of_educative": number_of_educative,
{% if gymnast %}{{ gymnast}} - {% endif %}{{ date|date:"l j F Y" }}{% if gymnast %}{{ gymnast }} - {% endif %}{{ date|date:"l j F Y" }}
{{ trainingprogram.rank }}{{ trainingprogram.passe.label }}{% if trainingprogram.repetition != 1 %}   {{ trainingprogram.repetition }}{% endif %}{{ trainingprogram.passe.label }}{% if trainingprogram.repetition != 1 %}   {{ trainingprogram.repetition }}{% endif %} {{ trainingprogram.number_of_skill}} {{ trainingprogram.difficulty }}