diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index 21aa517..3b49861 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-07-06 10:16+0200\n"
+"POT-Creation-Date: 2024-07-06 21:27+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Emmy D'Anello \n"
"Language-Team: LANGUAGE \n"
@@ -79,7 +79,7 @@ msgstr "Type de permission nécessaire pour écrire un message dans un canal."
#: chat/models.py:62 draw/admin.py:53 draw/admin.py:71 draw/admin.py:88
#: draw/models.py:27 participation/admin.py:79 participation/admin.py:144
#: participation/admin.py:176 participation/models.py:783
-#: participation/models.py:807 participation/models.py:1116
+#: participation/models.py:807 participation/models.py:1131
#: registration/models.py:763
#: registration/templates/registration/payment_form.html:53
msgid "tournament"
@@ -95,7 +95,7 @@ msgstr ""
#: chat/models.py:73 draw/models.py:446 draw/models.py:473
#: participation/admin.py:140 participation/admin.py:160
-#: participation/models.py:1651 participation/models.py:1660
+#: participation/models.py:1666 participation/models.py:1675
#: participation/tables.py:84
msgid "pool"
msgstr "poule"
@@ -265,7 +265,7 @@ msgid "teams"
msgstr "équipes"
#: draw/admin.py:92 draw/models.py:245 draw/models.py:465
-#: participation/models.py:1120
+#: participation/models.py:1135
msgid "round"
msgstr "tour"
@@ -634,7 +634,7 @@ msgstr "Le numéro du tour doit être entre 1 et {nb}."
msgid "rounds"
msgstr "tours"
-#: draw/models.py:268 participation/models.py:1128
+#: draw/models.py:268 participation/models.py:1143
msgid "letter"
msgstr "lettre"
@@ -672,12 +672,12 @@ msgstr "L'instance complète de la poule."
msgid "Pool {letter}{number}"
msgstr "Poule {letter}{number}"
-#: draw/models.py:447 participation/models.py:1652
+#: draw/models.py:447 participation/models.py:1667
msgid "pools"
msgstr "poules"
-#: draw/models.py:459 participation/models.py:1106 participation/models.py:1871
-#: participation/models.py:1901 participation/models.py:1943
+#: draw/models.py:459 participation/models.py:1121 participation/models.py:1886
+#: participation/models.py:1920 participation/models.py:1962
msgid "participation"
msgstr "participation"
@@ -701,9 +701,9 @@ msgid ""
msgstr ""
"L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1."
-#: draw/models.py:496 draw/models.py:519 participation/models.py:1237
-#: participation/models.py:1674 participation/models.py:1908
-#: participation/views.py:1489 participation/views.py:1754
+#: draw/models.py:496 draw/models.py:519 participation/models.py:1252
+#: participation/models.py:1689 participation/models.py:1927
+#: participation/views.py:1492 participation/views.py:1757
#, python-brace-format
msgid "Problem #{problem}"
msgstr "Problème n°{problem}"
@@ -919,26 +919,26 @@ msgid "selected for final"
msgstr "sélectionnée pour la finale"
#: participation/admin.py:124 participation/admin.py:188
-#: participation/models.py:1681 participation/tables.py:114
+#: participation/models.py:1696 participation/tables.py:114
msgid "defender"
msgstr "défenseur⋅se"
-#: participation/admin.py:128 participation/models.py:1688
-#: participation/models.py:1955
+#: participation/admin.py:128 participation/models.py:1703
+#: participation/models.py:1974
msgid "opponent"
msgstr "opposant⋅e"
-#: participation/admin.py:132 participation/models.py:1695
-#: participation/models.py:1956
+#: participation/admin.py:132 participation/models.py:1710
+#: participation/models.py:1975
msgid "reviewer"
msgstr "rapporteur⋅rice"
-#: participation/admin.py:136 participation/models.py:1702
-#: participation/models.py:1957
+#: participation/admin.py:136 participation/models.py:1717
+#: participation/models.py:1976
msgid "observer"
msgstr "observateur⋅rice"
-#: participation/admin.py:192 participation/models.py:1906
+#: participation/admin.py:192 participation/models.py:1925
msgid "problem"
msgstr "numéro de problème"
@@ -1239,7 +1239,7 @@ msgid "first phase date"
msgstr "date du premier tour"
#: participation/models.py:327
-msgid "limit date to upload the syntheses for the first phase"
+msgid "limit date to upload the written reviews for the first phase"
msgstr "date limite pour envoyer les notes de synthèses pour la première phase"
#: participation/models.py:332
@@ -1252,7 +1252,7 @@ msgstr ""
"cocher la case lorsque les solutions pour le second tour sont accessibles"
#: participation/models.py:342
-msgid "limit date to upload the syntheses for the second phase"
+msgid "limit date to upload the written reviews for the second phase"
msgstr "date limite d'envoi des notes de synthèse pour la seconde phase"
#: participation/models.py:347
@@ -1265,7 +1265,7 @@ msgstr ""
"cocher la case lorsque les solutions pour le second tour sont accessibles"
#: participation/models.py:357
-msgid "limit date to upload the syntheses for the third phase"
+msgid "limit date to upload the written reviews for the third phase"
msgstr ""
"date limite pour envoyer les notes de synthèses pour la troisième phase"
@@ -1294,7 +1294,7 @@ msgid "Final ranking"
msgstr "Classement final"
#: participation/models.py:481 participation/models.py:553
-#: participation/models.py:1312 participation/views.py:1728
+#: participation/models.py:1327 participation/views.py:1731
msgid "Team"
msgstr "Équipe"
@@ -1326,15 +1326,15 @@ msgstr "Scores jour 3"
msgid "Tweaks day 3"
msgstr "Ajustements 3"
-#: participation/models.py:485 participation/models.py:1312
-#: participation/views.py:1735
+#: participation/models.py:485 participation/models.py:1327
+#: participation/views.py:1738
msgid "Total"
msgstr "Total"
#: participation/models.py:485 participation/models.py:553
-#: participation/models.py:1312
+#: participation/models.py:1327
#: participation/templates/participation/tournament_harmonize.html:14
-#: participation/views.py:1738
+#: participation/views.py:1741
msgid "Rank"
msgstr "Rang"
@@ -1346,7 +1346,7 @@ msgstr "Score"
msgid "Mention"
msgstr "Mention"
-#: participation/models.py:698 participation/models.py:1581
+#: participation/models.py:698 participation/models.py:1596
msgid "Don't update the table structure for a better automated integration."
msgstr ""
"Ne pas mettre à jour la structure de la table pour une meilleure intégration "
@@ -1456,47 +1456,47 @@ msgstr ""
"tour, vous défendrez votre solution du problème "
"{problem}.
"
-#: participation/models.py:930 participation/models.py:988
-#: participation/models.py:1047
+#: participation/models.py:930 participation/models.py:993
+#: participation/models.py:1057
#, python-brace-format
msgid ""
"You will oppose the solution of the team {opponent} on the problem {problem}. You can upload your synthesis "
-"sheet on this page.
"
+"href='{solution_url}'>problem {problem}. You can upload your written "
+"review on this page."
msgstr ""
"Vous opposerez la solution de l'équipe {opponent} sur le problème {problem}. Vous pouvez envoyer votre note "
"de synthèse sur cette page.
"
-#: participation/models.py:939 participation/models.py:997
-#: participation/models.py:1056
+#: participation/models.py:939 participation/models.py:1002
+#: participation/models.py:1066
#, python-brace-format
msgid ""
"You will report the solution of the team {reviewer} on the problem {problem}. You can upload your synthesis sheet "
-"on this page.
"
+"href='{solution_url}'>problem {problem}. You can upload your written "
+"review on this page."
msgstr ""
"Vous rapporterez la solution de l'équipe {reviewer} sur le problème {problem}. Vous pouvez envoyer votre note "
"de synthèse sur cette page.
"
-#: participation/models.py:949 participation/models.py:1007
-#: participation/models.py:1066
+#: participation/models.py:949 participation/models.py:1012
+#: participation/models.py:1076
#, python-brace-format
msgid ""
"You will observe the solution of the team {observer} on the problem {problem}. You can upload your synthesis sheet "
-"on this page.
"
+"href='{solution_url}'>problem {problem}. You can upload your written "
+"review on this page."
msgstr ""
"Vous observerez la solution de l'équipe {observer} sur le problème {problem}. Vous pouvez envoyer votre note "
"de synthèse sur cette page.
"
-#: participation/models.py:969 registration/models.py:629
+#: participation/models.py:974 registration/models.py:629
msgid "First round"
msgstr "Premier tour"
-#: participation/models.py:981
+#: participation/models.py:986
#, python-brace-format
msgid ""
"For the second round, you will defend your "
@@ -1505,12 +1505,12 @@ msgstr ""
"Pour le second tour, vous défendrez votre "
"solution du problème {problem}.
"
-#: participation/models.py:1027 participation/models.py:1086
+#: participation/models.py:1037 participation/models.py:1101
#: registration/models.py:640
msgid "Second round"
msgstr "Second tour"
-#: participation/models.py:1040
+#: participation/models.py:1050
#, python-brace-format
msgid ""
"For the third round, you will defend your "
@@ -1519,7 +1519,7 @@ msgstr ""
"Pour le troisième tour, vous défendrez votre "
"solution du problème {problem}.
"
-#: participation/models.py:1092
+#: participation/models.py:1107
#, 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:1097
+#: participation/models.py:1112
msgid "Tournament ended"
msgstr "Tournoi terminé"
-#: participation/models.py:1107 participation/models.py:1150
+#: participation/models.py:1122 participation/models.py:1165
msgid "participations"
msgstr "participations"
-#: participation/models.py:1122 participation/models.py:1123
-#: participation/models.py:1124
+#: participation/models.py:1137 participation/models.py:1138
+#: participation/models.py:1139
#, python-brace-format
msgid "Round {round}"
msgstr "Tour {round}"
-#: participation/models.py:1138
+#: participation/models.py:1153
msgid "room"
msgstr "salle"
-#: participation/models.py:1140
+#: participation/models.py:1155
msgid "Room 1"
msgstr "Salle 1"
-#: participation/models.py:1141
+#: participation/models.py:1156
msgid "Room 2"
msgstr "Salle 2"
-#: participation/models.py:1144
+#: participation/models.py:1159
msgid "For 5-teams pools only"
msgstr "Pour les poules de 5 équipe uniquement"
-#: participation/models.py:1156
+#: participation/models.py:1171
msgid "juries"
msgstr "jurys"
-#: participation/models.py:1165
+#: participation/models.py:1180
msgid "president of the jury"
msgstr "président⋅e du jury"
-#: participation/models.py:1172
+#: participation/models.py:1187
msgid "BigBlueButton URL"
msgstr "Lien BigBlueButton"
-#: participation/models.py:1173
+#: participation/models.py:1188
msgid "The link of the BBB visio for this pool."
msgstr "Le lien du salon BBB pour cette poule."
-#: participation/models.py:1178
+#: participation/models.py:1193
msgid "results available"
msgstr "résultats disponibles"
-#: participation/models.py:1179
+#: participation/models.py:1194
msgid ""
"Check this case when results become accessible to teams. They stay "
"accessible to you. Only averages are given."
@@ -1587,65 +1587,65 @@ msgstr ""
"Ils restent toujours accessibles pour vous. Seules les moyennes sont "
"communiquées."
-#: participation/models.py:1211
+#: participation/models.py:1226
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:1238 participation/models.py:1312
-#: participation/views.py:1483 participation/views.py:1732
+#: participation/models.py:1253 participation/models.py:1327
+#: participation/views.py:1486 participation/views.py:1735
msgid "Problem"
msgstr "Problème"
-#: participation/models.py:1243 participation/views.py:1498
+#: participation/models.py:1258 participation/views.py:1501
msgid "Role"
msgstr "Rôle"
-#: participation/models.py:1248 participation/views.py:1532
-#: participation/views.py:1533
+#: participation/models.py:1263 participation/views.py:1535
+#: participation/views.py:1536
msgid "Juree"
msgstr "Juré⋅e"
-#: participation/models.py:1271 participation/models.py:1597
-#: participation/models.py:1619 participation/views.py:1602
+#: participation/models.py:1286 participation/models.py:1612
+#: participation/models.py:1634 participation/views.py:1605
msgid "Average"
msgstr "Moyenne"
-#: participation/models.py:1277 participation/views.py:1621
+#: participation/models.py:1292 participation/views.py:1624
msgid "Coefficient"
msgstr "Coefficien"
-#: participation/models.py:1278 participation/views.py:1664
+#: participation/models.py:1293 participation/views.py:1667
msgid "Subtotal"
msgstr "Sous-total"
-#: participation/models.py:1544
+#: participation/models.py:1559
#, python-brace-format
msgid "Input must be a valid integer between {min_note} and {max_note}."
msgstr "L'entrée doit être un entier valide entre {min_note} et {max_note}."
-#: participation/models.py:1632
+#: participation/models.py:1647
#, 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:1645
+#: participation/models.py:1660
#, python-brace-format
msgid "Pool {code} for tournament {tournament} with teams {teams}"
msgstr "Poule {code} du tournoi {tournament} avec les équipes {teams}"
-#: participation/models.py:1665
+#: participation/models.py:1680
msgid "position"
msgstr "position"
-#: participation/models.py:1672
+#: participation/models.py:1687
msgid "defended solution"
msgstr "solution défendue"
-#: participation/models.py:1710
+#: participation/models.py:1725
msgid "penalties"
msgstr "pénalités"
-#: participation/models.py:1712
+#: participation/models.py:1727
msgid ""
"Number of penalties for the defender. The defender will loose a 0.5 "
"coefficient per penalty."
@@ -1653,128 +1653,128 @@ 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:1838 participation/models.py:1841
-#: participation/models.py:1844 participation/models.py:1847
+#: participation/models.py:1853 participation/models.py:1856
+#: participation/models.py:1859 participation/models.py:1862
#, 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:1852
+#: participation/models.py:1867
#, python-brace-format
msgid "Passage of {defender} for problem {problem}"
msgstr "Passage de {defender} pour le problème {problem}"
-#: participation/models.py:1856 participation/models.py:1865
-#: participation/models.py:1950 participation/models.py:1993
+#: participation/models.py:1871 participation/models.py:1880
+#: participation/models.py:1969 participation/models.py:2012
msgid "passage"
msgstr "passage"
-#: participation/models.py:1857
+#: participation/models.py:1872
msgid "passages"
msgstr "passages"
-#: participation/models.py:1876
+#: participation/models.py:1891
msgid "difference"
msgstr "différence"
-#: participation/models.py:1877
+#: participation/models.py:1892
msgid "Score to add/remove on the final score"
msgstr "Score à ajouter/retrancher au score final"
-#: participation/models.py:1884
+#: participation/models.py:1899
msgid "tweak"
msgstr "harmonisation"
-#: participation/models.py:1885
+#: participation/models.py:1900
msgid "tweaks"
msgstr "harmonisations"
-#: participation/models.py:1913
+#: participation/models.py:1932
msgid "solution for the final tournament"
msgstr "solution pour la finale"
-#: participation/models.py:1918 participation/models.py:1962
+#: participation/models.py:1937 participation/models.py:1981
msgid "file"
msgstr "fichier"
-#: participation/models.py:1928
+#: participation/models.py:1947
#, 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:1930
+#: participation/models.py:1949
msgid "for final"
msgstr "pour la finale"
-#: participation/models.py:1933
+#: participation/models.py:1952
msgid "solution"
msgstr "solution"
-#: participation/models.py:1934
+#: participation/models.py:1953
msgid "solutions"
msgstr "solutions"
-#: participation/models.py:1968
+#: participation/models.py:1987
#, python-brace-format
-msgid "Synthesis of {team} as {type} for problem {problem} of {defender}"
+msgid "Written review 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:1976
-msgid "synthesis"
+#: participation/models.py:1995
+msgid "written review"
msgstr "note de synthèse"
-#: participation/models.py:1977
-msgid "syntheses"
+#: participation/models.py:1996
+msgid "written reviews"
msgstr "notes de synthèse"
-#: participation/models.py:1986
+#: participation/models.py:2005
msgid "jury"
msgstr "jury"
-#: participation/models.py:1998
+#: participation/models.py:2017
msgid "defender writing note"
msgstr "note d'écrit défenseur⋅se"
-#: participation/models.py:2004
+#: participation/models.py:2023
msgid "defender oral note"
msgstr "note d'oral défenseur⋅se"
-#: participation/models.py:2010
+#: participation/models.py:2029
msgid "opponent writing note"
msgstr "note d'écrit opposant⋅e"
-#: participation/models.py:2016
+#: participation/models.py:2035
msgid "opponent oral note"
msgstr "note d'oral opposant⋅e"
-#: participation/models.py:2022
+#: participation/models.py:2041
msgid "reviewer writing note"
msgstr "note d'écrit rapporteur⋅rice"
-#: participation/models.py:2028
+#: participation/models.py:2047
msgid "reviewer oral note"
msgstr "note d'oral du rapporteur⋅rice"
-#: participation/models.py:2034
+#: participation/models.py:2053
msgid "observer writing note"
msgstr "note d'écrit de l'observateur⋅rice"
-#: participation/models.py:2040
+#: participation/models.py:2059
msgid "observer oral note"
msgstr "note d'oral de l'observateur⋅rice"
-#: participation/models.py:2105
+#: participation/models.py:2124
#, python-brace-format
msgid "Notes of {jury} for {passage}"
msgstr "Notes de {jury} pour le {passage}"
-#: participation/models.py:2108
+#: participation/models.py:2127
msgid "note"
msgstr "note"
-#: participation/models.py:2109
+#: participation/models.py:2128
msgid "notes"
msgstr "notes"
@@ -1910,7 +1910,7 @@ msgstr "Envoyer une solution"
#: participation/templates/participation/upload_motivation_letter.html:13
#: participation/templates/participation/upload_notes.html:24
#: participation/templates/participation/upload_solution.html:11
-#: participation/templates/participation/upload_synthesis.html:18
+#: participation/templates/participation/upload_written_review.html:23
#: registration/templates/registration/upload_health_sheet.html:17
#: registration/templates/registration/upload_parental_authorization.html:17
#: registration/templates/registration/upload_photo_authorization.html:18
@@ -1963,7 +1963,7 @@ msgstr "Notes de synthèse :"
#: participation/templates/participation/passage_detail.html:53
#: participation/templates/participation/pool_detail.html:68
-msgid "No synthesis was uploaded yet."
+msgid "No review was uploaded yet."
msgstr "Aucune note de synthèse n'a encore été envoyée."
#: participation/templates/participation/passage_detail.html:61
@@ -1973,8 +1973,8 @@ msgstr "Modifier les notes"
#: participation/templates/participation/passage_detail.html:66
#: participation/templates/participation/passage_detail.html:187
-msgid "Upload synthesis"
-msgstr "Envoyer une note de synthèse"
+msgid "Upload review"
+msgstr "Envoyer la note de synthèse"
#: participation/templates/participation/passage_detail.html:74
msgid "Notes detail"
@@ -2374,15 +2374,15 @@ msgid "date of the random draw"
msgstr "date du tirage au sort"
#: participation/templates/participation/tournament_detail.html:41
-msgid "date of maximal syntheses submission for the first round"
+msgid "date of maximal written reviews submission for the first round"
msgstr "date limite de soumission des notes de synthèse pour le premier tour"
#: participation/templates/participation/tournament_detail.html:44
-msgid "date of maximal syntheses submission for the second round"
+msgid "date of maximal written reviews submission for the second round"
msgstr "date limite de soumission des notes de synthèse pour le second tour"
#: participation/templates/participation/tournament_detail.html:48
-msgid "date of maximal syntheses submission for the third round"
+msgid "date of maximal written reviews submission for the third round"
msgstr "date limite de soumission des notes de synthèse pour le troisième tour"
#: participation/templates/participation/tournament_detail.html:56
@@ -2462,6 +2462,42 @@ msgstr "Dépublier les notes pour le troisième tour"
msgid "Files available for download"
msgstr "Fichiers disponibles au téléchargement"
+#: participation/templates/participation/tournament_detail.html:236
+msgid "Validated team participant data spreadsheet"
+msgstr "Tableur des données des équipes validées"
+
+#: participation/templates/participation/tournament_detail.html:241
+msgid "All teams participant data spreadsheet"
+msgstr "Tableur des données de toutes les équipes"
+
+#: participation/templates/participation/tournament_detail.html:246
+msgid "Archive of all authorisations sorted by team and person"
+msgstr "Archive de toutes les autorisations triées par équipe et personne"
+
+#: participation/templates/participation/tournament_detail.html:251
+msgid "Archive of all submitted solutions sorted by team"
+msgstr "Archive de toutes les solutions envoyées triées par équipe"
+
+#: participation/templates/participation/tournament_detail.html:256
+msgid "Archive of all sent solutions sorted by problem"
+msgstr "Archive de toutes les solutions envoyées triées par problème"
+
+#: participation/templates/participation/tournament_detail.html:261
+msgid "Archive of all sent solutions sorted by pool"
+msgstr "Archive de toutes les solutions envoyées triées par poule"
+
+#: participation/templates/participation/tournament_detail.html:266
+msgid "Archive of all summary notes sorted by pool and passage"
+msgstr "Archive de toutes les notes de synthèse triées par poule et passage"
+
+#: participation/templates/participation/tournament_detail.html:272
+msgid "Note spreadsheet on Google Sheets"
+msgstr "Tableur de notes sur Google Sheets"
+
+#: participation/templates/participation/tournament_detail.html:277
+msgid "Archive of all printable note sheets sorted by pool"
+msgstr "Archive de toutes les fiches de notes imprimables triées par poule"
+
#: participation/templates/participation/tournament_harmonize.html:16
#: registration/models.py:655
msgid "Note"
@@ -2504,11 +2540,11 @@ msgstr ""
msgid "Download empty notation sheet"
msgstr "Télécharger la fiche de notation vierge"
-#: participation/templates/participation/upload_synthesis.html:9
+#: participation/templates/participation/upload_written_review.html:9
msgid "Templates:"
msgstr "Modèles :"
-#: participation/templates/participation/upload_synthesis.html:13
+#: participation/templates/participation/upload_written_review.html:14
msgid "Warning: non-free format"
msgstr "Attention : format non libre"
@@ -2656,96 +2692,96 @@ msgstr "Vous ne pouvez pas envoyer de solution après la date limite."
msgid "Solutions of team {trigram}.zip"
msgstr "Solutions de l'équipe {trigram}.zip"
-#: participation/views.py:1022
+#: participation/views.py:1023
#, python-brace-format
-msgid "Syntheses of team {trigram}.zip"
+msgid "Written reviews of team {trigram}.zip"
msgstr "Notes de synthèse de l'équipe {trigram}.zip"
-#: participation/views.py:1039 participation/views.py:1054
+#: participation/views.py:1040 participation/views.py:1056
#, python-brace-format
msgid "Solutions of {tournament}.zip"
msgstr "Solutions de {tournament}.zip"
-#: participation/views.py:1039 participation/views.py:1054
+#: participation/views.py:1041 participation/views.py:1057
#, python-brace-format
-msgid "Syntheses of {tournament}.zip"
+msgid "Written reviews of {tournament}.zip"
msgstr "Notes de synthèse de {tournament}.zip"
-#: participation/views.py:1063
+#: participation/views.py:1066
#, python-brace-format
msgid "Solutions for pool {pool} of tournament {tournament}.zip"
msgstr "Solutions pour la poule {pool} du tournoi {tournament}.zip"
-#: participation/views.py:1064
+#: participation/views.py:1067
#, python-brace-format
-msgid "Syntheses for pool {pool} of tournament {tournament}.zip"
+msgid "Written reviews for pool {pool} of tournament {tournament}.zip"
msgstr "Notes de synthèses pour la poule {pool} du tournoi {tournament}.zip"
-#: participation/views.py:1106
+#: participation/views.py:1109
#, python-brace-format
msgid "Jury of pool {pool} for {tournament} with teams {teams}"
msgstr "Jury de la poule {pool} pour {tournament} avec les équipes {teams}"
-#: participation/views.py:1122
+#: participation/views.py:1125
#, python-brace-format
msgid "The jury {name} is already in the pool!"
msgstr "{name} est déjà dans la poule !"
-#: participation/views.py:1142
+#: participation/views.py:1145
msgid "New jury account"
msgstr "Nouveau compte de juré⋅e"
-#: participation/views.py:1163
+#: participation/views.py:1166
#, python-brace-format
msgid "The jury {name} has been successfully added!"
msgstr "{name} a été ajouté⋅e avec succès en tant que juré⋅e !"
-#: participation/views.py:1199
+#: participation/views.py:1202
#, python-brace-format
msgid "The jury {name} has been successfully removed!"
msgstr "{name} a été retiré⋅e avec succès du jury !"
-#: participation/views.py:1225
+#: participation/views.py:1228
#, python-brace-format
msgid "The jury {name} has been successfully promoted president!"
msgstr "{name} a été nommé⋅e président⋅e du jury !"
-#: participation/views.py:1253
+#: participation/views.py:1256
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 :"
-#: participation/views.py:1269
+#: participation/views.py:1272
msgid "Notes were successfully uploaded."
msgstr "Les notes ont bien été envoyées."
-#: participation/views.py:1504
+#: participation/views.py:1507
msgid "Defender"
msgstr "Défenseur⋅se"
-#: participation/views.py:1510
+#: participation/views.py:1513
msgid "Opponent"
msgstr "Opposant⋅e"
-#: participation/views.py:1517
+#: participation/views.py:1520
msgid "Reviewer"
msgstr "Rapporteur⋅rice"
-#: participation/views.py:1524
+#: participation/views.py:1527
msgid "Observer"
msgstr "Observateur⋅rice"
-#: participation/views.py:1895
+#: participation/views.py:1898
#, 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:1900
+#: participation/views.py:1903
#, python-brace-format
msgid "Notation sheets of {tournament}.zip"
msgstr "Feuilles de notation de {tournament}.zip"
-#: participation/views.py:2067
-msgid "You can't upload a synthesis after the deadline."
+#: participation/views.py:2070
+msgid "You can't upload a written review after the deadline."
msgstr "Vous ne pouvez pas envoyer de note de synthèse après la date limite."
#: registration/admin.py:53 registration/admin.py:69 registration/admin.py:85
diff --git a/participation/admin.py b/participation/admin.py
index ca73ee3..a94b57e 100644
--- a/participation/admin.py
+++ b/participation/admin.py
@@ -4,7 +4,7 @@
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
-from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament, Tweak
+from .models import Note, Participation, Passage, Pool, Solution, Team, Tournament, Tweak, WrittenReview
class ParticipationInline(admin.StackedInline):
@@ -32,8 +32,8 @@ class SolutionInline(admin.TabularInline):
show_change_link = True
-class SynthesisInline(admin.TabularInline):
- model = Synthesis
+class WrittenReviewInline(admin.TabularInline):
+ model = WrittenReview
extra = 0
ordering = ('passage__solution_number', 'type',)
autocomplete_fields = ('passage',)
@@ -95,7 +95,7 @@ class ParticipationAdmin(admin.ModelAdmin):
search_fields = ('team__name', 'team__trigram',)
list_filter = ('valid', 'tournament',)
autocomplete_fields = ('team', 'tournament',)
- inlines = (SolutionInline, SynthesisInline,)
+ inlines = (SolutionInline, WrittenReviewInline,)
@admin.register(Pool)
@@ -178,19 +178,19 @@ class SolutionAdmin(admin.ModelAdmin):
return Tournament.final_tournament() if record.final_solution else record.participation.tournament
-@admin.register(Synthesis)
-class SynthesisAdmin(admin.ModelAdmin):
+@admin.register(WrittenReview)
+class WrittenReviewAdmin(admin.ModelAdmin):
list_display = ('participation', 'type', 'defender', 'passage',)
list_filter = ('participation__tournament', 'type', 'passage__solution_number',)
search_fields = ('participation__team__name', 'participation__team__trigram',)
autocomplete_fields = ('participation', 'passage',)
@admin.display(description=_("defender"))
- def defender(self, record: Synthesis):
+ def defender(self, record: WrittenReview):
return record.passage.defender
@admin.display(description=_("problem"))
- def problem(self, record: Synthesis):
+ def problem(self, record: WrittenReview):
return record.passage.solution_number
diff --git a/participation/api/serializers.py b/participation/api/serializers.py
index ce6866d..86d25ec 100644
--- a/participation/api/serializers.py
+++ b/participation/api/serializers.py
@@ -3,7 +3,7 @@
from rest_framework import serializers
-from ..models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament
+from ..models import Note, Participation, Passage, Pool, Solution, Team, Tournament, WrittenReview
class NoteSerializer(serializers.ModelSerializer):
@@ -38,9 +38,9 @@ class SolutionSerializer(serializers.ModelSerializer):
fields = '__all__'
-class SynthesisSerializer(serializers.ModelSerializer):
+class WrittenReviewSerializer(serializers.ModelSerializer):
class Meta:
- model = Synthesis
+ model = WrittenReview
fields = '__all__'
@@ -58,9 +58,9 @@ class TournamentSerializer(serializers.ModelSerializer):
class Meta:
model = Tournament
fields = ('id', 'pk', 'name', 'date_start', 'date_end', 'place', 'max_teams', 'price', 'remote',
- 'inscription_limit', 'solution_limit', 'solutions_draw', 'syntheses_first_phase_limit',
- 'solutions_available_second_phase', 'syntheses_second_phase_limit',
- 'solutions_available_third_phase', 'syntheses_third_phase_limit',
+ 'inscription_limit', 'solution_limit', 'solutions_draw', 'reviews_first_phase_limit',
+ 'solutions_available_second_phase', 'reviews_second_phase_limit',
+ 'solutions_available_third_phase', 'reviews_third_phase_limit',
'description', 'organizers', 'final', 'participations',)
diff --git a/participation/api/urls.py b/participation/api/urls.py
index 7034d0c..5dd5003 100644
--- a/participation/api/urls.py
+++ b/participation/api/urls.py
@@ -2,7 +2,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
from .views import NoteViewSet, ParticipationViewSet, PassageViewSet, PoolViewSet, \
- SolutionViewSet, SynthesisViewSet, TeamViewSet, TournamentViewSet, TweakViewSet
+ SolutionViewSet, TeamViewSet, TournamentViewSet, TweakViewSet, WrittenReviewViewSet
def register_participation_urls(router, path):
@@ -13,8 +13,8 @@ def register_participation_urls(router, path):
router.register(path + "/participation", ParticipationViewSet)
router.register(path + "/passage", PassageViewSet)
router.register(path + "/pool", PoolViewSet)
+ router.register(path + "/review", WrittenReviewViewSet)
router.register(path + "/solution", SolutionViewSet)
- router.register(path + "/synthesis", SynthesisViewSet)
router.register(path + "/team", TeamViewSet)
router.register(path + "/tournament", TournamentViewSet)
router.register(path + "/tweak", TweakViewSet)
diff --git a/participation/api/views.py b/participation/api/views.py
index 923d29d..097e739 100644
--- a/participation/api/views.py
+++ b/participation/api/views.py
@@ -4,8 +4,8 @@ from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.viewsets import ModelViewSet
from .serializers import NoteSerializer, ParticipationSerializer, PassageSerializer, PoolSerializer, \
- SolutionSerializer, SynthesisSerializer, TeamSerializer, TournamentSerializer, TweakSerializer
-from ..models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament, Tweak
+ SolutionSerializer, TeamSerializer, TournamentSerializer, TweakSerializer, WrittenReviewSerializer
+from ..models import Note, Participation, Passage, Pool, Solution, Team, Tournament, Tweak, WrittenReview
class NoteViewSet(ModelViewSet):
@@ -44,9 +44,9 @@ class SolutionViewSet(ModelViewSet):
filterset_fields = ['participation', 'number', 'problem', 'final_solution', ]
-class SynthesisViewSet(ModelViewSet):
- queryset = Synthesis.objects.all()
- serializer_class = SynthesisSerializer
+class WrittenReviewViewSet(ModelViewSet):
+ queryset = WrittenReview.objects.all()
+ serializer_class = WrittenReviewSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['participation', 'number', 'passage', 'type', ]
@@ -64,9 +64,9 @@ class TournamentViewSet(ModelViewSet):
serializer_class = TournamentSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['name', 'date_start', 'date_end', 'place', 'max_teams', 'price', 'remote',
- 'inscription_limit', 'solution_limit', 'solutions_draw', 'syntheses_first_phase_limit',
- 'solutions_available_second_phase', 'syntheses_second_phase_limit',
- 'solutions_available_third_phase', 'syntheses_third_phase_limit',
+ 'inscription_limit', 'solution_limit', 'solutions_draw', 'reviews_first_phase_limit',
+ 'solutions_available_second_phase', 'reviews_second_phase_limit',
+ 'solutions_available_third_phase', 'reviews_third_phase_limit',
'description', 'organizers', 'final', ]
diff --git a/participation/forms.py b/participation/forms.py
index 2178cd1..9cdd64d 100644
--- a/participation/forms.py
+++ b/participation/forms.py
@@ -16,7 +16,7 @@ from pypdf import PdfReader
from registration.models import VolunteerRegistration
from tfjm import settings
-from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament
+from .models import Note, Participation, Passage, Pool, Solution, Team, Tournament, WrittenReview
class TeamForm(forms.ModelForm):
@@ -137,7 +137,7 @@ class TournamentForm(forms.ModelForm):
if settings.NB_ROUNDS < 3:
del self.fields['date_third_phase']
del self.fields['solutions_available_third_phase']
- del self.fields['syntheses_third_phase_limit']
+ del self.fields['reviews_third_phase_limit']
if not settings.PAYMENT_MANAGEMENT:
del self.fields['price']
@@ -151,14 +151,14 @@ class TournamentForm(forms.ModelForm):
'solution_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%d %H:%M'),
'solutions_draw': forms.DateTimeInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%d %H:%M'),
'date_first_phase': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
- 'syntheses_first_phase_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'},
- format='%Y-%m-%d %H:%M'),
+ 'reviews_first_phase_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'},
+ format='%Y-%m-%d %H:%M'),
'date_second_phase': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
- 'syntheses_second_phase_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'},
- format='%Y-%m-%d %H:%M'),
+ 'reviews_second_phase_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'},
+ format='%Y-%m-%d %H:%M'),
'date_third_phase': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
- 'syntheses_third_phase_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'},
- format='%Y-%m-%d %H:%M'),
+ 'reviews_third_phase_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'},
+ format='%Y-%m-%d %H:%M'),
'organizers': forms.SelectMultiple(attrs={
'class': 'selectpicker',
'data-live-search': 'true',
@@ -359,7 +359,7 @@ class PassageForm(forms.ModelForm):
fields = ('position', 'solution_number', 'defender', 'opponent', 'reviewer', 'opponent', 'defender_penalties',)
-class SynthesisForm(forms.ModelForm):
+class WrittenReviewForm(forms.ModelForm):
def clean_file(self):
if "file" in self.files:
file = self.files["file"]
@@ -375,11 +375,11 @@ class SynthesisForm(forms.ModelForm):
def save(self, commit=True):
"""
- Don't save a synthesis with this way. Use a view instead
+ Don't save a written review with this way. Use a view instead
"""
class Meta:
- model = Synthesis
+ model = WrittenReview
fields = ('file',)
diff --git a/participation/migrations/0020_rename_synthesis_writtenreview_and_more.py b/participation/migrations/0020_rename_synthesis_writtenreview_and_more.py
new file mode 100644
index 0000000..e292683
--- /dev/null
+++ b/participation/migrations/0020_rename_synthesis_writtenreview_and_more.py
@@ -0,0 +1,75 @@
+# Generated by Django 5.0.6 on 2024-07-06 19:19
+
+import django.utils.timezone
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("participation", "0019_note_observer_oral_note_observer_writing_and_more"),
+ ]
+
+ operations = [
+ migrations.RenameModel(
+ old_name="Synthesis",
+ new_name="WrittenReview",
+ ),
+ migrations.AlterModelOptions(
+ name="writtenreview",
+ options={
+ "ordering": ("passage__pool__round", "type"),
+ "verbose_name": "written review",
+ "verbose_name_plural": "written reviews",
+ },
+ ),
+ migrations.RenameField(
+ model_name="tournament",
+ old_name="syntheses_first_phase_limit",
+ new_name="reviews_first_phase_limit",
+ ),
+ migrations.RenameField(
+ model_name="tournament",
+ old_name="syntheses_second_phase_limit",
+ new_name="reviews_second_phase_limit",
+ ),
+ migrations.RenameField(
+ model_name="tournament",
+ old_name="syntheses_third_phase_limit",
+ new_name="reviews_third_phase_limit",
+ ),
+ migrations.AlterField(
+ model_name="tournament",
+ name="reviews_first_phase_limit",
+ field=models.DateTimeField(
+ default=django.utils.timezone.now,
+ verbose_name="limit date to upload the written reviews for the first phase",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="tournament",
+ name="reviews_second_phase_limit",
+ field=models.DateTimeField(
+ default=django.utils.timezone.now,
+ verbose_name="limit date to upload the written reviews for the second phase",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="tournament",
+ name="reviews_third_phase_limit",
+ field=models.DateTimeField(
+ default=django.utils.timezone.now,
+ verbose_name="limit date to upload the written reviews for the third phase",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="writtenreview",
+ name="passage",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="written_reviews",
+ to="participation.passage",
+ verbose_name="passage",
+ ),
+ ),
+ ]
diff --git a/participation/models.py b/participation/models.py
index 383b9b5..2452e30 100644
--- a/participation/models.py
+++ b/participation/models.py
@@ -323,8 +323,8 @@ class Tournament(models.Model):
default=date.today,
)
- syntheses_first_phase_limit = models.DateTimeField(
- verbose_name=_("limit date to upload the syntheses for the first phase"),
+ reviews_first_phase_limit = models.DateTimeField(
+ verbose_name=_("limit date to upload the written reviews for the first phase"),
default=timezone.now,
)
@@ -338,8 +338,8 @@ class Tournament(models.Model):
default=False,
)
- syntheses_second_phase_limit = models.DateTimeField(
- verbose_name=_("limit date to upload the syntheses for the second phase"),
+ reviews_second_phase_limit = models.DateTimeField(
+ verbose_name=_("limit date to upload the written reviews for the second phase"),
default=timezone.now,
)
@@ -353,8 +353,8 @@ class Tournament(models.Model):
default=False,
)
- syntheses_third_phase_limit = models.DateTimeField(
- verbose_name=_("limit date to upload the syntheses for the third phase"),
+ reviews_third_phase_limit = models.DateTimeField(
+ verbose_name=_("limit date to upload the written reviews for the third phase"),
default=timezone.now,
)
@@ -442,10 +442,10 @@ class Tournament(models.Model):
return Solution.objects.filter(participation__tournament=self)
@property
- def syntheses(self):
+ def written_reviews(self):
if self.final:
- return Synthesis.objects.filter(final_solution=True)
- return Synthesis.objects.filter(participation__tournament=self)
+ return WrittenReview.objects.filter(final_solution=True)
+ return WrittenReview.objects.filter(participation__tournament=self)
@property
def best_format(self):
@@ -911,7 +911,7 @@ class Participation(models.Model):
'priority': 1,
'content': content,
})
- elif timezone.now() <= tournament.syntheses_first_phase_limit + timedelta(hours=2):
+ elif timezone.now() <= tournament.reviews_first_phase_limit + timedelta(hours=2):
defender_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=1, defender=self)
opponent_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=1, opponent=self)
reviewer_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=1, reviewer=self)
@@ -929,7 +929,7 @@ class Participation(models.Model):
opponent_text = _("You will oppose the solution of the team {opponent} on the "
"problem {problem}. "
- "You can upload your synthesis sheet on this page.
")
+ "You can upload your written review on this page.
")
solution_url = opponent_passage.defended_solution.file.url
passage_url = reverse_lazy("participation:passage_detail", args=(opponent_passage.pk,))
opponent_content = format_lazy(opponent_text, opponent=opponent_passage.defender.team.trigram,
@@ -938,7 +938,7 @@ class Participation(models.Model):
reviewer_text = _("You will report the solution of the team {reviewer} on the "
"problem {problem}. "
- "You can upload your synthesis sheet on this page.
")
+ "You can upload your written review on this page.
")
solution_url = reviewer_passage.defended_solution.file.url
passage_url = reverse_lazy("participation:passage_detail", args=(reviewer_passage.pk,))
reviewer_content = format_lazy(reviewer_text, reviewer=reviewer_passage.defender.team.trigram,
@@ -948,7 +948,7 @@ class Participation(models.Model):
if observer_passage:
observer_text = _("You will observe the solution of the team {observer} on the "
"problem {problem}. "
- "You can upload your synthesis sheet on this page.
")
+ "You can upload your written review on this page.")
solution_url = observer_passage.defended_solution.file.url
passage_url = reverse_lazy("participation:passage_detail", args=(observer_passage.pk,))
observer_content = format_lazy(observer_text,
@@ -959,24 +959,24 @@ class Participation(models.Model):
observer_content = ""
if settings.TFJM_APP == "TFJM":
- syntheses_template_begin = f"{settings.STATIC_URL}tfjm/Fiche_synthèse."
- syntheses_templates = " — ".join(f"{ext.upper()}"
- for ext in ["pdf", "tex", "odt", "docx"])
+ reviews_template_begin = f"{settings.STATIC_URL}tfjm/Fiche_synthèse."
+ reviews_templates = " — ".join(f"{ext.upper()}"
+ for ext in ["pdf", "tex", "odt", "docx"])
else:
- syntheses_template_begin = f"{settings.STATIC_URL}eteam/Written_review."
- syntheses_templates = " — ".join(f"{ext.upper()}"
- for ext in ["pdf", "tex"])
- syntheses_templates_content = f"{_('Templates:')} {syntheses_templates}
"
+ reviews_template_begin = f"{settings.STATIC_URL}eteam/Written_review."
+ reviews_templates = " — ".join(f"{ext.upper()}"
+ for ext in ["pdf", "tex"])
+ reviews_templates_content = f"{_('Templates:')} {reviews_templates}
"
content = defender_content + opponent_content + reviewer_content + observer_content \
- + syntheses_templates_content
+ + reviews_templates_content
informations.append({
'title': _("First round"),
'type': "info",
'priority': 1,
'content': content,
})
- elif timezone.now() <= tournament.syntheses_second_phase_limit + timedelta(hours=2):
+ elif timezone.now() <= tournament.reviews_second_phase_limit + timedelta(hours=2):
defender_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=2, defender=self)
opponent_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=2, opponent=self)
reviewer_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=2, reviewer=self)
@@ -992,7 +992,7 @@ class Participation(models.Model):
opponent_text = _("You will oppose the solution of the team {opponent} on the "
"problem {problem}. "
- "You can upload your synthesis sheet on this page.
")
+ "You can upload your written review on this page.")
solution_url = opponent_passage.defended_solution.file.url
passage_url = reverse_lazy("participation:passage_detail", args=(opponent_passage.pk,))
opponent_content = format_lazy(opponent_text, opponent=opponent_passage.defender.team.trigram,
@@ -1001,7 +1001,7 @@ class Participation(models.Model):
reviewer_text = _("You will report the solution of the team {reviewer} on the "
"problem {problem}. "
- "You can upload your synthesis sheet on this page.
")
+ "You can upload your written review on this page.")
solution_url = reviewer_passage.defended_solution.file.url
passage_url = reverse_lazy("participation:passage_detail", args=(reviewer_passage.pk,))
reviewer_content = format_lazy(reviewer_text, reviewer=reviewer_passage.defender.team.trigram,
@@ -1011,7 +1011,7 @@ class Participation(models.Model):
if observer_passage:
observer_text = _("You will observe the solution of the team {observer} on the "
"problem {problem}. "
- "You can upload your synthesis sheet on this page.
")
+ "You can upload your written review on this page.")
solution_url = observer_passage.defended_solution.file.url
passage_url = reverse_lazy("participation:passage_detail", args=(observer_passage.pk,))
observer_content = format_lazy(observer_text,
@@ -1022,17 +1022,17 @@ class Participation(models.Model):
observer_content = ""
if settings.TFJM_APP == "TFJM":
- syntheses_template_begin = f"{settings.STATIC_URL}tfjm/Fiche_synthèse."
- syntheses_templates = " — ".join(f"{ext.upper()}"
- for ext in ["pdf", "tex", "odt", "docx"])
+ reviews_template_begin = f"{settings.STATIC_URL}tfjm/Fiche_synthèse."
+ reviews_templates = " — ".join(f"{ext.upper()}"
+ for ext in ["pdf", "tex", "odt", "docx"])
else:
- syntheses_template_begin = f"{settings.STATIC_URL}eteam/Written_review."
- syntheses_templates = " — ".join(f"{ext.upper()}"
- for ext in ["pdf", "tex"])
- syntheses_templates_content = f"{_('Templates:')} {syntheses_templates}
"
+ reviews_template_begin = f"{settings.STATIC_URL}eteam/Written_review."
+ reviews_templates = " — ".join(f"{ext.upper()}"
+ for ext in ["pdf", "tex"])
+ reviews_templates_content = f"{_('Templates:')} {reviews_templates}
"
content = defender_content + opponent_content + reviewer_content + observer_content \
- + syntheses_templates_content
+ + reviews_templates_content
informations.append({
'title': _("Second round"),
'type': "info",
@@ -1040,7 +1040,7 @@ class Participation(models.Model):
'content': content,
})
elif settings.TFJM_APP == "ETEAM" \
- and timezone.now() <= tournament.syntheses_third_phase_limit + timedelta(hours=2):
+ and timezone.now() <= tournament.reviews_third_phase_limit + timedelta(hours=2):
defender_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=3, defender=self)
opponent_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=3, opponent=self)
reviewer_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=3, reviewer=self)
@@ -1056,7 +1056,7 @@ class Participation(models.Model):
opponent_text = _("You will oppose the solution of the team {opponent} on the "
"problem {problem}. "
- "You can upload your synthesis sheet on this page.
")
+ "You can upload your written review on this page.")
solution_url = opponent_passage.defended_solution.file.url
passage_url = reverse_lazy("participation:passage_detail", args=(opponent_passage.pk,))
opponent_content = format_lazy(opponent_text, opponent=opponent_passage.defender.team.trigram,
@@ -1065,7 +1065,7 @@ class Participation(models.Model):
reviewer_text = _("You will report the solution of the team {reviewer} on the "
"problem {problem}. "
- "You can upload your synthesis sheet on this page.
")
+ "You can upload your written review on this page.")
solution_url = reviewer_passage.defended_solution.file.url
passage_url = reverse_lazy("participation:passage_detail", args=(reviewer_passage.pk,))
reviewer_content = format_lazy(reviewer_text, reviewer=reviewer_passage.defender.team.trigram,
@@ -1075,7 +1075,7 @@ class Participation(models.Model):
if observer_passage:
observer_text = _("You will observe the solution of the team {observer} on the "
"problem {problem}. "
- "You can upload your synthesis sheet on this page.
")
+ "You can upload your written review on this page.")
solution_url = observer_passage.defended_solution.file.url
passage_url = reverse_lazy("participation:passage_detail", args=(observer_passage.pk,))
observer_content = format_lazy(observer_text,
@@ -1086,17 +1086,17 @@ class Participation(models.Model):
observer_content = ""
if settings.TFJM_APP == "TFJM":
- syntheses_template_begin = f"{settings.STATIC_URL}tfjm/Fiche_synthèse."
- syntheses_templates = " — ".join(f"{ext.upper()}"
- for ext in ["pdf", "tex", "odt", "docx"])
+ reviews_template_begin = f"{settings.STATIC_URL}tfjm/Fiche_synthèse."
+ reviews_templates = " — ".join(f"{ext.upper()}"
+ for ext in ["pdf", "tex", "odt", "docx"])
else:
- syntheses_template_begin = f"{settings.STATIC_URL}eteam/Written_review."
- syntheses_templates = " — ".join(f"{ext.upper()}"
- for ext in ["pdf", "tex"])
- syntheses_templates_content = f"{_('Templates:')} {syntheses_templates}
"
+ reviews_template_begin = f"{settings.STATIC_URL}eteam/Written_review."
+ reviews_templates = " — ".join(f"{ext.upper()}"
+ for ext in ["pdf", "tex"])
+ reviews_templates_content = f"{_('Templates:')} {reviews_templates}
"
content = defender_content + opponent_content + reviewer_content + observer_content \
- + syntheses_templates_content
+ + reviews_templates_content
informations.append({
'title': _("Second round"),
'type': "info",
@@ -1256,7 +1256,7 @@ class Pool(models.Model):
f"{_('Reviewer')} ({passage.reviewer.team.trigram})", ""]
+ ([f"{_('Observer')} ({passage.observer.team.trigram})", ""] if has_observer else [])
for passage in passages), start=[str(_("Role")), ""]),
- sum(([f"{_('Writing')} (/{20 if settings.TFJM_APP == "TFJM" else 10})",
+ sum(([f"{_('Writing')} (/{20 if settings.TFJM_APP == 'TFJM' else 10})",
f"{_('Oral')} (/{20 if settings.TFJM_APP == 'TFJM' else 10})",
f"{_('Writing')} (/10)", f"{_('Oral')} (/10)", f"{_('Writing')} (/10)", f"{_('Oral')} (/10)"]
+ ([f"{_('Writing')} (/10)", f"{_('Oral')} (/10)"] if has_observer else [])
@@ -1905,8 +1905,12 @@ def get_solution_filename(instance, filename):
+ ("_final" if instance.final_solution else "")
+def get_review_filename(instance, filename):
+ return f"reviews/{instance.participation.team.trigram}_{instance.type}_{instance.passage.pk}"
+
+
def get_synthesis_filename(instance, filename):
- return f"syntheses/{instance.participation.team.trigram}_{instance.type}_{instance.passage.pk}"
+ return get_review_filename(instance, filename)
class Solution(models.Model):
@@ -1951,7 +1955,7 @@ class Solution(models.Model):
ordering = ('participation__team__trigram', 'final_solution', 'problem',)
-class Synthesis(models.Model):
+class WrittenReview(models.Model):
participation = models.ForeignKey(
Participation,
on_delete=models.CASCADE,
@@ -1961,7 +1965,7 @@ class Synthesis(models.Model):
passage = models.ForeignKey(
Passage,
on_delete=models.CASCADE,
- related_name="syntheses",
+ related_name="written_reviews",
verbose_name=_("passage"),
)
@@ -1980,7 +1984,7 @@ class Synthesis(models.Model):
)
def __str__(self):
- return _("Synthesis of {team} as {type} for problem {problem} of {defender}").format(
+ return _("Written review of {team} as {type} for problem {problem} of {defender}").format(
team=self.participation.team.trigram,
type=self.get_type_display(),
problem=self.passage.solution_number,
@@ -1988,8 +1992,8 @@ class Synthesis(models.Model):
)
class Meta:
- verbose_name = _("synthesis")
- verbose_name_plural = _("syntheses")
+ verbose_name = _("written review")
+ verbose_name_plural = _("written reviews")
unique_together = (('participation', 'passage', 'type', ), )
ordering = ('passage__pool__round', 'type',)
diff --git a/participation/templates/participation/passage_detail.html b/participation/templates/participation/passage_detail.html
index 0733ef7..e345153 100644
--- a/participation/templates/participation/passage_detail.html
+++ b/participation/templates/participation/passage_detail.html
@@ -47,10 +47,10 @@
{% trans "Syntheses:" %}
- {% for synthesis in passage.syntheses.all %}
- {{ synthesis }}{% if not forloop.last %}, {% endif %}
+ {% for review in passage.written_reviews.all %}
+ {{ review }}{% if not forloop.last %}, {% endif %}
{% empty %}
- {% trans "No synthesis was uploaded yet." %}
+ {% trans "No review was uploaded yet." %}
{% endfor %}
@@ -63,7 +63,7 @@
{% elif user.registration.participates %}
{% endif %}
@@ -184,10 +184,10 @@
{% include "base_modal.html" with modal_id=note.modal_name %}
{% endfor %}
{% elif user.registration.participates %}
- {% trans "Upload synthesis" as modal_title %}
+ {% trans "Upload review" as modal_title %}
{% trans "Upload" as modal_button %}
- {% url "participation:upload_synthesis" pk=passage.pk as modal_action %}
- {% include "base_modal.html" with modal_id="uploadSynthesis" modal_enctype="multipart/form-data" %}
+ {% url "participation:upload_review" pk=passage.pk as modal_action %}
+ {% include "base_modal.html" with modal_id="uploadWrittenReview" modal_enctype="multipart/form-data" %}
{% endif %}
{% endblock %}
@@ -201,8 +201,8 @@
initModal("{{ note.modal_name }}", "{% url "participation:update_notes" pk=note.pk %}")
{% endfor %}
{% elif user.registration.participates %}
- initModal("uploadSynthesis", "{% url "participation:upload_synthesis" pk=passage.pk %}")
+ initModal("uploadWrittenReview", "{% url "participation:upload_review" pk=passage.pk %}")
{% endif %}
- });
+ })
{% endblock %}
diff --git a/participation/templates/participation/pool_detail.html b/participation/templates/participation/pool_detail.html
index 66c3e11..28a5424 100644
--- a/participation/templates/participation/pool_detail.html
+++ b/participation/templates/participation/pool_detail.html
@@ -62,15 +62,15 @@
{% for passage in pool.passages.all %}
{{ passage.defender.team.trigram }} — {{ passage.get_solution_number_display }} :
- {% for synthesis in passage.syntheses.all %}
- {{ synthesis.participation.team.trigram }} ({{ synthesis.get_type_display }}){% if not forloop.last %}, {% endif %}
+ {% for review in passage.written_reviews.all %}
+ {{ review.participation.team.trigram }} ({{ review.get_type_display }}){% if not forloop.last %}, {% endif %}
{% empty %}
- {% trans "No synthesis was uploaded yet." %}
+ {% trans "No review was uploaded yet." %}
{% endfor %}
{% endfor %}
-
+
{% trans "Download all" %}
diff --git a/participation/templates/participation/tournament_detail.html b/participation/templates/participation/tournament_detail.html
index a6ef096..683d855 100644
--- a/participation/templates/participation/tournament_detail.html
+++ b/participation/templates/participation/tournament_detail.html
@@ -38,15 +38,15 @@
{% trans 'date of the random draw'|capfirst %}
{{ tournament.solutions_draw }}
- {% trans 'date of maximal syntheses submission for the first round'|capfirst %}
- {{ tournament.syntheses_first_phase_limit }}
+ {% trans 'date of maximal written reviews submission for the first round'|capfirst %}
+ {{ tournament.reviews_first_phase_limit }}
- {% trans 'date of maximal syntheses submission for the second round'|capfirst %}
- {{ tournament.syntheses_second_phase_limit }}
+ {% trans 'date of maximal written reviews submission for the second round'|capfirst %}
+ {{ tournament.reviews_second_phase_limit }}
{% if TFJM.APP == "ETEAM" %}
- {% trans 'date of maximal syntheses submission for the third round'|capfirst %}
- {{ tournament.syntheses_third_phase_limit }}
+ {% trans 'date of maximal written reviews submission for the third round'|capfirst %}
+ {{ tournament.reviews_third_phase_limit }}
{% endif %}
{% trans 'description'|capfirst %}
@@ -233,48 +233,48 @@
diff --git a/participation/templates/participation/upload_synthesis.html b/participation/templates/participation/upload_written_review.html
similarity index 100%
rename from participation/templates/participation/upload_synthesis.html
rename to participation/templates/participation/upload_written_review.html
diff --git a/participation/urls.py b/participation/urls.py
index 2c97587..4812a05 100644
--- a/participation/urls.py
+++ b/participation/urls.py
@@ -8,11 +8,11 @@ from .views import CreateTeamView, FinalNotationSheetTemplateView, GSheetNotific
PassageDetailView, PassageUpdateView, PoolCreateView, PoolDetailView, PoolJuryView, PoolNotesTemplateView, \
PoolPresideJuryView, PoolRemoveJuryView, PoolUpdateView, PoolUploadNotesView, \
ScaleNotationSheetTemplateView, SelectTeamFinalView, \
- SolutionsDownloadView, SolutionUploadView, SynthesisUploadView, \
+ SolutionsDownloadView, SolutionUploadView, \
TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \
TeamUploadMotivationLetterView, TournamentCreateView, TournamentDetailView, TournamentExportCSVView, \
TournamentHarmonizeNoteView, TournamentHarmonizeView, TournamentListView, TournamentPaymentsView, \
- TournamentPublishNotesView, TournamentUpdateView
+ TournamentPublishNotesView, TournamentUpdateView, WrittenReviewUploadView
app_name = "participation"
@@ -42,8 +42,8 @@ urlpatterns = [
name="tournament_authorizations"),
path("tournament//solutions/", SolutionsDownloadView.as_view(),
name="tournament_solutions"),
- path("tournament//syntheses/", SolutionsDownloadView.as_view(),
- name="tournament_syntheses"),
+ path("tournament//written_reviews/", SolutionsDownloadView.as_view(),
+ name="tournament_written_reviews"),
path("tournament//notation/sheets/", NotationSheetsArchiveView.as_view(),
name="tournament_notation_sheets"),
path("tournament//notation/notifications/", GSheetNotificationsView.as_view(),
@@ -60,7 +60,7 @@ urlpatterns = [
path("pools//", PoolDetailView.as_view(), name="pool_detail"),
path("pools//update/", PoolUpdateView.as_view(), name="pool_update"),
path("pools//solutions/", SolutionsDownloadView.as_view(), name="pool_download_solutions"),
- path("pools//syntheses/", SolutionsDownloadView.as_view(), name="pool_download_syntheses"),
+ path("pools//written_reviews/", SolutionsDownloadView.as_view(), name="pool_download_written_reviews"),
path("pools//notation/scale/", ScaleNotationSheetTemplateView.as_view(), name="pool_scale_note_sheet"),
path("pools//notation/final/", FinalNotationSheetTemplateView.as_view(), name="pool_final_note_sheet"),
path("pools//notation/sheets/", NotationSheetsArchiveView.as_view(), name="pool_notation_sheets"),
@@ -71,6 +71,6 @@ urlpatterns = [
path("pools//upload-notes/template/", PoolNotesTemplateView.as_view(), name="pool_notes_template"),
path("pools/passages//", PassageDetailView.as_view(), name="passage_detail"),
path("pools/passages//update/", PassageUpdateView.as_view(), name="passage_update"),
- path("pools/passages//solution/", SynthesisUploadView.as_view(), name="upload_synthesis"),
+ path("pools/passages//written_review/", WrittenReviewUploadView.as_view(), name="upload_written_review"),
path("pools/passages/notes//", NoteUpdateView.as_view(), name="update_notes"),
]
diff --git a/participation/views.py b/participation/views.py
index 8a3b4f4..0aebdf9 100644
--- a/participation/views.py
+++ b/participation/views.py
@@ -46,9 +46,9 @@ from tfjm.lists import get_sympa_client
from tfjm.views import AdminMixin, VolunteerMixin
from .forms import AddJuryForm, JoinTeamForm, MotivationLetterForm, NoteForm, ParticipationForm, PassageForm, \
- PoolForm, RequestValidationForm, SolutionForm, SynthesisForm, TeamForm, TournamentForm, \
- UploadNotesForm, ValidateParticipationForm
-from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament, Tweak
+ PoolForm, RequestValidationForm, SolutionForm, TeamForm, TournamentForm, UploadNotesForm, \
+ ValidateParticipationForm, WrittenReviewForm
+from .models import Note, Participation, Passage, Pool, Solution, Team, Tournament, Tweak, WrittenReview
from .tables import NoteTable, ParticipationTable, PassageTable, PoolTable, TeamTable, TournamentTable
@@ -977,7 +977,7 @@ class PoolUpdateView(VolunteerMixin, UpdateView):
class SolutionsDownloadView(VolunteerMixin, View):
"""
- Download all solutions or syntheses as a ZIP archive.
+ Download all solutions or written reviews as a ZIP archive.
"""
def dispatch(self, request, *args, **kwargs):
@@ -1018,11 +1018,12 @@ class SolutionsDownloadView(VolunteerMixin, View):
if 'team_id' in kwargs:
team = Team.objects.get(pk=kwargs["team_id"])
solutions = Solution.objects.filter(participation=team.participation).all()
- syntheses = Synthesis.objects.filter(participation=team.participation).all()
- filename = _("Solutions of team {trigram}.zip") if is_solution else _("Syntheses of team {trigram}.zip")
+ written_reviews = WrittenReview.objects.filter(participation=team.participation).all()
+ filename = _("Solutions of team {trigram}.zip") if is_solution \
+ else _("Written reviews of team {trigram}.zip")
filename = filename.format(trigram=team.trigram)
- def prefix(s: Solution | Synthesis) -> str:
+ def prefix(s: Solution | WrittenReview) -> str:
return ""
elif 'tournament_id' in kwargs:
tournament = Tournament.objects.get(pk=kwargs["tournament_id"])
@@ -1035,11 +1036,12 @@ class SolutionsDownloadView(VolunteerMixin, View):
for sol in pool.solutions:
sol.pool = pool
solutions.append(sol)
- syntheses = Synthesis.objects.filter(passage__pool__tournament=tournament).all()
- filename = _("Solutions of {tournament}.zip") if is_solution else _("Syntheses of {tournament}.zip")
+ written_reviews = WrittenReview.objects.filter(passage__pool__tournament=tournament).all()
+ filename = _("Solutions of {tournament}.zip") if is_solution \
+ else _("Written reviews of {tournament}.zip")
filename = filename.format(tournament=tournament.name)
- def prefix(s: Solution | Synthesis) -> str:
+ def prefix(s: Solution | WrittenReview) -> str:
pool = s.pool if is_solution else s.passage.pool
p = f"Poule {pool.short_name}/"
if not is_solution:
@@ -1050,27 +1052,28 @@ class SolutionsDownloadView(VolunteerMixin, View):
solutions = Solution.objects.filter(participation__tournament=tournament).all()
else:
solutions = Solution.objects.filter(final_solution=True).all()
- syntheses = Synthesis.objects.filter(passage__pool__tournament=tournament).all()
- filename = _("Solutions of {tournament}.zip") if is_solution else _("Syntheses of {tournament}.zip")
+ written_reviews = WrittenReview.objects.filter(passage__pool__tournament=tournament).all()
+ filename = _("Solutions of {tournament}.zip") if is_solution \
+ else _("Written reviews of {tournament}.zip")
filename = filename.format(tournament=tournament.name)
- def prefix(s: Solution | Synthesis) -> str:
+ def prefix(s: Solution | WrittenReview) -> str:
return f"{s.participation.team.trigram}/" if sort_by == "team" else f"Problème {s.problem}/"
else:
pool = Pool.objects.get(pk=kwargs["pool_id"])
solutions = pool.solutions
- syntheses = Synthesis.objects.filter(passage__pool=pool).all()
+ written_reviews = WrittenReview.objects.filter(passage__pool=pool).all()
filename = _("Solutions for pool {pool} of tournament {tournament}.zip") \
- if is_solution else _("Syntheses for pool {pool} of tournament {tournament}.zip")
+ if is_solution else _("Written reviews for pool {pool} of tournament {tournament}.zip")
filename = filename.format(pool=pool.short_name,
tournament=pool.tournament.name)
- def prefix(s: Solution | Synthesis) -> str:
+ def prefix(s: Solution | WrittenReview) -> str:
return ""
output = BytesIO()
zf = ZipFile(output, "w")
- for s in (solutions if is_solution else syntheses):
+ for s in (solutions if is_solution else written_reviews):
if s.file.storage.exists(s.file.path):
zf.write("media/" + s.file.name, prefix(s) + f"{s}.pdf")
@@ -2028,9 +2031,9 @@ class PassageUpdateView(VolunteerMixin, UpdateView):
return self.handle_no_permission()
-class SynthesisUploadView(LoginRequiredMixin, FormView):
- template_name = "participation/upload_synthesis.html"
- form_class = SynthesisForm
+class WrittenReviewUploadView(LoginRequiredMixin, FormView):
+ template_name = "participation/upload_written_review.html"
+ form_class = WrittenReviewForm
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated or not request.user.registration.participates:
@@ -2057,14 +2060,14 @@ class SynthesisUploadView(LoginRequiredMixin, FormView):
form_syn = form.instance
form_syn.type = 1 if self.participation == self.passage.opponent \
else 2 if self.participation == self.passage.reviewer else 3
- syn_qs = Synthesis.objects.filter(participation=self.participation,
- passage=self.passage,
- type=form_syn.type).all()
+ syn_qs = WrittenReview.objects.filter(participation=self.participation,
+ passage=self.passage,
+ type=form_syn.type).all()
- deadline = self.passage.pool.tournament.syntheses_first_phase_limit if self.passage.pool.round == 1 \
- else self.passage.pool.tournament.syntheses_second_phase_limit
+ deadline = self.passage.pool.tournament.reviews_first_phase_limit if self.passage.pool.round == 1 \
+ else self.passage.pool.tournament.reviews_second_phase_limit
if syn_qs.exists() and timezone.now() > deadline:
- form.add_error(None, _("You can't upload a synthesis after the deadline."))
+ form.add_error(None, _("You can't upload a written review after the deadline."))
return self.form_invalid(form)
# Drop previous solution if existing
diff --git a/registration/views.py b/registration/views.py
index 2d0fe1a..60328d0 100644
--- a/registration/views.py
+++ b/registration/views.py
@@ -26,7 +26,7 @@ from django.utils.translation import gettext_lazy as _
from django.views.generic import CreateView, DetailView, RedirectView, TemplateView, UpdateView, View
from django_tables2 import SingleTableView
from magic import Magic
-from participation.models import Passage, Solution, Synthesis, Tournament
+from participation.models import Passage, Solution, Tournament, WrittenReview
from tfjm.tokens import email_validation_token
from tfjm.views import UserMixin, UserRegistrationMixin, VolunteerMixin
@@ -871,30 +871,30 @@ class SolutionView(LoginRequiredMixin, View):
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
-class SynthesisView(LoginRequiredMixin, View):
+class WrittenReviewView(LoginRequiredMixin, View):
"""
- Display the sent synthesis.
+ Display the sent written reviews.
"""
def get(self, request, *args, **kwargs):
filename = kwargs["filename"]
- path = f"media/syntheses/{filename}"
+ path = f"media/reviews/{filename}"
if not os.path.exists(path):
raise Http404
- synthesis = Synthesis.objects.get(file__endswith=filename)
+ reviews = WrittenReview.objects.get(file__endswith=filename)
user = request.user
if not (user.registration.is_admin or user.registration.is_volunteer
- and (user.registration in synthesis.passage.pool.juries.all()
- or user.registration in synthesis.passage.pool.tournament.organizers.all()
- or user.registration.pools_presided.filter(tournament=synthesis.passage.pool.tournament).exists())
- or user.registration.participates and user.registration.team == synthesis.participation.team):
+ and (user.registration in reviews.passage.pool.juries.all()
+ or user.registration in reviews.passage.pool.tournament.organizers.all()
+ or user.registration.pools_presided.filter(tournament=reviews.passage.pool.tournament).exists())
+ or user.registration.participates and user.registration.team == reviews.participation.team):
raise PermissionDenied
# Guess mime type of the file
mime = Magic(mime=True)
mime_type = mime.from_file(path)
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
# Replace file name
- true_file_name = str(synthesis) + f".{ext}"
+ true_file_name = str(reviews) + f".{ext}"
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
diff --git a/tfjm/urls.py b/tfjm/urls.py
index 16bac38..d2aa6f9 100644
--- a/tfjm/urls.py
+++ b/tfjm/urls.py
@@ -24,7 +24,7 @@ from django.views.defaults import bad_request, page_not_found, permission_denied
from django.views.generic import TemplateView
from participation.views import MotivationLetterView
from registration.views import HealthSheetView, ParentalAuthorizationView, PhotoAuthorizationView, \
- ReceiptView, SolutionView, SynthesisView, VaccineSheetView
+ ReceiptView, SolutionView, VaccineSheetView, WrittenReviewView
from .views import AdminSearchView
@@ -61,8 +61,8 @@ urlpatterns = [
path('media/solutions//', SolutionView.as_view(),
name='solution'),
- path('media/syntheses//', SynthesisView.as_view(),
- name='synthesis'),
+ path('media/reviews//', WrittenReviewView.as_view(),
+ name='reviews'),
]
if settings.DEBUG: