Add observer notes

Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
Emmy D'Anello 2023-04-07 12:10:25 +02:00
parent 9eed5ca2a0
commit a382e089ae
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
9 changed files with 216 additions and 96 deletions

View File

@ -353,6 +353,7 @@ class Pool(models.Model):
await self.asave() await self.asave()
# Define the passage matrix according to the number of teams # Define the passage matrix according to the number of teams
table = []
if self.size == 3: if self.size == 3:
table = [ table = [
[0, 1, 2], [0, 1, 2],
@ -361,10 +362,10 @@ class Pool(models.Model):
] ]
elif self.size == 4: elif self.size == 4:
table = [ table = [
[0, 1, 2], [0, 1, 2, 3],
[1, 2, 3], [1, 2, 3, 0],
[2, 3, 0], [2, 3, 0, 1],
[3, 0, 1], [3, 0, 1, 2],
] ]
elif self.size == 5: elif self.size == 5:
table = [ table = [
@ -377,7 +378,7 @@ class Pool(models.Model):
for i, line in enumerate(table): for i, line in enumerate(table):
# Create the passage # Create the passage
await Passage.objects.acreate( passage = await Passage.objects.acreate(
pool=self.associated_pool, pool=self.associated_pool,
position=i + 1, position=i + 1,
solution_number=tds[line[0]].accepted, solution_number=tds[line[0]].accepted,
@ -386,6 +387,10 @@ class Pool(models.Model):
reporter=tds[line[2]].participation, reporter=tds[line[2]].participation,
defender_penalties=tds[line[0]].penalty_int, defender_penalties=tds[line[0]].penalty_int,
) )
if self.size == 4:
# Add observer for 4-teams pools
passage.observer = tds[line[3]].participation
await passage.asave()
return self.associated_pool return self.associated_pool

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: TFJM\n" "Project-Id-Version: TFJM\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-04-07 00:04+0200\n" "POT-Creation-Date: 2023-04-07 12:02+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n" "Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -33,7 +33,7 @@ msgstr "équipes"
msgid "tournament" msgid "tournament"
msgstr "tournoi" msgstr "tournoi"
#: draw/admin.py:60 draw/models.py:228 draw/models.py:415 #: draw/admin.py:60 draw/models.py:228 draw/models.py:420
#: participation/models.py:355 #: participation/models.py:355
msgid "round" msgid "round"
msgstr "tour" msgstr "tour"
@ -201,78 +201,78 @@ msgstr "poule associée"
msgid "The full pool instance." msgid "The full pool instance."
msgstr "L'instance complète de la poule." msgstr "L'instance complète de la poule."
#: draw/models.py:393 #: draw/models.py:398
#, python-brace-format #, python-brace-format
msgid "Pool {letter}{number}" msgid "Pool {letter}{number}"
msgstr "Poule {letter}{number}" msgstr "Poule {letter}{number}"
#: draw/models.py:396 draw/models.py:423 participation/admin.py:69 #: draw/models.py:401 draw/models.py:428 participation/admin.py:69
#: participation/admin.py:88 participation/models.py:421 #: participation/admin.py:88 participation/models.py:421
#: participation/models.py:430 participation/tables.py:82 #: participation/models.py:430 participation/tables.py:82
msgid "pool" msgid "pool"
msgstr "poule" msgstr "poule"
#: draw/models.py:397 participation/models.py:422 #: draw/models.py:402 participation/models.py:422
msgid "pools" msgid "pools"
msgstr "poules" msgstr "poules"
#: draw/models.py:409 participation/models.py:342 participation/models.py:562 #: draw/models.py:414 participation/models.py:342 participation/models.py:580
#: participation/models.py:592 participation/models.py:630 #: participation/models.py:610 participation/models.py:648
msgid "participation" msgid "participation"
msgstr "participation" msgstr "participation"
#: draw/models.py:430 #: draw/models.py:435
msgid "passage index" msgid "passage index"
msgstr "numéro de passage" msgstr "numéro de passage"
#: draw/models.py:431 #: draw/models.py:436
msgid "" msgid ""
"The passage order in the pool, between 0 and the size of the pool minus 1." "The passage order in the pool, between 0 and the size of the pool minus 1."
msgstr "" msgstr ""
"L'ordre de passage dans la poule, de 0 à la taille de la poule moins 1." "L'ordre de passage dans la poule, de 0 à la taille de la poule moins 1."
#: draw/models.py:439 #: draw/models.py:444
msgid "choose index" msgid "choose index"
msgstr "numéro de choix" msgstr "numéro de choix"
#: draw/models.py:440 #: draw/models.py:445
msgid "" msgid ""
"The choice order in the pool, between 0 and the size of the pool minus 1." "The choice order in the pool, between 0 and the size of the pool minus 1."
msgstr "" msgstr ""
"L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1." "L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1."
#: draw/models.py:446 draw/models.py:469 participation/models.py:444 #: draw/models.py:451 draw/models.py:474 participation/models.py:444
#: participation/models.py:599 #: participation/models.py:617
#, python-brace-format #, python-brace-format
msgid "Problem #{problem}" msgid "Problem #{problem}"
msgstr "Problème n°{problem}" msgstr "Problème n°{problem}"
#: draw/models.py:450 draw/models.py:473 #: draw/models.py:455 draw/models.py:478
msgid "accepted problem" msgid "accepted problem"
msgstr "problème accepté" msgstr "problème accepté"
#: draw/models.py:457 #: draw/models.py:462
msgid "passage dice" msgid "passage dice"
msgstr "dé d'ordre de passage" msgstr "dé d'ordre de passage"
#: draw/models.py:464 #: draw/models.py:469
msgid "choice dice" msgid "choice dice"
msgstr "dé d'ordre de choix" msgstr "dé d'ordre de choix"
#: draw/models.py:478 #: draw/models.py:483
msgid "rejected problems" msgid "rejected problems"
msgstr "problèmes rejetés" msgstr "problèmes rejetés"
#: draw/models.py:504 #: draw/models.py:509
#, python-brace-format #, python-brace-format
msgid "Draw of the team {trigram} for the pool {letter}{number}" msgid "Draw of the team {trigram} for the pool {letter}{number}"
msgstr "Tirage de l'équipe {trigram} pour la poule {letter}{number}" msgstr "Tirage de l'équipe {trigram} pour la poule {letter}{number}"
#: draw/models.py:510 #: draw/models.py:515
msgid "team draw" msgid "team draw"
msgstr "tirage d'équipe" msgstr "tirage d'équipe"
#: draw/models.py:511 #: draw/models.py:516
msgid "team draws" msgid "team draws"
msgstr "tirages d'équipe" msgstr "tirages d'équipe"
@ -439,16 +439,16 @@ msgid "defender"
msgstr "défenseur⋅se" msgstr "défenseur⋅se"
#: participation/admin.py:61 participation/models.py:458 #: participation/admin.py:61 participation/models.py:458
#: participation/models.py:642 #: participation/models.py:660
msgid "opponent" msgid "opponent"
msgstr "opposant⋅e" msgstr "opposant⋅e"
#: participation/admin.py:65 participation/models.py:465 #: participation/admin.py:65 participation/models.py:465
#: participation/models.py:643 #: participation/models.py:661
msgid "reporter" msgid "reporter"
msgstr "rapporteur⋅e" msgstr "rapporteur⋅e"
#: participation/admin.py:120 participation/models.py:597 #: participation/admin.py:120 participation/models.py:615
msgid "problem" msgid "problem"
msgstr "numéro de problème" msgstr "numéro de problème"
@ -706,11 +706,15 @@ msgstr "position"
msgid "defended solution" msgid "defended solution"
msgstr "solution défendue" msgstr "solution défendue"
#: participation/models.py:470 #: participation/models.py:475
msgid "observer"
msgstr "observateur⋅rice"
#: participation/models.py:480
msgid "penalties" msgid "penalties"
msgstr "pénalités" msgstr "pénalités"
#: participation/models.py:472 #: participation/models.py:482
msgid "" msgid ""
"Number of penalties for the defender. The defender will loose a 0.5 " "Number of penalties for the defender. The defender will loose a 0.5 "
"coefficient per penalty." "coefficient per penalty."
@ -718,120 +722,124 @@ msgstr ""
"Nombre de pénalités pour læ défenseur⋅se. Læ défenseur⋅se perd un " "Nombre de pénalités pour læ défenseur⋅se. Læ défenseur⋅se perd un "
"coefficient 0.5 sur sa présentation orale par pénalité." "coefficient 0.5 sur sa présentation orale par pénalité."
#: participation/models.py:532 participation/models.py:535 #: participation/models.py:547 participation/models.py:550
#: participation/models.py:538 #: participation/models.py:553 participation/models.py:556
#, python-brace-format #, python-brace-format
msgid "Team {trigram} is not registered in the pool." msgid "Team {trigram} is not registered in the pool."
msgstr "L'équipe {trigram} n'est pas inscrite dans la poule." msgstr "L'équipe {trigram} n'est pas inscrite dans la poule."
#: participation/models.py:543 #: participation/models.py:561
#, python-brace-format #, python-brace-format
msgid "Passage of {defender} for problem {problem}" msgid "Passage of {defender} for problem {problem}"
msgstr "Passage de {defender} pour le problème {problem}" msgstr "Passage de {defender} pour le problème {problem}"
#: participation/models.py:547 participation/models.py:556 #: participation/models.py:565 participation/models.py:574
#: participation/models.py:637 participation/models.py:679 #: participation/models.py:655 participation/models.py:697
msgid "passage" msgid "passage"
msgstr "passage" msgstr "passage"
#: participation/models.py:548 #: participation/models.py:566
msgid "passages" msgid "passages"
msgstr "passages" msgstr "passages"
#: participation/models.py:567 #: participation/models.py:585
msgid "difference" msgid "difference"
msgstr "différence" msgstr "différence"
#: participation/models.py:568 #: participation/models.py:586
msgid "Score to add/remove on the final score" msgid "Score to add/remove on the final score"
msgstr "Score à ajouter/retrancher au score final" msgstr "Score à ajouter/retrancher au score final"
#: participation/models.py:575 #: participation/models.py:593
msgid "tweak" msgid "tweak"
msgstr "harmonisation" msgstr "harmonisation"
#: participation/models.py:576 #: participation/models.py:594
msgid "tweaks" msgid "tweaks"
msgstr "harmonisations" msgstr "harmonisations"
#: participation/models.py:604 #: participation/models.py:622
msgid "solution for the final tournament" msgid "solution for the final tournament"
msgstr "solution pour la finale" msgstr "solution pour la finale"
#: participation/models.py:609 participation/models.py:648 #: participation/models.py:627 participation/models.py:666
msgid "file" msgid "file"
msgstr "fichier" msgstr "fichier"
#: participation/models.py:615 #: participation/models.py:633
#, python-brace-format #, python-brace-format
msgid "Solution of team {team} for problem {problem}" msgid "Solution of team {team} for problem {problem}"
msgstr "Solution de l'équipe {team} pour le problème {problem}" msgstr "Solution de l'équipe {team} pour le problème {problem}"
#: participation/models.py:617 #: participation/models.py:635
msgid "for final" msgid "for final"
msgstr "pour la finale" msgstr "pour la finale"
#: participation/models.py:620 #: participation/models.py:638
msgid "solution" msgid "solution"
msgstr "solution" msgstr "solution"
#: participation/models.py:621 #: participation/models.py:639
msgid "solutions" msgid "solutions"
msgstr "solutions" msgstr "solutions"
#: participation/models.py:654 #: participation/models.py:672
#, python-brace-format #, python-brace-format
msgid "Synthesis of {team} as {type} for problem {problem} of {defender}" msgid "Synthesis of {team} as {type} for problem {problem} of {defender}"
msgstr "" msgstr ""
"Note de synthèse de l'équipe {team} en tant que {type} pour le problème " "Note de synthèse de l'équipe {team} en tant que {type} pour le problème "
"{problem} de {defender}" "{problem} de {defender}"
#: participation/models.py:662 #: participation/models.py:680
msgid "synthesis" msgid "synthesis"
msgstr "note de synthèse" msgstr "note de synthèse"
#: participation/models.py:663 #: participation/models.py:681
msgid "syntheses" msgid "syntheses"
msgstr "notes de synthèse" msgstr "notes de synthèse"
#: participation/models.py:672 #: participation/models.py:690
msgid "jury" msgid "jury"
msgstr "jury" msgstr "jury"
#: participation/models.py:684 #: participation/models.py:702
msgid "defender writing note" msgid "defender writing note"
msgstr "note d'écrit de læ défenseur⋅se" msgstr "note d'écrit de læ défenseur⋅se"
#: participation/models.py:690 #: participation/models.py:708
msgid "defender oral note" msgid "defender oral note"
msgstr "note d'oral de læ défenseur⋅se" msgstr "note d'oral de læ défenseur⋅se"
#: participation/models.py:696 #: participation/models.py:714
msgid "opponent writing note" msgid "opponent writing note"
msgstr "note d'écrit de l'opposant⋅e" msgstr "note d'écrit de l'opposant⋅e"
#: participation/models.py:702 #: participation/models.py:720
msgid "opponent oral note" msgid "opponent oral note"
msgstr "note d'oral de l'opposant⋅e" msgstr "note d'oral de l'opposant⋅e"
#: participation/models.py:708 #: participation/models.py:726
msgid "reporter writing note" msgid "reporter writing note"
msgstr "note d'écrit de læ rapporteur⋅e" msgstr "note d'écrit de læ rapporteur⋅e"
#: participation/models.py:714 #: participation/models.py:732
msgid "reporter oral note" msgid "reporter oral note"
msgstr "note d'oral de læ rapporteur⋅e" msgstr "note d'oral de læ rapporteur⋅e"
#: participation/models.py:732 #: participation/models.py:738
msgid "observer note"
msgstr "note de l'observateur⋅rice"
#: participation/models.py:757
#, python-brace-format #, python-brace-format
msgid "Notes of {jury} for {passage}" msgid "Notes of {jury} for {passage}"
msgstr "Notes de {jury} pour le {passage}" msgstr "Notes de {jury} pour le {passage}"
#: participation/models.py:739 #: participation/models.py:764
msgid "note" msgid "note"
msgstr "note" msgstr "note"
#: participation/models.py:740 #: participation/models.py:765
msgid "notes" msgid "notes"
msgstr "notes" msgstr "notes"
@ -911,9 +919,9 @@ msgid "Join"
msgstr "Rejoindre" msgstr "Rejoindre"
#: participation/templates/participation/note_form.html:11 #: participation/templates/participation/note_form.html:11
#: participation/templates/participation/passage_detail.html:49 #: participation/templates/participation/passage_detail.html:54
#: participation/templates/participation/passage_detail.html:105 #: participation/templates/participation/passage_detail.html:120
#: participation/templates/participation/passage_detail.html:111 #: participation/templates/participation/passage_detail.html:126
#: participation/templates/participation/pool_add_jurys.html:35 #: participation/templates/participation/pool_add_jurys.html:35
#: participation/templates/participation/pool_detail.html:88 #: participation/templates/participation/pool_detail.html:88
#: participation/templates/participation/pool_detail.html:106 #: participation/templates/participation/pool_detail.html:106
@ -980,7 +988,7 @@ msgid "Upload solution"
msgstr "Envoyer une solution" msgstr "Envoyer une solution"
#: participation/templates/participation/participation_detail.html:59 #: participation/templates/participation/participation_detail.html:59
#: participation/templates/participation/passage_detail.html:117 #: participation/templates/participation/passage_detail.html:132
#: participation/templates/participation/pool_detail.html:116 #: participation/templates/participation/pool_detail.html:116
#: participation/templates/participation/team_detail.html:185 #: participation/templates/participation/team_detail.html:185
#: participation/templates/participation/upload_motivation_letter.html:13 #: participation/templates/participation/upload_motivation_letter.html:13
@ -1019,73 +1027,85 @@ msgstr "Opposant⋅e :"
msgid "Reporter:" msgid "Reporter:"
msgstr "Rapporteur⋅e :" msgstr "Rapporteur⋅e :"
#: participation/templates/participation/passage_detail.html:28 #: participation/templates/participation/passage_detail.html:29
msgid "Observer:"
msgstr "Observateur⋅rice :"
#: participation/templates/participation/passage_detail.html:33
msgid "Defended solution:" msgid "Defended solution:"
msgstr "Solution défendue" msgstr "Solution défendue"
#: participation/templates/participation/passage_detail.html:31 #: participation/templates/participation/passage_detail.html:36
msgid "Defender penalties count:" msgid "Defender penalties count:"
msgstr "Nombre de pénalités :" msgstr "Nombre de pénalités :"
#: participation/templates/participation/passage_detail.html:34 #: participation/templates/participation/passage_detail.html:39
msgid "Syntheses:" msgid "Syntheses:"
msgstr "Notes de synthèse :" msgstr "Notes de synthèse :"
#: participation/templates/participation/passage_detail.html:39 #: participation/templates/participation/passage_detail.html:44
msgid "No synthesis was uploaded yet." msgid "No synthesis was uploaded yet."
msgstr "Aucune note de synthèse n'a encore été envoyée." msgstr "Aucune note de synthèse n'a encore été envoyée."
#: participation/templates/participation/passage_detail.html:47 #: participation/templates/participation/passage_detail.html:52
#: participation/templates/participation/passage_detail.html:110 #: participation/templates/participation/passage_detail.html:125
msgid "Update notes" msgid "Update notes"
msgstr "Modifier les notes" msgstr "Modifier les notes"
#: participation/templates/participation/passage_detail.html:53 #: participation/templates/participation/passage_detail.html:58
#: participation/templates/participation/passage_detail.html:116 #: participation/templates/participation/passage_detail.html:131
msgid "Upload synthesis" msgid "Upload synthesis"
msgstr "Envoyer une note de synthèse" msgstr "Envoyer une note de synthèse"
#: participation/templates/participation/passage_detail.html:61 #: participation/templates/participation/passage_detail.html:66
msgid "Notes detail" msgid "Notes detail"
msgstr "Détails des notes" msgstr "Détails des notes"
#: participation/templates/participation/passage_detail.html:68 #: participation/templates/participation/passage_detail.html:73
msgid "Average points for the defender writing:" msgid "Average points for the defender writing:"
msgstr "Moyenne de l'écrit de læ défenseur⋅se :" msgstr "Moyenne de l'écrit de læ défenseur⋅se :"
#: participation/templates/participation/passage_detail.html:71 #: participation/templates/participation/passage_detail.html:76
msgid "Average points for the defender oral:" msgid "Average points for the defender oral:"
msgstr "Moyenne de l'oral de læ défenseur⋅se :" msgstr "Moyenne de l'oral de læ défenseur⋅se :"
#: participation/templates/participation/passage_detail.html:74 #: participation/templates/participation/passage_detail.html:79
msgid "Average points for the opponent writing:" msgid "Average points for the opponent writing:"
msgstr "Moyenne de l'écrit de l'opposant⋅e :" msgstr "Moyenne de l'écrit de l'opposant⋅e :"
#: participation/templates/participation/passage_detail.html:77 #: participation/templates/participation/passage_detail.html:82
msgid "Average points for the opponent oral:" msgid "Average points for the opponent oral:"
msgstr "Moyenne de l'oral de l'opposant⋅e :" msgstr "Moyenne de l'oral de l'opposant⋅e :"
#: participation/templates/participation/passage_detail.html:80 #: participation/templates/participation/passage_detail.html:85
msgid "Average points for the reporter writing:" msgid "Average points for the reporter writing:"
msgstr "Moyenne de l'écrit de læ rapporteur⋅e :" msgstr "Moyenne de l'écrit de læ rapporteur⋅e :"
#: participation/templates/participation/passage_detail.html:83 #: participation/templates/participation/passage_detail.html:88
msgid "Average points for the reporter oral:" msgid "Average points for the reporter oral:"
msgstr "Moyenne de l'oral de læ rapporteur⋅e :" msgstr "Moyenne de l'oral de læ rapporteur⋅e :"
#: participation/templates/participation/passage_detail.html:90 #: participation/templates/participation/passage_detail.html:92
msgid "Average points for the observer oral:"
msgstr "Moyenne de l'oral de l'observateur⋅rice :"
#: participation/templates/participation/passage_detail.html:100
msgid "Defender points:" msgid "Defender points:"
msgstr "Points de læ défenseur⋅se :" msgstr "Points de læ défenseur⋅se :"
#: participation/templates/participation/passage_detail.html:93 #: participation/templates/participation/passage_detail.html:103
msgid "Opponent points:" msgid "Opponent points:"
msgstr "Points de l'opposant⋅e :" msgstr "Points de l'opposant⋅e :"
#: participation/templates/participation/passage_detail.html:96 #: participation/templates/participation/passage_detail.html:106
msgid "Reporter points:" msgid "Reporter points:"
msgstr "Points de læ rapporteur⋅e :" msgstr "Points de læ rapporteur⋅e :"
#: participation/templates/participation/passage_detail.html:104 #: participation/templates/participation/passage_detail.html:110
msgid "Observer points:"
msgstr "Points de l'observateur⋅rice :"
#: participation/templates/participation/passage_detail.html:119
#: participation/templates/participation/passage_form.html:11 #: participation/templates/participation/passage_form.html:11
msgid "Update passage" msgid "Update passage"
msgstr "Modifier le passage" msgstr "Modifier le passage"
@ -1546,33 +1566,33 @@ msgstr "L'équipe n'est pas encore validée."
msgid "Participation of team {trigram}" msgid "Participation of team {trigram}"
msgstr "Participation de l'équipe {trigram}" msgstr "Participation de l'équipe {trigram}"
#: participation/views.py:641 #: participation/views.py:643
msgid "You can't upload a solution after the deadline." msgid "You can't upload a solution after the deadline."
msgstr "Vous ne pouvez pas envoyer de solution après la date limite." msgstr "Vous ne pouvez pas envoyer de solution après la date limite."
#: participation/views.py:732 #: participation/views.py:734
#, python-brace-format #, python-brace-format
msgid "Jurys of {pool}" msgid "Jurys of {pool}"
msgstr "Juré⋅es de la {pool}" msgstr "Juré⋅es de la {pool}"
#: participation/views.py:759 #: participation/views.py:761
msgid "New TFJM² jury account" msgid "New TFJM² jury account"
msgstr "Nouveau compte de juré⋅e pour le TFJM²" msgstr "Nouveau compte de juré⋅e pour le TFJM²"
#: participation/views.py:772 #: participation/views.py:774
#, python-brace-format #, python-brace-format
msgid "The jury {name} has been successfully added!" msgid "The jury {name} has been successfully added!"
msgstr "Læ juré⋅e {name} a été ajouté⋅e avec succès !" msgstr "Læ juré⋅e {name} a été ajouté⋅e avec succès !"
#: participation/views.py:808 #: participation/views.py:810
msgid "The following user is not registered as a jury:" msgid "The following user is not registered as a jury:"
msgstr "L'utilisateur⋅rice suivant n'est pas inscrit⋅e en tant que juré⋅e :" msgstr "L'utilisateur⋅rice suivant n'est pas inscrit⋅e en tant que juré⋅e :"
#: participation/views.py:816 #: participation/views.py:818
msgid "Notes were successfully uploaded." msgid "Notes were successfully uploaded."
msgstr "Les notes ont bien été envoyées." msgstr "Les notes ont bien été envoyées."
#: participation/views.py:974 #: participation/views.py:979
msgid "You can't upload a synthesis after the deadline." 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." msgstr "Vous ne pouvez pas envoyer de note de synthèse après la date limite."

View File

@ -323,7 +323,7 @@ class PassageForm(forms.ModelForm):
class Meta: class Meta:
model = Passage model = Passage
fields = ('position', 'solution_number', 'defender', 'opponent', 'reporter', 'defender_penalties',) fields = ('position', 'solution_number', 'defender', 'opponent', 'reporter', 'observer', 'defender_penalties',)
class SynthesisForm(forms.ModelForm): class SynthesisForm(forms.ModelForm):
@ -350,4 +350,4 @@ class NoteForm(forms.ModelForm):
class Meta: class Meta:
model = Note model = Note
fields = ('defender_writing', 'defender_oral', 'opponent_writing', fields = ('defender_writing', 'defender_oral', 'opponent_writing',
'opponent_oral', 'reporter_writing', 'reporter_oral', ) 'opponent_oral', 'reporter_writing', 'reporter_oral', 'observer_oral', )

View File

@ -0,0 +1,45 @@
# Generated by Django 4.2 on 2023-04-07 10:07
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("participation", "0006_alter_passage_options_passage_position_and_more"),
]
operations = [
migrations.AddField(
model_name="note",
name="observer_oral",
field=models.SmallIntegerField(
choices=[
(-4, -4),
(-3, -3),
(-2, -2),
(-1, -1),
(0, 0),
(1, 1),
(2, 2),
(3, 3),
(4, 4),
],
default=0,
verbose_name="observer note",
),
),
migrations.AddField(
model_name="passage",
name="observer",
field=models.ForeignKey(
blank=True,
default=None,
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="+",
to="participation.participation",
verbose_name="observer",
),
),
]

View File

@ -466,6 +466,16 @@ class Passage(models.Model):
related_name="+", related_name="+",
) )
observer = models.ForeignKey(
Participation,
on_delete=models.PROTECT,
null=True,
blank=True,
default=None,
verbose_name=_("observer"),
related_name="+",
)
defender_penalties = models.PositiveSmallIntegerField( defender_penalties = models.PositiveSmallIntegerField(
verbose_name=_("penalties"), verbose_name=_("penalties"),
default=0, default=0,
@ -520,9 +530,14 @@ class Passage(models.Model):
def average_reporter(self) -> float: def average_reporter(self) -> float:
return self.average_reporter_writing + self.average_reporter_oral return self.average_reporter_writing + self.average_reporter_oral
@property
def average_observer(self) -> float:
return self.avg(note.observer_oral for note in self.notes.all())
def average(self, participation): def average(self, participation):
return self.average_defender if participation == self.defender else self.average_opponent \ return self.average_defender if participation == self.defender else self.average_opponent \
if participation == self.opponent else self.average_reporter if participation == self.reporter else 0 if participation == self.opponent else self.average_reporter if participation == self.reporter \
else self.average_observer if participation == self.observer else 0
def get_absolute_url(self): def get_absolute_url(self):
return reverse_lazy("participation:passage_detail", args=(self.pk,)) return reverse_lazy("participation:passage_detail", args=(self.pk,))
@ -537,6 +552,9 @@ class Passage(models.Model):
if self.reporter not in self.pool.participations.all(): if self.reporter not in self.pool.participations.all():
raise ValidationError(_("Team {trigram} is not registered in the pool.") raise ValidationError(_("Team {trigram} is not registered in the pool.")
.format(trigram=self.reporter.team.trigram)) .format(trigram=self.reporter.team.trigram))
if self.observer and self.observer not in self.pool.participations.all():
raise ValidationError(_("Team {trigram} is not registered in the pool.")
.format(trigram=self.observer.team.trigram))
return super().clean() return super().clean()
def __str__(self): def __str__(self):
@ -716,14 +734,21 @@ class Note(models.Model):
default=0, default=0,
) )
observer_oral = models.SmallIntegerField(
verbose_name=_("observer note"),
choices=zip(range(-4, 5), range(-4, 5)),
default=0,
)
def set_all(self, defender_writing: int, defender_oral: int, opponent_writing: int, opponent_oral: int, def set_all(self, defender_writing: int, defender_oral: int, opponent_writing: int, opponent_oral: int,
reporter_writing: int, reporter_oral: int): reporter_writing: int, reporter_oral: int, observer_oral: int = 0):
self.defender_writing = defender_writing self.defender_writing = defender_writing
self.defender_oral = defender_oral self.defender_oral = defender_oral
self.opponent_writing = opponent_writing self.opponent_writing = opponent_writing
self.opponent_oral = opponent_oral self.opponent_oral = opponent_oral
self.reporter_writing = reporter_writing self.reporter_writing = reporter_writing
self.reporter_oral = reporter_oral self.reporter_oral = reporter_oral
self.observer_oral = observer_oral
def get_absolute_url(self): def get_absolute_url(self):
return reverse_lazy("participation:passage_detail", args=(self.passage.pk,)) return reverse_lazy("participation:passage_detail", args=(self.passage.pk,))
@ -733,7 +758,7 @@ class Note(models.Model):
def __bool__(self): def __bool__(self):
return any((self.defender_writing, self.defender_oral, self.opponent_writing, self.opponent_oral, return any((self.defender_writing, self.defender_oral, self.opponent_writing, self.opponent_oral,
self.reporter_writing, self.reporter_oral)) self.reporter_writing, self.reporter_oral, self.observer_oral))
class Meta: class Meta:
verbose_name = _("note") verbose_name = _("note")

View File

@ -141,4 +141,4 @@ class NoteTable(tables.Table):
} }
model = Note model = Note
fields = ('jury', 'defender_writing', 'defender_oral', 'opponent_writing', 'opponent_oral', fields = ('jury', 'defender_writing', 'defender_oral', 'opponent_writing', 'opponent_oral',
'reporter_writing', 'reporter_oral',) 'reporter_writing', 'reporter_oral', 'observer_oral',)

View File

@ -25,6 +25,11 @@
<dt class="col-sm-3">{% trans "Reporter:" %}</dt> <dt class="col-sm-3">{% trans "Reporter:" %}</dt>
<dd class="col-sm-9"><a href="{{ passage.reporter.get_absolute_url }}">{{ passage.reporter.team }}</a></dd> <dd class="col-sm-9"><a href="{{ passage.reporter.get_absolute_url }}">{{ passage.reporter.team }}</a></dd>
{% if passage.observer %}
<dt class="col-sm-3">{% trans "Observer:" %}</dt>
<dd class="col-sm-9"><a href="{{ passage.observer.get_absolute_url }}">{{ passage.observer.team }}</a></dd>
{% endif %}
<dt class="col-sm-3">{% trans "Defended solution:" %}</dt> <dt class="col-sm-3">{% trans "Defended solution:" %}</dt>
<dd class="col-sm-9"><a href="{{ passage.defended_solution.file.url }}">{{ passage.defended_solution }}</a></dd> <dd class="col-sm-9"><a href="{{ passage.defended_solution.file.url }}">{{ passage.defended_solution }}</a></dd>
@ -82,6 +87,11 @@
<dt class="col-sm-8">{% trans "Average points for the reporter oral:" %}</dt> <dt class="col-sm-8">{% trans "Average points for the reporter oral:" %}</dt>
<dd class="col-sm-4">{{ passage.average_reporter_oral|floatformat }}/10</dd> <dd class="col-sm-4">{{ passage.average_reporter_oral|floatformat }}/10</dd>
{% if passage.observer %}
<dt class="col-sm-8">{% trans "Average points for the observer oral:" %}</dt>
<dd class="col-sm-4">{{ passage.average_observer|floatformat }}/4</dd>
{% endif %}
</dl> </dl>
<hr> <hr>
@ -95,6 +105,11 @@
<dt class="col-sm-8">{% trans "Reporter points:" %}</dt> <dt class="col-sm-8">{% trans "Reporter points:" %}</dt>
<dd class="col-sm-4">{{ passage.average_reporter|floatformat }}/19</dd> <dd class="col-sm-4">{{ passage.average_reporter|floatformat }}/19</dd>
{% if passage.observer %}
<dt class="col-sm-8">{% trans "Observer points:" %}</dt>
<dd class="col-sm-4">{{ passage.average_observer|floatformat }}/4</dd>
{% endif %}
</dl> </dl>
</div> </div>
</div> </div>

View File

@ -62,7 +62,7 @@ Tour {{ pool.round }} \;-- Poule {{ pool.get_letter_display }}{{ page }} \;-- {%
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$ & \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$
{% endfor %} & \hline {% endfor %} & \hline
{% if passages.count == 4 %} {% if passages.count == 4 %}
\multirow{4}{35mm}{\Large Intervention exceptionnelle}& \multicolumn{2}{c|}{\Large {{ passages.last.defender.team.trigram }}}{% for passage in passages.all %}{% if forloop.counter < 4 %} & \multicolumn{2}{c|}{\Large {{ passage.defender.team.trigram }}}{% endif %}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}} \multirow{4}{35mm}{\Large Intervention exceptionnelle}{% for passage in passages.all %} & \multicolumn{2}{c|}{\Large {{ passage.observer.team.trigram }}}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}}
& \multicolumn{2}{c|}{\phantom{asd asd} \phantom{asd asd}} & \multicolumn{2}{c|}{\phantom{asd asd} \phantom{asd asd}}
& \multicolumn{2}{c|}{\phantom{asd asd} \phantom{asd asd}} & \multicolumn{2}{c|}{\phantom{asd asd} \phantom{asd asd}}
& \multicolumn{2}{c|}{\phantom{asd asd} \phantom{asd asd}} & \multicolumn{2}{c|}{\phantom{asd asd} \phantom{asd asd}}

View File

@ -920,6 +920,9 @@ class PassageDetailView(LoginRequiredMixin, DetailView):
context["notes"] = NoteTable([note for note in self.object.notes.all() if note]) context["notes"] = NoteTable([note for note in self.object.notes.all() if note])
elif self.request.user.registration.is_admin: elif self.request.user.registration.is_admin:
context["notes"] = NoteTable([note for note in self.object.notes.all() if note]) context["notes"] = NoteTable([note for note in self.object.notes.all() if note])
if 'notes' in context and not self.object.observer:
# Only display the observer column for 4-teams pools
context['notes']._sequence.pop()
return context return context
@ -1003,3 +1006,10 @@ class NoteUpdateView(VolunteerMixin, UpdateView):
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission() return self.handle_no_permission()
def get_form(self, form_class=None):
form = super().get_form(form_class)
if not self.object.passage.observer:
# Set the note of the observer only for 4-teams pools
del form.fields['observer_oral']
return form