From 266afaf5c979a3b1e98af7e9172199c3fc35c017 Mon Sep 17 00:00:00 2001 From: Emmy D'Anello Date: Thu, 18 Apr 2024 14:53:58 +0200 Subject: [PATCH] Split 5-teams pols in two pools for each room Signed-off-by: Emmy D'Anello --- draw/models.py | 25 +- locale/fr/LC_MESSAGES/django.po | 320 ++++++++++-------- participation/admin.py | 4 +- .../0013_alter_pool_options_pool_room.py | 31 ++ participation/models.py | 107 ++++-- participation/tables.py | 2 +- .../templates/participation/pool_detail.html | 19 +- .../templates/participation/tex/finale.tex | 6 +- participation/views.py | 61 ++-- 9 files changed, 337 insertions(+), 238 deletions(-) create mode 100644 participation/migrations/0013_alter_pool_options_pool_room.py diff --git a/draw/models.py b/draw/models.py index 96b78bf..391ff2d 100644 --- a/draw/models.py +++ b/draw/models.py @@ -361,6 +361,17 @@ class Pool(models.Model): .prefetch_related('participation')]) await self.asave() + pool2 = None + if self.size == 5: + pool2, _created = await PPool.objects.aget_or_create( + tournament=self.round.draw.tournament, + round=self.round.number, + letter=self.letter, + room=2, + ) + await pool2.participations.aset([td.participation async for td in self.team_draws + .prefetch_related('participation')]) + # Define the passage matrix according to the number of teams table = [] if self.size == 3: @@ -380,16 +391,24 @@ class Pool(models.Model): table = [ [0, 2, 3], [1, 3, 4], - [4, 0, 2], + [2, 4, 0], [3, 0, 1], [4, 1, 2], ] for i, line in enumerate(table): + passage_pool = self.associated_pool + passage_position = i + 1 + if self.size == 5: + # In 5-teams pools, we may create some passages in the second room + if i % 2 == 1: + passage_pool = pool2 + passage_position = 1 + i // 2 + # Create the passage await Passage.objects.acreate( - pool=self.associated_pool, - position=i + 1, + pool=passage_pool, + position=passage_position, solution_number=tds[line[0]].accepted, defender=tds[line[0]].participation, opponent=tds[line[1]].participation, diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index a1d2366..7983e18 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: TFJM\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-16 23:57+0200\n" +"POT-Creation-Date: 2024-04-17 22:47+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Emmy D'Anello \n" "Language-Team: LANGUAGE \n" @@ -29,15 +29,15 @@ msgstr "équipes" #: draw/admin.py:53 draw/admin.py:71 draw/admin.py:88 draw/models.py:26 #: participation/admin.py:79 participation/admin.py:140 -#: participation/admin.py:171 participation/models.py:656 -#: participation/models.py:680 participation/models.py:886 +#: participation/admin.py:171 participation/models.py:683 +#: participation/models.py:707 participation/models.py:927 #: registration/models.py:756 #: registration/templates/registration/payment_form.html:53 msgid "tournament" msgstr "tournoi" -#: draw/admin.py:92 draw/models.py:234 draw/models.py:429 -#: participation/models.py:890 +#: draw/admin.py:92 draw/models.py:234 draw/models.py:448 +#: participation/models.py:931 msgid "round" msgstr "tour" @@ -175,7 +175,7 @@ msgstr "La poule en cours, où les équipes choisissent leurs problèmes" msgid "rounds" msgstr "tours" -#: draw/models.py:257 participation/models.py:904 +#: draw/models.py:257 participation/models.py:939 msgid "letter" msgstr "lettre" @@ -208,82 +208,82 @@ msgstr "poule associée" msgid "The full pool instance." msgstr "L'instance complète de la poule." -#: draw/models.py:407 +#: draw/models.py:426 #, python-brace-format msgid "Pool {letter}{number}" msgstr "Poule {letter}{number}" -#: draw/models.py:410 draw/models.py:437 participation/admin.py:136 -#: participation/admin.py:155 participation/models.py:1364 -#: participation/models.py:1373 participation/tables.py:84 +#: draw/models.py:429 draw/models.py:456 participation/admin.py:136 +#: participation/admin.py:155 participation/models.py:1397 +#: participation/models.py:1406 participation/tables.py:84 msgid "pool" msgstr "poule" -#: draw/models.py:411 participation/models.py:1365 +#: draw/models.py:430 participation/models.py:1398 msgid "pools" msgstr "poules" -#: draw/models.py:423 participation/models.py:876 participation/models.py:1514 -#: participation/models.py:1544 participation/models.py:1586 +#: draw/models.py:442 participation/models.py:917 participation/models.py:1547 +#: participation/models.py:1577 participation/models.py:1619 msgid "participation" msgstr "participation" -#: draw/models.py:444 +#: draw/models.py:463 msgid "passage index" msgstr "numéro de passage" -#: draw/models.py:445 +#: draw/models.py:464 msgid "" "The passage order in the pool, between 0 and the size of the pool minus 1." msgstr "" "L'ordre de passage dans la poule, de 0 à la taille de la poule moins 1." -#: draw/models.py:453 +#: draw/models.py:472 msgid "choose index" msgstr "numéro de choix" -#: draw/models.py:454 +#: draw/models.py:473 msgid "" "The choice order in the pool, between 0 and the size of the pool minus 1." msgstr "" "L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1." -#: draw/models.py:460 draw/models.py:483 participation/models.py:1387 -#: participation/models.py:1551 +#: draw/models.py:479 draw/models.py:502 participation/models.py:1420 +#: participation/models.py:1584 #, python-brace-format msgid "Problem #{problem}" msgstr "Problème n°{problem}" -#: draw/models.py:464 +#: draw/models.py:483 msgid "accepted problem" msgstr "problème accepté" -#: draw/models.py:471 +#: draw/models.py:490 msgid "passage dice" msgstr "dé d'ordre de passage" -#: draw/models.py:478 +#: draw/models.py:497 msgid "choice dice" msgstr "dé d'ordre de choix" -#: draw/models.py:487 +#: draw/models.py:506 msgid "purposed problem" msgstr "problème proposé" -#: draw/models.py:492 +#: draw/models.py:511 msgid "rejected problems" msgstr "problèmes rejetés" -#: draw/models.py:521 +#: draw/models.py:540 #, python-brace-format msgid "Draw of the team {trigram} for the pool {letter}{number}" msgstr "Tirage de l'équipe {trigram} pour la poule {letter}{number}" -#: draw/models.py:527 +#: draw/models.py:546 msgid "team draw" msgstr "tirage d'équipe" -#: draw/models.py:528 +#: draw/models.py:547 msgid "team draws" msgstr "tirages d'équipe" @@ -332,7 +332,7 @@ msgid "Continue draw" msgstr "Continuer le tirage" #: draw/templates/draw/tournament_content.html:216 participation/admin.py:167 -#: participation/models.py:252 participation/models.py:671 +#: participation/models.py:252 participation/models.py:698 #: participation/templates/participation/tournament_harmonize.html:15 #: registration/models.py:157 registration/models.py:747 #: registration/tables.py:39 @@ -345,35 +345,31 @@ msgstr "équipe" #: draw/templates/draw/tournament_content.html:228 #: draw/templates/draw/tournament_content.html:229 #: draw/templates/draw/tournament_content.html:230 -#: participation/templates/participation/pool_detail.html:85 -#: participation/templates/participation/pool_detail.html:89 -#: participation/templates/participation/pool_detail.html:94 -#: participation/templates/participation/pool_detail.html:98 msgid "Room" msgstr "Salle" -#: draw/templates/draw/tournament_content.html:335 -#: draw/templates/draw/tournament_content.html:354 +#: draw/templates/draw/tournament_content.html:334 +#: draw/templates/draw/tournament_content.html:353 msgid "Abort" msgstr "Annuler" -#: draw/templates/draw/tournament_content.html:345 +#: draw/templates/draw/tournament_content.html:344 msgid "Are you sure?" msgstr "Êtes-vous sûr⋅e ?" -#: draw/templates/draw/tournament_content.html:349 +#: draw/templates/draw/tournament_content.html:348 msgid "This will reset the draw from the beginning." msgstr "Cela va réinitialiser le tirage au sort depuis le début." -#: draw/templates/draw/tournament_content.html:350 +#: draw/templates/draw/tournament_content.html:349 msgid "This operation is irreversible." msgstr "Cette opération est irréversible." -#: draw/templates/draw/tournament_content.html:351 +#: draw/templates/draw/tournament_content.html:350 msgid "Are you sure you want to abort this draw?" msgstr "Êtes-vous sûr·e de vouloir annuler le tirage au sort ?" -#: draw/templates/draw/tournament_content.html:355 +#: draw/templates/draw/tournament_content.html:354 #: tfjm/templates/base_modal.html:17 msgid "Close" msgstr "Fermer" @@ -452,26 +448,26 @@ msgstr "Changelog de type \"{action}\" pour le modèle {model} le {timestamp}" msgid "valid" msgstr "valide" -#: participation/admin.py:87 participation/models.py:692 +#: participation/admin.py:87 participation/models.py:719 msgid "selected for final" msgstr "sélectionnée pour la finale" #: participation/admin.py:124 participation/admin.py:183 -#: participation/models.py:1394 participation/tables.py:112 +#: participation/models.py:1427 participation/tables.py:112 msgid "defender" msgstr "défenseur⋅se" -#: participation/admin.py:128 participation/models.py:1401 -#: participation/models.py:1598 +#: participation/admin.py:128 participation/models.py:1434 +#: participation/models.py:1631 msgid "opponent" msgstr "opposant⋅e" -#: participation/admin.py:132 participation/models.py:1408 -#: participation/models.py:1599 +#: participation/admin.py:132 participation/models.py:1441 +#: participation/models.py:1632 msgid "reporter" msgstr "rapporteur⋅rice" -#: participation/admin.py:187 participation/models.py:1549 +#: participation/admin.py:187 participation/models.py:1582 msgid "problem" msgstr "numéro de problème" @@ -799,28 +795,36 @@ msgstr "finale" msgid "Google Sheet ID" msgstr "ID de la feuille Google Sheets" -#: participation/models.py:657 registration/admin.py:125 +#: participation/models.py:684 registration/admin.py:125 msgid "tournaments" msgstr "tournois" -#: participation/models.py:686 +#: participation/models.py:713 msgid "valid team" msgstr "équipe valide" -#: participation/models.py:687 +#: participation/models.py:714 msgid "The participation got the validation of the organizers." msgstr "La participation a été validée par les organisateur⋅rices." -#: participation/models.py:693 +#: participation/models.py:720 msgid "The team is selected for the final tournament." msgstr "L'équipe est sélectionnée pour la finale." -#: participation/models.py:700 +#: participation/models.py:724 +msgid "mention" +msgstr "mention" + +#: participation/models.py:731 +msgid "mention (final)" +msgstr "Mention (pour la finale) :" + +#: participation/models.py:741 #, python-brace-format msgid "Participation of the team {name} ({trigram})" msgstr "Participation de l'équipe {name} ({trigram})" -#: participation/models.py:707 +#: participation/models.py:748 #, python-brace-format msgid "" "

The team {trigram} has {nb_missing_payments} missing payments. Each " @@ -833,11 +837,11 @@ msgstr "" "notification de bourse) pour participer au tournoi.

Les participant⋅es " "qui n'ont pas encore payé sont : {participants}.

" -#: participation/models.py:715 +#: participation/models.py:756 msgid "Missing payments" msgstr "Paiements manquants" -#: participation/models.py:732 +#: participation/models.py:773 msgid "" "

The solutions for the tournament of {tournament} are due on the {date:%Y-" "%m-%d %H:%M}.

You have currently sent {nb_solutions} " @@ -852,11 +856,11 @@ msgstr "" "pouvez envoyer vos solutions sur votre page de " "participation.

" -#: participation/models.py:742 participation/models.py:756 +#: participation/models.py:783 participation/models.py:797 msgid "Solutions due" msgstr "Rendu des solutions" -#: participation/models.py:748 +#: participation/models.py:789 msgid "" "

The solutions for the tournament of {tournament} are due on the {date:%Y-" "%m-%d %H:%M}.

Remember that you can only fix minor changes to your " @@ -869,7 +873,7 @@ msgstr "" "parties.

Vous pouvez envoyer vos solutions sur votre " "page de participation.

" -#: participation/models.py:762 registration/models.py:600 +#: participation/models.py:803 registration/models.py:600 msgid "" "

The draw of the solutions for the tournament {tournament} is planned on " "the {date:%Y-%m-%d %H:%M}. You can join it on this link." @@ -879,11 +883,11 @@ msgstr "" "{date:%d/%m/%Y %H:%M}. Vous pouvez y participer sur ce lien.

" -#: participation/models.py:768 registration/models.py:607 +#: participation/models.py:809 registration/models.py:607 msgid "Draw of solutions" msgstr "Tirage au sort des solutions" -#: participation/models.py:779 +#: participation/models.py:820 #, python-brace-format msgid "" "

The solutions draw is ended. You can check the result on votre solution du problème " "{problem}.

" -#: participation/models.py:788 participation/models.py:831 +#: participation/models.py:829 participation/models.py:872 #, python-brace-format msgid "" "

You will oppose the solution of the team {opponent} on the problème {problem}. Vous pouvez envoyer votre note " "de synthèse sur cette page.

" -#: participation/models.py:797 participation/models.py:840 +#: participation/models.py:838 participation/models.py:881 #, python-brace-format msgid "" "

You will report the solution of the team {reporter} on the problème {problem}. Vous pouvez envoyer votre note " "de synthèse sur cette page.

" -#: participation/models.py:813 registration/models.py:622 +#: participation/models.py:854 registration/models.py:622 msgid "First round" msgstr "Premier tour" -#: participation/models.py:824 +#: participation/models.py:865 #, python-brace-format msgid "" "

For the second round, you will defend your " @@ -930,11 +934,11 @@ msgstr "" "

Pour le second tour, vous défendrez votre " "solution du problème {problem}.

" -#: participation/models.py:856 registration/models.py:633 +#: participation/models.py:897 registration/models.py:633 msgid "Second round" msgstr "Second tour" -#: participation/models.py:862 +#: participation/models.py:903 #, python-brace-format msgid "" "

The tournament {tournament} is ended. You can check the results on the Le tournoi {tournament} est terminé. Vous pouvez consulter les résultats " "sur la page du tournoi.

" -#: participation/models.py:867 +#: participation/models.py:908 msgid "Tournament ended" msgstr "Tournoi terminé" -#: participation/models.py:877 participation/models.py:910 +#: participation/models.py:918 participation/models.py:961 msgid "participations" msgstr "participations" -#: participation/models.py:892 participation/models.py:893 +#: participation/models.py:933 participation/models.py:934 #, python-brace-format msgid "Round {round}" msgstr "Tour {round}" -#: participation/models.py:916 +#: participation/models.py:949 +msgid "room" +msgstr "salle" + +#: participation/models.py:951 +msgid "Room 1" +msgstr "Salle 1" + +#: participation/models.py:952 +msgid "Room 2" +msgstr "Salle 2" + +#: participation/models.py:955 +msgid "For 5-teams pools only" +msgstr "Pour les poules de 5 équipe uniquement" + +#: participation/models.py:967 msgid "juries" msgstr "jurys" -#: participation/models.py:925 +#: participation/models.py:976 msgid "president of the jury" msgstr "président⋅e du jury" -#: participation/models.py:932 +#: participation/models.py:983 msgid "BigBlueButton URL" msgstr "Lien BigBlueButton" -#: participation/models.py:933 +#: participation/models.py:984 msgid "The link of the BBB visio for this pool." msgstr "Le lien du salon BBB pour cette poule." -#: participation/models.py:938 +#: participation/models.py:989 msgid "results available" msgstr "résultats disponibles" -#: participation/models.py:939 +#: participation/models.py:990 msgid "" "Check this case when results become accessible to teams. They stay " "accessible to you. Only averages are given." @@ -985,33 +1005,33 @@ msgstr "" "Ils restent toujours accessibles pour vous. Seules les moyennes sont " "communiquées." -#: participation/models.py:964 +#: participation/models.py:1018 msgid "The president of the jury must be part of the jury." msgstr "Læ président⋅e du jury doit faire partie du jury." -#: participation/models.py:1345 +#: participation/models.py:1378 #, python-brace-format msgid "The jury {jury} is not part of the jury for this pool." msgstr "{jury} ne fait pas partie du jury pour cette poule." -#: participation/models.py:1358 +#: participation/models.py:1391 #, python-brace-format msgid "Pool of day {round} for tournament {tournament} with teams {teams}" msgstr "Poule du jour {round} du tournoi {tournament} avec les équipes {teams}" -#: participation/models.py:1378 +#: participation/models.py:1411 msgid "position" msgstr "position" -#: participation/models.py:1385 +#: participation/models.py:1418 msgid "defended solution" msgstr "solution défendue" -#: participation/models.py:1413 +#: participation/models.py:1446 msgid "penalties" msgstr "pénalités" -#: participation/models.py:1415 +#: participation/models.py:1448 msgid "" "Number of penalties for the defender. The defender will loose a 0.5 " "coefficient per penalty." @@ -1019,120 +1039,120 @@ msgstr "" "Nombre de pénalités pour l'équipe défenseuse. Elle perd un coefficient 0.5 " "sur sa présentation orale par pénalité." -#: participation/models.py:1484 participation/models.py:1487 -#: participation/models.py:1490 +#: participation/models.py:1517 participation/models.py:1520 +#: participation/models.py:1523 #, python-brace-format msgid "Team {trigram} is not registered in the pool." msgstr "L'équipe {trigram} n'est pas inscrite dans la poule." -#: participation/models.py:1495 +#: participation/models.py:1528 #, python-brace-format msgid "Passage of {defender} for problem {problem}" msgstr "Passage de {defender} pour le problème {problem}" -#: participation/models.py:1499 participation/models.py:1508 -#: participation/models.py:1593 participation/models.py:1635 +#: participation/models.py:1532 participation/models.py:1541 +#: participation/models.py:1626 participation/models.py:1668 msgid "passage" msgstr "passage" -#: participation/models.py:1500 +#: participation/models.py:1533 msgid "passages" msgstr "passages" -#: participation/models.py:1519 +#: participation/models.py:1552 msgid "difference" msgstr "différence" -#: participation/models.py:1520 +#: participation/models.py:1553 msgid "Score to add/remove on the final score" msgstr "Score à ajouter/retrancher au score final" -#: participation/models.py:1527 +#: participation/models.py:1560 msgid "tweak" msgstr "harmonisation" -#: participation/models.py:1528 +#: participation/models.py:1561 msgid "tweaks" msgstr "harmonisations" -#: participation/models.py:1556 +#: participation/models.py:1589 msgid "solution for the final tournament" msgstr "solution pour la finale" -#: participation/models.py:1561 participation/models.py:1604 +#: participation/models.py:1594 participation/models.py:1637 msgid "file" msgstr "fichier" -#: participation/models.py:1571 +#: participation/models.py:1604 #, python-brace-format msgid "Solution of team {team} for problem {problem}" msgstr "Solution de l'équipe {team} pour le problème {problem}" -#: participation/models.py:1573 +#: participation/models.py:1606 msgid "for final" msgstr "pour la finale" -#: participation/models.py:1576 +#: participation/models.py:1609 msgid "solution" msgstr "solution" -#: participation/models.py:1577 +#: participation/models.py:1610 msgid "solutions" msgstr "solutions" -#: participation/models.py:1610 +#: participation/models.py:1643 #, python-brace-format msgid "Synthesis of {team} as {type} for problem {problem} of {defender}" msgstr "" "Note de synthèse de l'équipe {team} en tant que {type} pour le problème " "{problem} de {defender}" -#: participation/models.py:1618 +#: participation/models.py:1651 msgid "synthesis" msgstr "note de synthèse" -#: participation/models.py:1619 +#: participation/models.py:1652 msgid "syntheses" msgstr "notes de synthèse" -#: participation/models.py:1628 +#: participation/models.py:1661 msgid "jury" msgstr "jury" -#: participation/models.py:1640 +#: participation/models.py:1673 msgid "defender writing note" msgstr "note d'écrit défenseur⋅se" -#: participation/models.py:1646 +#: participation/models.py:1679 msgid "defender oral note" msgstr "note d'oral défenseur⋅se" -#: participation/models.py:1652 +#: participation/models.py:1685 msgid "opponent writing note" msgstr "note d'écrit opposant⋅e" -#: participation/models.py:1658 +#: participation/models.py:1691 msgid "opponent oral note" msgstr "note d'oral opposant⋅e" -#: participation/models.py:1664 +#: participation/models.py:1697 msgid "reporter writing note" msgstr "note d'écrit rapporteur⋅rice" -#: participation/models.py:1670 +#: participation/models.py:1703 msgid "reporter oral note" msgstr "note d'oral du rapporteur⋅rice" -#: participation/models.py:1728 +#: participation/models.py:1761 #, python-brace-format msgid "Notes of {jury} for {passage}" msgstr "Notes de {jury} pour le {passage}" -#: participation/models.py:1731 +#: participation/models.py:1764 msgid "note" msgstr "note" -#: participation/models.py:1732 +#: participation/models.py:1765 msgid "notes" msgstr "notes" @@ -1159,8 +1179,8 @@ msgstr "Du {start} au {end}" #: participation/tables.py:94 #, python-brace-format -msgid "Pool {letter}{round}" -msgstr "Poule {letter}{round}" +msgid "Pool {code}" +msgstr "Poule {code}" #: participation/tables.py:98 msgid "No defined team" @@ -1172,7 +1192,7 @@ msgstr "Pas d'équipe définie" #: participation/templates/participation/passage_detail.html:140 #: participation/templates/participation/passage_detail.html:146 #: participation/templates/participation/pool_detail.html:13 -#: participation/templates/participation/pool_detail.html:157 +#: participation/templates/participation/pool_detail.html:152 #: participation/templates/participation/team_detail.html:179 #: participation/templates/participation/team_detail.html:243 #: participation/templates/participation/tournament_form.html:12 @@ -1273,7 +1293,7 @@ msgstr "Envoyer une solution" #: participation/templates/participation/participation_detail.html:65 #: participation/templates/participation/passage_detail.html:152 -#: participation/templates/participation/pool_detail.html:162 +#: participation/templates/participation/pool_detail.html:157 #: participation/templates/participation/team_detail.html:238 #: participation/templates/participation/upload_motivation_letter.html:13 #: participation/templates/participation/upload_notes.html:24 @@ -1321,12 +1341,12 @@ msgid "Defender penalties count:" msgstr "Nombre de pénalités :" #: participation/templates/participation/passage_detail.html:43 -#: participation/templates/participation/pool_detail.html:54 +#: participation/templates/participation/pool_detail.html:59 msgid "Syntheses:" msgstr "Notes de synthèse :" #: participation/templates/participation/passage_detail.html:48 -#: participation/templates/participation/pool_detail.html:63 +#: participation/templates/participation/pool_detail.html:68 msgid "No synthesis was uploaded yet." msgstr "Aucune note de synthèse n'a encore été envoyée." @@ -1393,36 +1413,40 @@ msgstr "Tour :" msgid "Letter:" msgstr "Lettre :" -#: participation/templates/participation/pool_detail.html:29 +#: participation/templates/participation/pool_detail.html:30 +msgid "Room:" +msgstr "Salle :" + +#: participation/templates/participation/pool_detail.html:34 msgid "Teams:" msgstr "Équipes :" -#: participation/templates/participation/pool_detail.html:36 +#: participation/templates/participation/pool_detail.html:41 msgid "Juries:" msgstr "Juré⋅es :" -#: participation/templates/participation/pool_detail.html:40 +#: participation/templates/participation/pool_detail.html:45 msgid "Edit jury" msgstr "Modifier le jury" -#: participation/templates/participation/pool_detail.html:44 +#: participation/templates/participation/pool_detail.html:49 msgid "Defended solutions:" msgstr "Solutions défendues :" -#: participation/templates/participation/pool_detail.html:50 -#: participation/templates/participation/pool_detail.html:69 +#: participation/templates/participation/pool_detail.html:55 +#: participation/templates/participation/pool_detail.html:74 msgid "Download all" msgstr "Tout télécharger" -#: participation/templates/participation/pool_detail.html:74 +#: participation/templates/participation/pool_detail.html:79 msgid "BigBlueButton link:" msgstr "Lien BigBlueButton :" -#: participation/templates/participation/pool_detail.html:80 +#: participation/templates/participation/pool_detail.html:85 msgid "Notation sheets:" msgstr "Feuilles de notations :" -#: participation/templates/participation/pool_detail.html:85 +#: participation/templates/participation/pool_detail.html:90 msgid "Download the scale sheet" msgstr "Télécharger la feuille de barème" @@ -1430,42 +1454,42 @@ msgstr "Télécharger la feuille de barème" msgid "Download the final notation sheet" msgstr "Télécharger la fiche de notation finale" -#: participation/templates/participation/pool_detail.html:103 +#: participation/templates/participation/pool_detail.html:98 msgid "Download all notation sheets" msgstr "Télécharger toutes les fiches de notation" -#: participation/templates/participation/pool_detail.html:108 +#: participation/templates/participation/pool_detail.html:103 msgid "Google Sheets Spreadsheet:" msgstr "Tableur Google Sheets :" -#: participation/templates/participation/pool_detail.html:112 +#: participation/templates/participation/pool_detail.html:107 msgid "Go to the Google Sheets page of the pool" msgstr "Aller à la page Google Sheets de la poule" -#: participation/templates/participation/pool_detail.html:121 +#: participation/templates/participation/pool_detail.html:116 #: participation/templates/participation/tournament_detail.html:101 #: participation/templates/participation/tournament_harmonize.html:8 msgid "Ranking" msgstr "Classement" -#: participation/templates/participation/pool_detail.html:136 +#: participation/templates/participation/pool_detail.html:131 msgid "Upload notes from a spreadsheet file" msgstr "Soumettre les notes à partir d'un tableur" -#: participation/templates/participation/pool_detail.html:140 +#: participation/templates/participation/pool_detail.html:135 msgid "Download notation spreadsheet" msgstr "Télécharger le tableur de notes" -#: participation/templates/participation/pool_detail.html:152 +#: participation/templates/participation/pool_detail.html:147 msgid "Passages" msgstr "Passages" -#: participation/templates/participation/pool_detail.html:156 +#: participation/templates/participation/pool_detail.html:151 #: participation/templates/participation/pool_form.html:11 msgid "Update pool" msgstr "Modifier la poule" -#: participation/templates/participation/pool_detail.html:161 +#: participation/templates/participation/pool_detail.html:156 msgid "Upload notes" msgstr "Envoyer les notes" @@ -1763,41 +1787,41 @@ msgstr "Accéder à la liste des paiements" msgid "Pools" msgstr "Poules" -#: participation/templates/participation/tournament_detail.html:111 +#: participation/templates/participation/tournament_detail.html:119 msgid "Selected for final tournament" msgstr "Sélectionnée pour la finale" -#: participation/templates/participation/tournament_detail.html:119 +#: participation/templates/participation/tournament_detail.html:127 msgid "Select for final tournament" msgstr "Sélectionner pour la finale" -#: participation/templates/participation/tournament_detail.html:132 -#: participation/templates/participation/tournament_detail.html:136 +#: participation/templates/participation/tournament_detail.html:140 +#: participation/templates/participation/tournament_detail.html:144 msgid "Harmonize" msgstr "Harmoniser" -#: participation/templates/participation/tournament_detail.html:132 -#: participation/templates/participation/tournament_detail.html:136 +#: participation/templates/participation/tournament_detail.html:140 +#: participation/templates/participation/tournament_detail.html:144 msgid "Day" msgstr "Jour" -#: participation/templates/participation/tournament_detail.html:145 +#: participation/templates/participation/tournament_detail.html:153 msgid "Publish notes for first round" msgstr "Publier les notes pour le premier tour" -#: participation/templates/participation/tournament_detail.html:150 +#: participation/templates/participation/tournament_detail.html:158 msgid "Unpublish notes for first round" msgstr "Dépublier les notes pour le premier tour" -#: participation/templates/participation/tournament_detail.html:156 +#: participation/templates/participation/tournament_detail.html:164 msgid "Publish notes for second round" msgstr "Publier les notes pour le second tour" -#: participation/templates/participation/tournament_detail.html:161 +#: participation/templates/participation/tournament_detail.html:169 msgid "Unpublish notes for second round" msgstr "Dépublier les notes pour le second tour" -#: participation/templates/participation/tournament_detail.html:173 +#: participation/templates/participation/tournament_detail.html:181 msgid "Files available for download" msgstr "Fichiers disponibles au téléchargement" @@ -2061,17 +2085,17 @@ msgstr "L'utilisateur⋅rice suivant n'est pas inscrit⋅e en tant que juré⋅e msgid "Notes were successfully uploaded." msgstr "Les notes ont bien été envoyées." -#: participation/views.py:1855 +#: participation/views.py:1825 #, python-brace-format msgid "Notation sheets of pool {pool} of {tournament}.zip" msgstr "Feuilles de notations pour la poule {pool} du tournoi {tournament}.zip" -#: participation/views.py:1860 +#: participation/views.py:1830 #, python-brace-format msgid "Notation sheets of {tournament}.zip" msgstr "Feuilles de notation de {tournament}.zip" -#: participation/views.py:2033 +#: participation/views.py:1995 msgid "You can't upload a synthesis after the deadline." msgstr "Vous ne pouvez pas envoyer de note de synthèse après la date limite." diff --git a/participation/admin.py b/participation/admin.py index 29cca92..4345c41 100644 --- a/participation/admin.py +++ b/participation/admin.py @@ -100,8 +100,8 @@ class ParticipationAdmin(admin.ModelAdmin): @admin.register(Pool) class PoolAdmin(admin.ModelAdmin): - list_display = ('__str__', 'tournament', 'round', 'letter', 'teams', 'jury_president',) - list_filter = ('tournament', 'round', 'letter',) + list_display = ('__str__', 'tournament', 'round', 'letter', 'room', 'teams', 'jury_president',) + list_filter = ('tournament', 'round', 'letter', 'room',) search_fields = ('participations__team__name', 'participations__team__trigram',) autocomplete_fields = ('tournament', 'participations', 'jury_president', 'juries',) inlines = (PassageInline, TweakInline,) diff --git a/participation/migrations/0013_alter_pool_options_pool_room.py b/participation/migrations/0013_alter_pool_options_pool_room.py new file mode 100644 index 0000000..81fa70f --- /dev/null +++ b/participation/migrations/0013_alter_pool_options_pool_room.py @@ -0,0 +1,31 @@ +# Generated by Django 5.0.3 on 2024-04-17 20:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("participation", "0012_participation_mention_participation_mention_final"), + ] + + operations = [ + migrations.AlterModelOptions( + name="pool", + options={ + "ordering": ("round", "letter", "room"), + "verbose_name": "pool", + "verbose_name_plural": "pools", + }, + ), + migrations.AddField( + model_name="pool", + name="room", + field=models.PositiveSmallIntegerField( + choices=[(1, "Room 1"), (2, "Room 2")], + default=1, + help_text="For 5-teams pools only", + verbose_name="room", + ), + ), + ] diff --git a/participation/models.py b/participation/models.py index e0d748e..322428c 100644 --- a/participation/models.py +++ b/participation/models.py @@ -10,7 +10,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator, RegexVa from django.db import models from django.db.models import Index from django.urls import reverse_lazy -from django.utils import timezone +from django.utils import timezone, translation from django.utils.crypto import get_random_string from django.utils.text import format_lazy from django.utils.timezone import localtime @@ -430,7 +430,9 @@ class Tournament(models.Model): self.notes_sheet_id = spreadsheet.id self.save() - def update_ranking_spreadsheet(self): + def update_ranking_spreadsheet(self): # noqa: C901 + translation.activate('fr') + gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT) spreadsheet = gc.open_by_key(self.notes_sheet_id) worksheets = spreadsheet.worksheets() @@ -444,27 +446,35 @@ class Tournament(models.Model): header = [["Équipe", "Score jour 1", "Harmonisation 1", "Score jour 2", "Harmonisation 2", "Total", "Rang"]] lines = [] - participations = self.participations.filter(pools__round=1, pools__tournament=self).all() + participations = self.participations.filter(pools__round=1, pools__tournament=self).distinct().all() for i, participation in enumerate(participations): line = [f"{participation.team.name} ({participation.team.trigram})"] lines.append(line) - pool1 = self.pools.get(round=1, participations=participation) - passage1 = pool1.passages.get(defender=participation) + passage1 = Passage.objects.get(pool__tournament=self, pool__round=1, defender=participation) + pool1 = passage1.pool + if pool1.participations.count() != 5: + position1 = passage1.position + else: + position1 = (passage1.position - 1) * 2 + pool1.room tweak1_qs = Tweak.objects.filter(pool=pool1, participation=participation) tweak1 = tweak1_qs.get() if tweak1_qs.exists() else None - line.append(f"=SIERREUR('Poule {pool1.short_name}'!$D{pool1.juries.count() + 10 + passage1.position}; 0)") + line.append(f"=SIERREUR('Poule {pool1.short_name}'!$D{pool1.juries.count() + 10 + position1}; 0)") line.append(tweak1.diff if tweak1 else 0) - if self.pools.filter(round=2, participations=participation).exists(): - pool2 = self.pools.get(round=2, participations=participation) - passage2 = pool2.passages.get(defender=participation) + if Passage.objects.filter(pool__tournament=self, pool__round=2, defender=participation).exists(): + passage2 = Passage.objects.get(pool__tournament=self, pool__round=2, defender=participation) + pool2 = passage2.pool + if pool2.participations.count() != 5: + position2 = passage2.position + else: + position2 = (passage2.position - 1) * 2 + pool2.room tweak2_qs = Tweak.objects.filter(pool=pool2, participation=participation) tweak2 = tweak2_qs.get() if tweak2_qs.exists() else None line.append( - f"=SIERREUR('Poule {pool2.short_name}'!$D{pool2.juries.count() + 10 + passage2.position}; 0)") + f"=SIERREUR('Poule {pool2.short_name}'!$D{pool2.juries.count() + 10 + position2}; 0)") line.append(tweak2.diff if tweak2 else 0) else: # User has no second pool yet @@ -936,13 +946,23 @@ class Pool(models.Model): ) letter = models.PositiveSmallIntegerField( + verbose_name=_('letter'), choices=[ (1, 'A'), (2, 'B'), (3, 'C'), (4, 'D'), ], - verbose_name=_('letter'), + ) + + room = models.PositiveSmallIntegerField( + verbose_name=_("room"), + choices=[ + (1, _("Room 1")), + (2, _("Room 2")), + ], + default=1, + help_text=_("For 5-teams pools only"), ) participations = models.ManyToManyField( @@ -983,7 +1003,10 @@ class Pool(models.Model): @property def short_name(self): - return f"{self.get_letter_display()}{self.round}" + short_name = f"{self.get_letter_display()}{self.round}" + if self.participations.count() == 5: + short_name += f" — {self.get_room_display()}" + return short_name @property def solutions(self): @@ -1006,6 +1029,8 @@ class Pool(models.Model): return super().validate_constraints() def update_spreadsheet(self): # noqa: C901 + translation.activate('fr') + # Create tournament sheet if it does not exist self.tournament.create_spreadsheet() @@ -1085,18 +1110,38 @@ class Pool(models.Model): ranking = [ ["Équipe", "", "Problème", "Total", "Rang"], ] - for passage in passages: + all_passages = Passage.objects.filter(pool__tournament=self.tournament, + pool__round=self.round, + pool__letter=self.letter).order_by('position', 'pool__room') + for i, passage in enumerate(all_passages): participation = passage.defender - defender_pos = passage.position - 1 - opponent_pos = passages.get(opponent=passage.defender).position - 1 - reporter_pos = passages.get(reporter=passage.defender).position - 1 + defender_passage = Passage.objects.get(defender=participation, + pool__tournament=self.tournament, pool__round=self.round) + defender_row = 5 + defender_passage.pool.juries.count() + defender_col = defender_passage.position - 1 + + opponent_passage = Passage.objects.get(opponent=participation, + pool__tournament=self.tournament, pool__round=self.round) + opponent_row = 5 + opponent_passage.pool.juries.count() + opponent_col = opponent_passage.position - 1 + + reporter_passage = Passage.objects.get(reporter=participation, + pool__tournament=self.tournament, pool__round=self.round) + reporter_row = 5 + reporter_passage.pool.juries.count() + reporter_col = reporter_passage.position - 1 + formula = "=" - formula += getcol(min_column + defender_pos * passage_width) + str(max_row + 3) # Defender - formula += " + " + getcol(min_column + opponent_pos * passage_width + 2) + str(max_row + 3) # Opponent - formula += " + " + getcol(min_column + reporter_pos * passage_width + 4) + str(max_row + 3) # Reporter + formula += (f"'Poule {defender_passage.pool.short_name}'" + f"!{getcol(min_column + defender_col * passage_width)}{defender_row + 3}") # Defender + formula += (f" + 'Poule {opponent_passage.pool.short_name}'" + f"!{getcol(min_column + opponent_col * passage_width + 2)}{opponent_row + 3}") # Opponent + formula += (f" + 'Poule {reporter_passage.pool.short_name}'" + f"!{getcol(min_column + reporter_col * passage_width + 4)}{reporter_row + 3}") # Reporter ranking.append([f"{participation.team.name} ({participation.team.trigram})", "", - f"=${getcol(3 + (passage.position - 1) * passage_width)}$1", formula, - f"=RANG(D{max_row + 5 + passage.position}; " + f"='Poule {defender_passage.pool.short_name}'" + f"!${getcol(3 + defender_col * passage_width)}$1", + formula, + f"=RANG(D{max_row + 6 + i}; " f"D${max_row + 6}:D${max_row + 5 + pool_size})"]) all_values = header + notes + footer + ranking @@ -1147,10 +1192,10 @@ class Pool(models.Model): # Set background color for headers and footers bg_colors = [("A1:AF", (1, 1, 1)), - (f"A1:{getcol(2 + pool_size * passage_width)}3", (0.8, 0.8, 0.8)), + (f"A1:{getcol(2 + passages.count() * passage_width)}3", (0.8, 0.8, 0.8)), (f"A{min_row - 1}:B{max_row}", (0.95, 0.95, 0.95)), (f"A{max_row + 1}:B{max_row + 3}", (0.8, 0.8, 0.8)), - (f"C{max_row + 1}:{getcol(2 + pool_size * passage_width)}{max_row + 3}", (0.9, 0.9, 0.9)), + (f"C{max_row + 1}:{getcol(2 + passages.count() * passage_width)}{max_row + 3}", (0.9, 0.9, 0.9)), (f"A{max_row + 5}:E{max_row + 5}", (0.8, 0.8, 0.8)), (f"A{max_row + 6}:E{max_row + 5 + pool_size}", (0.9, 0.9, 0.9)),] for bg_range, bg_color in bg_colors: @@ -1233,11 +1278,11 @@ class Pool(models.Model): # Define borders border_ranges = [("A1:AF", "0000"), - (f"A1:{getcol(2 + pool_size * passage_width)}{max_row + 3}", "1111"), + (f"A1:{getcol(2 + passages.count() * passage_width)}{max_row + 3}", "1111"), (f"A{max_row + 5}:E{max_row + pool_size + 5}", "1111"), (f"A1:B{max_row + 3}", "1113"), - (f"C1:{getcol(2 + (pool_size - 1) * passage_width)}1", "1113")] - for i in range(pool_size - 1): + (f"C1:{getcol(2 + (passages.count() - 1) * passage_width)}1", "1113")] + for i in range(passages.count() - 1): border_ranges.append((f"{getcol(1 + (i + 1) * passage_width)}2" f":{getcol(2 + (i + 1) * passage_width)}2", "1113")) border_ranges.append((f"{getcol(2 + (i + 1) * passage_width)}3" @@ -1264,7 +1309,7 @@ class Pool(models.Model): }) # Add range conditions - for i in range(pool_size): + for i in range(passages.count()): for j in range(passage_width): column = getcol(min_column + i * passage_width + j) min_note = 0 @@ -1286,9 +1331,9 @@ class Pool(models.Model): }) # Set number format, display only one decimal - number_format_ranges = [f"C{max_row + 1}:{getcol(2 + passage_width * pool_size)}{max_row + 1}", - f"C{max_row + 3}:{getcol(2 + passage_width * pool_size)}{max_row + 3}", - f"D{max_row + 6}:D{max_row + 5 + pool_size}",] + number_format_ranges = [f"C{max_row + 1}:{getcol(2 + passage_width * passages.count())}{max_row + 1}", + f"C{max_row + 3}:{getcol(2 + passage_width * passages.count())}{max_row + 3}", + f"D{max_row + 6}:D{max_row + 5 + passages.count()}",] for number_format_range in number_format_ranges: format_requests.append({ "repeatCell": { @@ -1383,7 +1428,7 @@ class Pool(models.Model): class Meta: verbose_name = _("pool") verbose_name_plural = _("pools") - ordering = ('round', 'letter',) + ordering = ('round', 'letter', 'room',) class Passage(models.Model): diff --git a/participation/tables.py b/participation/tables.py index bd2feb5..936062d 100644 --- a/participation/tables.py +++ b/participation/tables.py @@ -91,7 +91,7 @@ class PoolTable(tables.Table): ) def render_letter(self, record): - return format_lazy(_("Pool {letter}{round}"), letter=record.get_letter_display(), round=record.round) + return format_lazy(_("Pool {code}"), code=record.short_name) def render_teams(self, record): return ", ".join(participation.team.trigram for participation in record.participations.all()) \ diff --git a/participation/templates/participation/pool_detail.html b/participation/templates/participation/pool_detail.html index c94cb2a..66c3e11 100644 --- a/participation/templates/participation/pool_detail.html +++ b/participation/templates/participation/pool_detail.html @@ -25,6 +25,11 @@
{% trans "Letter:" %}
{{ pool.get_letter_display }}
+ + {% if pool.participations.count == 5 %} +
{% trans "Room:" %}
+
{{ pool.get_room_display }}
+ {% endif %}
{% trans "Teams:" %}
@@ -82,22 +87,12 @@
- {% trans "Download the scale sheet" %}{% if pool.passages.count == 5 %} — {% trans "Room" %} 1{% endif %} + {% trans "Download the scale sheet" %} - {% if pool.passages.count == 5 %} - - {% trans "Room" %} 2 - - {% endif %} - {% trans "Download the final notation sheet" %}{% if pool.passages.count == 5 %} — {% trans "Room" %} 1{% endif %} + {% trans "Download the final notation sheet" %} - {% if pool.passages.count == 5 %} - - {% trans "Room" %} 2 - - {% endif %} {% trans "Download all notation sheets" %} diff --git a/participation/templates/participation/tex/finale.tex b/participation/templates/participation/tex/finale.tex index dc9a787..2fa769f 100644 --- a/participation/templates/participation/tex/finale.tex +++ b/participation/templates/participation/tex/finale.tex @@ -37,14 +37,14 @@ \Large {\bf \tfjmedition$^{e}$ Tournoi Fran\c cais des Jeunes Math\'ematiciennes et Math\'ematiciens \tfjm}\\ \vspace{3mm} -Tour {{ pool.round }} \;-- Poule {{ pool.get_letter_display }}{{ page }} \;-- {% if pool.round == 1 %}{{ pool.tournament.date_start }}{% else %}{{ pool.tournament.date_end }}{% endif %} +Tour {{ pool.round }} \;-- Poule {{ pool.get_letter_display }}{% if pool.participations.count == 5 %} \;-- {{ pool.get_room_display }}{% endif %} \;-- {% if pool.round == 1 %}{{ pool.tournament.date_start }}{% else %}{{ pool.tournament.date_end }}{% endif %} \vspace{15mm} -\begin{tabular}{|p{35mm}{% for passage in passages.all %}{% if passages.count == 3 %}|p{3cm}|p{3cm}{% else %}|p{2.5cm}|p{2.5cm}{% endif %}{% endfor %}|}\hline -\multirow{2}{35mm}{\LARGE R\^ole} {% for passage in passages.all %}& \multicolumn{2}{c|}{ \Large Probl\`eme {{ passage.solution_number }}}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}} +\begin{tabular}{|p{40mm}{% for passage in passages.all %}{% if passages.count == 3 %}|p{3cm}|p{3cm}{% else %}|p{2.5cm}|p{2.5cm}{% endif %}{% endfor %}|}\hline +\multirow{2}{40mm}{\LARGE R\^ole} {% for passage in passages.all %}& \multicolumn{2}{c|}{ \Large Probl\`eme {{ passage.solution_number }}}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}} {% for passage in passages.all %}& \hspace{4mm} {\Large \'ECRIT} & \hspace{4mm} {\Large ORAL}{% endfor %} \\ \hline \multirow{2}{35mm}{\LARGE D\'efenseur\textperiodcentered{}se} {% for passage in passages.all %}& \multicolumn{2}{c|}{\Large {{ passage.defender.team.trigram }}}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}} {% for passage in passages.all %} diff --git a/participation/views.py b/participation/views.py index d75a77d..77a86fd 100644 --- a/participation/views.py +++ b/participation/views.py @@ -1760,13 +1760,6 @@ class NotationSheetTemplateView(VolunteerMixin, DetailView): context = super().get_context_data(**kwargs) passages = self.object.passages.all() - if passages.count() == 5: - page = self.request.GET.get('page', '1') - if not page.isnumeric() or page not in ['1', '2']: - page = '1' - passages = passages.filter(id__in=([passages[0].id, passages[2].id, passages[4].id] - if page == '1' else [passages[1].id, passages[3].id])) - context['page'] = page context['passages'] = passages context['esp'] = passages.count() * '&' @@ -1841,44 +1834,36 @@ class NotationSheetsArchiveView(VolunteerMixin, DetailView): for pool in pools: prefix = f"{pool.short_name}/" if len(pools) > 1 else "" for template_name in ['bareme', 'finale']: - pages = [1] if pool.participations.count() < 5 else [1, 2] - for page in pages: - juries = list(pool.juries.all()) + [None] + juries = list(pool.juries.all()) + [None] - for jury in juries: - if jury is not None and template_name == "bareme": - continue + for jury in juries: + if jury is not None and template_name == "bareme": + continue - context = {'jury': jury, 'page': page, 'pool': pool, - 'tfjm_number': timezone.now().year - 2010} + context = {'jury': jury, 'pool': pool, + 'tfjm_number': timezone.now().year - 2010} - passages = pool.passages.all() - if passages.count() == 5: - passages = passages.filter( - id__in=([passages[0].id, passages[2].id, passages[4].id] - if page == '1' else [passages[1].id, passages[3].id])) + passages = pool.passages.all() + context['passages'] = passages + context['esp'] = passages.count() * '&' - context['passages'] = passages - context['esp'] = passages.count() * '&' + tex = render_to_string(f"participation/tex/{template_name}.tex", + context=context, request=self.request) + temp_dir = mkdtemp() + with open(os.path.join(temp_dir, "texput.tex"), "w") as f: + f.write(tex) - tex = render_to_string(f"participation/tex/{template_name}.tex", - context=context, request=self.request) - temp_dir = mkdtemp() - with open(os.path.join(temp_dir, "texput.tex"), "w") as f: - f.write(tex) + process = subprocess.Popen( + ["pdflatex", "-interaction=nonstopmode", f"-output-directory={temp_dir}", + os.path.join(temp_dir, "texput.tex"), ]) + process.wait() - process = subprocess.Popen( - ["pdflatex", "-interaction=nonstopmode", f"-output-directory={temp_dir}", - os.path.join(temp_dir, "texput.tex"), ]) - process.wait() + sheet_name = f"Barème pour la poule {pool.short_name}" if template_name == "bareme" \ + else (f"Feuille de notation pour la poule {pool.short_name}" + f" - {str(jury) if jury else 'Vierge'}") - sheet_name = f"Barème pour la poule {pool.short_name}" if template_name == "bareme" \ - else (f"Feuille de notation pour la poule {pool.short_name}" - f" - {str(jury) if jury else 'Vierge'}") - sheet_name += " - page 2" if page == 2 else "" - - zf.write(os.path.join(temp_dir, "texput.pdf"), - f"{prefix}{sheet_name}.pdf") + zf.write(os.path.join(temp_dir, "texput.pdf"), + f"{prefix}{sheet_name}.pdf") response = HttpResponse(content_type="application/zip") response["Content-Disposition"] = f"attachment; filename=\"{filename}\""