Add notation sheets templates that are autocompleted with the data

Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
Emmy D'Anello 2023-04-06 23:38:03 +02:00
parent ae62e3daf7
commit 5f09c35dee
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
6 changed files with 378 additions and 104 deletions

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-05 18:54+0200\n" "POT-Creation-Date: 2023-04-06 19:21+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"
@ -42,68 +42,68 @@ msgstr "tour"
msgid "Draw" msgid "Draw"
msgstr "Tirage au sort" msgstr "Tirage au sort"
#: draw/consumers.py:25 #: draw/consumers.py:28
msgid "You are not an organizer." msgid "You are not an organizer."
msgstr "Vous n'êtes pas un⋅e organisateur⋅rice." msgstr "Vous n'êtes pas un⋅e organisateur⋅rice."
#: draw/consumers.py:148 #: draw/consumers.py:151
msgid "The draw is already started." msgid "The draw is already started."
msgstr "Le tirage a déjà commencé." msgstr "Le tirage a déjà commencé."
#: draw/consumers.py:154 #: draw/consumers.py:157
msgid "Invalid format" msgid "Invalid format"
msgstr "Format invalide" msgstr "Format invalide"
#: draw/consumers.py:159 #: draw/consumers.py:162
#, python-brace-format #, python-brace-format
msgid "The sum must be equal to the number of teams: expected {len}, got {sum}" msgid "The sum must be equal to the number of teams: expected {len}, got {sum}"
msgstr "" msgstr ""
"La somme doit être égale au nombre d'équipes : attendu {len}, obtenu {sum}" "La somme doit être égale au nombre d'équipes : attendu {len}, obtenu {sum}"
#: draw/consumers.py:164 #: draw/consumers.py:167
msgid "There can be at most one pool with 5 teams." msgid "There can be at most one pool with 5 teams."
msgstr "Il ne peut y avoir au plus qu'une seule poule de 5 équipes." msgstr "Il ne peut y avoir au plus qu'une seule poule de 5 équipes."
#: draw/consumers.py:192 #: draw/consumers.py:195
msgid "Draw started!" msgid "Draw started!"
msgstr "Le tirage a commencé !" msgstr "Le tirage a commencé !"
#: draw/consumers.py:212 #: draw/consumers.py:215
#, python-brace-format #, python-brace-format
msgid "The draw for the tournament {tournament} will start." msgid "The draw for the tournament {tournament} will start."
msgstr "Le tirage au sort du tournoi {tournament} va commencer." msgstr "Le tirage au sort du tournoi {tournament} va commencer."
#: draw/consumers.py:223 draw/consumers.py:248 draw/consumers.py:579 #: draw/consumers.py:226 draw/consumers.py:251 draw/consumers.py:585
#: draw/consumers.py:768 draw/consumers.py:850 draw/consumers.py:867 #: draw/consumers.py:774 draw/consumers.py:856 draw/consumers.py:873
#: draw/consumers.py:937 draw/templates/draw/tournament_content.html:5 #: draw/consumers.py:943 draw/templates/draw/tournament_content.html:5
msgid "The draw has not started yet." msgid "The draw has not started yet."
msgstr "Le tirage au sort n'a pas encore commencé." msgstr "Le tirage au sort n'a pas encore commencé."
#: draw/consumers.py:235 #: draw/consumers.py:238
#, python-brace-format #, python-brace-format
msgid "The draw for the tournament {tournament} is aborted." msgid "The draw for the tournament {tournament} is aborted."
msgstr "Le tirage au sort du tournoi {tournament} est annulé." msgstr "Le tirage au sort du tournoi {tournament} est annulé."
#: draw/consumers.py:275 draw/consumers.py:296 draw/consumers.py:525 #: draw/consumers.py:278 draw/consumers.py:299 draw/consumers.py:531
#: draw/consumers.py:584 draw/consumers.py:773 #: draw/consumers.py:590 draw/consumers.py:779
msgid "This is not the time for this." msgid "This is not the time for this."
msgstr "Ce n'est pas le moment pour cela." msgstr "Ce n'est pas le moment pour cela."
#: draw/consumers.py:288 draw/consumers.py:291 #: draw/consumers.py:291 draw/consumers.py:294
msgid "You've already launched the dice." msgid "You've already launched the dice."
msgstr "Vous avez déjà lancé le dé." msgstr "Vous avez déjà lancé le dé."
#: draw/consumers.py:294 #: draw/consumers.py:297
msgid "It is not your turn." msgid "It is not your turn."
msgstr "Ce n'est pas votre tour." msgstr "Ce n'est pas votre tour."
#: draw/consumers.py:372 #: draw/consumers.py:378
#, python-brace-format #, python-brace-format
msgid "Dices from teams {teams} are identical. Please relaunch your dices." msgid "Dices from teams {teams} are identical. Please relaunch your dices."
msgstr "" msgstr ""
"Les dés des équipes {teams} sont identiques. Merci de relancer vos dés." "Les dés des équipes {teams} sont identiques. Merci de relancer vos dés."
#: draw/consumers.py:870 #: draw/consumers.py:876
msgid "This is only available for the final tournament." msgid "This is only available for the final tournament."
msgstr "Cela n'est possible que pour la finale." msgstr "Cela n'est possible que pour la finale."
@ -288,70 +288,70 @@ msgstr "Démarrer !"
msgid "Last dices" msgid "Last dices"
msgstr "Derniers jets de dés" msgstr "Derniers jets de dés"
#: draw/templates/draw/tournament_content.html:129 #: draw/templates/draw/tournament_content.html:61
msgid "Launch dice"
msgstr "Lancer le dé"
#: draw/templates/draw/tournament_content.html:143
msgid "Draw a problem"
msgstr "Tirer un problème"
#: draw/templates/draw/tournament_content.html:154
msgid "Accept"
msgstr "Accepter"
#: draw/templates/draw/tournament_content.html:157
msgid "Decline"
msgstr "Refuser"
#: draw/templates/draw/tournament_content.html:168
msgid "Export"
msgstr "Exporter"
#: draw/templates/draw/tournament_content.html:176
msgid "Continue draw"
msgstr "Continuer le tirage"
#: draw/templates/draw/tournament_content.html:183
msgid "Cancel last step" msgid "Cancel last step"
msgstr "Annuler la dernière étape" msgstr "Annuler la dernière étape"
#: draw/templates/draw/tournament_content.html:215 participation/admin.py:100 #: draw/templates/draw/tournament_content.html:136
msgid "Launch dice"
msgstr "Lancer le dé"
#: draw/templates/draw/tournament_content.html:150
msgid "Draw a problem"
msgstr "Tirer un problème"
#: draw/templates/draw/tournament_content.html:161
msgid "Accept"
msgstr "Accepter"
#: draw/templates/draw/tournament_content.html:164
msgid "Decline"
msgstr "Refuser"
#: draw/templates/draw/tournament_content.html:175
msgid "Export"
msgstr "Exporter"
#: draw/templates/draw/tournament_content.html:183
msgid "Continue draw"
msgstr "Continuer le tirage"
#: draw/templates/draw/tournament_content.html:216 participation/admin.py:100
#: participation/models.py:125 participation/models.py:310 #: participation/models.py:125 participation/models.py:310
#: registration/models.py:127 #: registration/models.py:127
msgid "team" msgid "team"
msgstr "équipe" msgstr "équipe"
#: draw/templates/draw/tournament_content.html:225
#: draw/templates/draw/tournament_content.html:226 #: draw/templates/draw/tournament_content.html:226
#: draw/templates/draw/tournament_content.html:227 #: draw/templates/draw/tournament_content.html:227
#: draw/templates/draw/tournament_content.html:228 #: draw/templates/draw/tournament_content.html:228
#: draw/templates/draw/tournament_content.html:229 #: draw/templates/draw/tournament_content.html:229
#: draw/templates/draw/tournament_content.html:230
msgid "Room" msgid "Room"
msgstr "Salle" msgstr "Salle"
#: draw/templates/draw/tournament_content.html:335 #: draw/templates/draw/tournament_content.html:335
#: draw/templates/draw/tournament_content.html:353 #: draw/templates/draw/tournament_content.html:354
msgid "Abort" msgid "Abort"
msgstr "Annuler" msgstr "Annuler"
#: draw/templates/draw/tournament_content.html:344 #: draw/templates/draw/tournament_content.html:345
msgid "Are you sure?" msgid "Are you sure?"
msgstr "Êtes-vous sûr⋅e ?" msgstr "Êtes-vous sûr⋅e ?"
#: draw/templates/draw/tournament_content.html:348 #: draw/templates/draw/tournament_content.html:349
msgid "This will reset the draw from the beginning." msgid "This will reset the draw from the beginning."
msgstr "Cela va réinitialiser le tirage au sort depuis le début." msgstr "Cela va réinitialiser le tirage au sort depuis le début."
#: draw/templates/draw/tournament_content.html:349 #: draw/templates/draw/tournament_content.html:350
msgid "This operation is irreversible." msgid "This operation is irreversible."
msgstr "Cette opération est irréversible." msgstr "Cette opération est irréversible."
#: draw/templates/draw/tournament_content.html:350 #: draw/templates/draw/tournament_content.html:351
msgid "Are you sure you want to abort this draw?" msgid "Are you sure you want to abort this draw?"
msgstr "Êtes-vous sûr·e de vouloir annuler le tirage au sort ?" msgstr "Êtes-vous sûr·e de vouloir annuler le tirage au sort ?"
#: draw/templates/draw/tournament_content.html:354 #: draw/templates/draw/tournament_content.html:355
#: tfjm/templates/base_modal.html:17 #: tfjm/templates/base_modal.html:17
msgid "Close" msgid "Close"
msgstr "Fermer" msgstr "Fermer"
@ -502,7 +502,7 @@ msgid "Add new jury"
msgstr "Ajouter un⋅e nouvelleau juré⋅e" msgstr "Ajouter un⋅e nouvelleau juré⋅e"
#: participation/forms.py:225 #: participation/forms.py:225
#: participation/templates/participation/pool_detail.html:77 #: participation/templates/participation/pool_detail.html:87
#: participation/templates/participation/tournament_detail.html:111 #: participation/templates/participation/tournament_detail.html:111
msgid "Add" msgid "Add"
msgstr "Ajouter" msgstr "Ajouter"
@ -907,9 +907,9 @@ msgstr "Rejoindre"
#: participation/templates/participation/passage_detail.html:102 #: participation/templates/participation/passage_detail.html:102
#: participation/templates/participation/passage_detail.html:108 #: participation/templates/participation/passage_detail.html:108
#: participation/templates/participation/pool_add_jurys.html:35 #: participation/templates/participation/pool_add_jurys.html:35
#: participation/templates/participation/pool_detail.html:63 #: participation/templates/participation/pool_detail.html:74
#: participation/templates/participation/pool_detail.html:82 #: participation/templates/participation/pool_detail.html:92
#: participation/templates/participation/pool_detail.html:87 #: participation/templates/participation/pool_detail.html:97
#: participation/templates/participation/team_detail.html:126 #: participation/templates/participation/team_detail.html:126
#: participation/templates/participation/team_detail.html:190 #: participation/templates/participation/team_detail.html:190
#: participation/templates/participation/tournament_form.html:12 #: participation/templates/participation/tournament_form.html:12
@ -973,7 +973,7 @@ msgstr "Envoyer une solution"
#: participation/templates/participation/participation_detail.html:59 #: participation/templates/participation/participation_detail.html:59
#: participation/templates/participation/passage_detail.html:114 #: participation/templates/participation/passage_detail.html:114
#: participation/templates/participation/pool_detail.html:92 #: participation/templates/participation/pool_detail.html:102
#: 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
#: participation/templates/participation/upload_notes.html:24 #: participation/templates/participation/upload_notes.html:24
@ -1092,7 +1092,7 @@ msgstr ""
#: participation/templates/participation/pool_add_jurys.html:11 #: participation/templates/participation/pool_add_jurys.html:11
#: participation/templates/participation/pool_add_jurys.html:34 #: participation/templates/participation/pool_add_jurys.html:34
#: participation/templates/participation/pool_detail.html:81 #: participation/templates/participation/pool_detail.html:91
#: participation/templates/participation/pool_form.html:11 #: participation/templates/participation/pool_form.html:11
msgid "Update pool" msgid "Update pool"
msgstr "Modifier la poule" msgstr "Modifier la poule"
@ -1142,25 +1142,33 @@ msgstr "Lien BigBlueButton :"
msgid "Ranking" msgid "Ranking"
msgstr "Classement" msgstr "Classement"
#: participation/templates/participation/pool_detail.html:62 #: participation/templates/participation/pool_detail.html:61
#: participation/templates/participation/pool_detail.html:76 msgid "Download the scale sheet"
msgid "Add passage" msgstr "Télécharger la feuille de barème"
msgstr "Ajouter un passage"
#: participation/templates/participation/pool_detail.html:64 #: participation/templates/participation/pool_detail.html:64
#: participation/templates/participation/pool_detail.html:86 msgid "Download the final notation sheet"
msgid "Update teams" msgstr "Télécharger la fiche de notation finale"
msgstr "Modifier les équipes"
#: participation/templates/participation/pool_detail.html:65 #: participation/templates/participation/pool_detail.html:66
msgid "Upload notes from a CSV file" msgid "Upload notes from a CSV file"
msgstr "Soumettre les notes à partir d'un fichier CSV" msgstr "Soumettre les notes à partir d'un fichier CSV"
#: participation/templates/participation/pool_detail.html:72 #: participation/templates/participation/pool_detail.html:73
#: participation/templates/participation/pool_detail.html:86
msgid "Add passage"
msgstr "Ajouter un passage"
#: participation/templates/participation/pool_detail.html:75
#: participation/templates/participation/pool_detail.html:96
msgid "Update teams"
msgstr "Modifier les équipes"
#: participation/templates/participation/pool_detail.html:82
msgid "Passages" msgid "Passages"
msgstr "Passages" msgstr "Passages"
#: participation/templates/participation/pool_detail.html:91 #: participation/templates/participation/pool_detail.html:101
msgid "Upload notes" msgid "Upload notes"
msgstr "Envoyer les notes" msgstr "Envoyer les notes"
@ -1294,7 +1302,7 @@ msgid "Invalidate"
msgstr "Invalider" msgstr "Invalider"
#: participation/templates/participation/team_detail.html:184 #: participation/templates/participation/team_detail.html:184
#: participation/views.py:335 #: participation/views.py:337
msgid "Upload motivation letter" msgid "Upload motivation letter"
msgstr "Envoyer la lettre de motivation" msgstr "Envoyer la lettre de motivation"
@ -1303,7 +1311,7 @@ msgid "Update team"
msgstr "Modifier l'équipe" msgstr "Modifier l'équipe"
#: participation/templates/participation/team_detail.html:194 #: participation/templates/participation/team_detail.html:194
#: participation/views.py:444 #: participation/views.py:446
msgid "Leave team" msgid "Leave team"
msgstr "Quitter l'équipe" msgstr "Quitter l'équipe"
@ -1415,49 +1423,49 @@ msgstr "Télécharger la fiche de notation vierge"
msgid "Templates:" msgid "Templates:"
msgstr "Modèles :" msgstr "Modèles :"
#: participation/views.py:46 tfjm/templates/base.html:73 #: participation/views.py:48 tfjm/templates/base.html:73
#: tfjm/templates/base.html:254 #: tfjm/templates/base.html:254
msgid "Create team" msgid "Create team"
msgstr "Créer une équipe" msgstr "Créer une équipe"
#: participation/views.py:55 participation/views.py:100 #: participation/views.py:57 participation/views.py:102
msgid "You don't participate, so you can't create a team." msgid "You don't participate, so you can't create a team."
msgstr "Vous ne participez pas, vous ne pouvez pas créer d'équipe." msgstr "Vous ne participez pas, vous ne pouvez pas créer d'équipe."
#: participation/views.py:57 participation/views.py:102 #: participation/views.py:59 participation/views.py:104
msgid "You are already in a team." msgid "You are already in a team."
msgstr "Vous êtes déjà dans une équipe." msgstr "Vous êtes déjà dans une équipe."
#: participation/views.py:91 tfjm/templates/base.html:78 #: participation/views.py:93 tfjm/templates/base.html:78
#: tfjm/templates/base.html:249 #: tfjm/templates/base.html:249
msgid "Join team" msgid "Join team"
msgstr "Rejoindre une équipe" msgstr "Rejoindre une équipe"
#: participation/views.py:153 participation/views.py:450 #: participation/views.py:155 participation/views.py:452
#: participation/views.py:484 #: participation/views.py:486
msgid "You are not in a team." msgid "You are not in a team."
msgstr "Vous n'êtes pas dans une équipe." msgstr "Vous n'êtes pas dans une équipe."
#: participation/views.py:154 participation/views.py:485 #: participation/views.py:156 participation/views.py:487
msgid "You don't participate, so you don't have any team." msgid "You don't participate, so you don't have any team."
msgstr "Vous ne participez pas, vous n'avez donc pas d'équipe." msgstr "Vous ne participez pas, vous n'avez donc pas d'équipe."
#: participation/views.py:180 #: participation/views.py:182
#, python-brace-format #, python-brace-format
msgid "Detail of team {trigram}" msgid "Detail of team {trigram}"
msgstr "Détails de l'équipe {trigram}" msgstr "Détails de l'équipe {trigram}"
#: participation/views.py:217 #: participation/views.py:219
msgid "You don't participate, so you can't request the validation of the team." msgid "You don't participate, so you can't request the validation of the team."
msgstr "" msgstr ""
"Vous ne participez pas, vous ne pouvez pas demander la validation de " "Vous ne participez pas, vous ne pouvez pas demander la validation de "
"l'équipe." "l'équipe."
#: participation/views.py:220 #: participation/views.py:222
msgid "The validation of the team is already done or pending." msgid "The validation of the team is already done or pending."
msgstr "La validation de l'équipe est déjà faite ou en cours." msgstr "La validation de l'équipe est déjà faite ou en cours."
#: participation/views.py:223 #: participation/views.py:225
msgid "" msgid ""
"The team can't be validated: missing email address confirmations, " "The team can't be validated: missing email address confirmations, "
"authorizations, people, motivation letter or the tournament is not set." "authorizations, people, motivation letter or the tournament is not set."
@ -1466,93 +1474,93 @@ msgstr ""
"d'adresse e-mail, soit une autorisation, soit des personnes, soit la lettre " "d'adresse e-mail, soit une autorisation, soit des personnes, soit la lettre "
"de motivation, soit le tournoi n'a pas été choisi." "de motivation, soit le tournoi n'a pas été choisi."
#: participation/views.py:245 #: participation/views.py:247
msgid "You are not an organizer of the tournament." msgid "You are not an organizer of the tournament."
msgstr "Vous n'êtes pas un⋅e organisateur⋅rice du tournoi." msgstr "Vous n'êtes pas un⋅e organisateur⋅rice du tournoi."
#: participation/views.py:248 #: participation/views.py:250
msgid "This team has no pending validation." msgid "This team has no pending validation."
msgstr "L'équipe n'a pas de validation en attente." msgstr "L'équipe n'a pas de validation en attente."
#: participation/views.py:278 #: participation/views.py:280
msgid "You must specify if you validate the registration or not." msgid "You must specify if you validate the registration or not."
msgstr "Vous devez spécifier si vous validez l'inscription ou non." msgstr "Vous devez spécifier si vous validez l'inscription ou non."
#: participation/views.py:313 #: participation/views.py:315
#, python-brace-format #, python-brace-format
msgid "Update team {trigram}" msgid "Update team {trigram}"
msgstr "Mise à jour de l'équipe {trigram}" msgstr "Mise à jour de l'équipe {trigram}"
#: participation/views.py:374 participation/views.py:430 #: participation/views.py:376 participation/views.py:432
#, python-brace-format #, python-brace-format
msgid "Motivation letter of {team}.{ext}" msgid "Motivation letter of {team}.{ext}"
msgstr "Lettre de motivation de {team}.{ext}" msgstr "Lettre de motivation de {team}.{ext}"
#: participation/views.py:405 #: participation/views.py:407
#, python-brace-format #, python-brace-format
msgid "Photo authorization of {participant}.{ext}" msgid "Photo authorization of {participant}.{ext}"
msgstr "Autorisation de droit à l'image de {participant}.{ext}" msgstr "Autorisation de droit à l'image de {participant}.{ext}"
#: participation/views.py:411 #: participation/views.py:413
#, python-brace-format #, python-brace-format
msgid "Parental authorization of {participant}.{ext}" msgid "Parental authorization of {participant}.{ext}"
msgstr "Autorisation parentale de {participant}.{ext}" msgstr "Autorisation parentale de {participant}.{ext}"
#: participation/views.py:418 #: participation/views.py:420
#, python-brace-format #, python-brace-format
msgid "Health sheet of {participant}.{ext}" msgid "Health sheet of {participant}.{ext}"
msgstr "Fiche sanitaire de {participant}.{ext}" msgstr "Fiche sanitaire de {participant}.{ext}"
#: participation/views.py:424 #: participation/views.py:426
#, python-brace-format #, python-brace-format
msgid "Vaccine sheet of {participant}.{ext}" msgid "Vaccine sheet of {participant}.{ext}"
msgstr "Carnet de vaccination de {participant}.{ext}" msgstr "Carnet de vaccination de {participant}.{ext}"
#: participation/views.py:434 #: participation/views.py:436
#, python-brace-format #, python-brace-format
msgid "Photo authorizations of team {trigram}.zip" msgid "Photo authorizations of team {trigram}.zip"
msgstr "Autorisations de droit à l'image de l'équipe {trigram}.zip" msgstr "Autorisations de droit à l'image de l'équipe {trigram}.zip"
#: participation/views.py:452 #: participation/views.py:454
msgid "The team is already validated or the validation is pending." msgid "The team is already validated or the validation is pending."
msgstr "La validation de l'équipe est déjà faite ou en cours." msgstr "La validation de l'équipe est déjà faite ou en cours."
#: participation/views.py:499 #: participation/views.py:501
msgid "The team is not validated yet." msgid "The team is not validated yet."
msgstr "L'équipe n'est pas encore validée." msgstr "L'équipe n'est pas encore validée."
#: participation/views.py:513 #: participation/views.py:515
#, python-brace-format #, python-brace-format
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:639 #: participation/views.py:641
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:730 #: participation/views.py:732
#, 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:757 #: participation/views.py:759
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:770 #: participation/views.py:772
#, 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:806 #: participation/views.py:808
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:814 #: participation/views.py:816
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:926 #: participation/views.py:957
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

@ -55,6 +55,17 @@
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
{% if user.registration.is_volunteer %}
<div class="card-footer text-center">
<a class="btn btn-info" href="{% url 'participation:pool_scale_note_sheet' pk=pool.pk %}">
{% trans "Download the scale sheet" %}
</a>
<a class="btn btn-info" href="{% url 'participation:pool_final_note_sheet' pk=pool.pk %}">
{% trans "Download the final notation sheet" %}
</a>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#uploadNotesModal">{% trans "Upload notes from a CSV file" %}</button>
</div>
{% endif %}
</div> </div>
</div> </div>
{% if user.registration.is_volunteer %} {% if user.registration.is_volunteer %}
@ -62,7 +73,6 @@
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#addPassageModal">{% trans "Add passage" %}</button> <button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#addPassageModal">{% trans "Add passage" %}</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#updatePoolModal">{% trans "Update" %}</button> <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#updatePoolModal">{% trans "Update" %}</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#updateTeamsModal">{% trans "Update teams" %}</button> <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#updateTeamsModal">{% trans "Update teams" %}</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#uploadNotesModal">{% trans "Upload notes from a CSV file" %}</button>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -0,0 +1,126 @@
\documentclass[12pt,a4paper,landscape]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8x]{inputenc}
\usepackage[french]{babel}
\usepackage[a4paper]{geometry}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{amsthm}
\usepackage{hyperref}
\usepackage{color}
\usepackage{mathtools}
\usepackage{comment}
\usepackage{array}
\usepackage{multirow}
\usepackage{footnote}
\usepackage{xintexpr}
\addtolength{\textwidth}{4cm}
\setlength{\parindent}{0mm}
\geometry{left=1.6cm,right=1.6cm,top=1.2cm,bottom=2cm}
\newcommand{\tfjm}{$\mathbb{TFJM}^2$}
\pagestyle{empty}
\renewcommand{\leq}{\leqslant}
\def\tfjmedition{~{{ tfjm_number }}}
\begin{document}
\thispagestyle{empty}
\begin{center}
\Large {\bf \tfjmedition$^{e}$ Tournoi Fran\c cais des Jeunes Math\'ematiciennes et Math\'ematiciens \tfjm}
\end{center}
\vspace{3mm}
\begin{center}
\begin{itemize}
{% for passage in pool.passages.all %}
\item D\'efenseur\textperiodcentered{}se au passage '{{ forloop.counter }}' : \underline{\texttt{~{{ passage.defender.team.trigram }}~}} $\qquad$ probl\`eme \underline{~{{ passage.solution_number }}~}
{% endfor %}
\end{itemize}
\end{center}
\vspace{6mm}
%%%%%%%%%%%%%%%%%%%%%DEFENSEUR
\begin{tabular}{|c|p{20mm}|p{11cm}|c{% for passage in pool.passages.all %}|p{2cm}{% endfor %}|}\hline
\multicolumn{4}{|l|}{{\bf D\'efenseur\textperiodcentered{}se} \normalsize pr\'esente les id\'ees et r\'esultats principaux pour la solution du probl\`eme.} {% for passage in pool.passages.all %}& Passage {{ forloop.counter }} {% endfor %}\\ \hline \hline
%ECRIT
\multirow{6}{3mm}{\centering \bf\'E\\ C\\ R\\ I\\ T} & \multirow{3}{20mm}{Partie scientifique} & Profondeur des r\'esultats d\'emontr\'es & [0,5] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
&& Originalit\'e et pertinence des preuves& [0,3] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
&& Exactitude et justesse des d\'emonstrations, algorithmes, etc. & [0,7] {{ esp|safe }}\\ \cline{2-{{ pool.passages.count|add:4 }}}
&\multirow{2}{20mm}{Forme} & Pr\'esentation (lisibilit\'e, etc.) & [0,2] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
&& Clart\'e du raisonnement : facile \`a comprendre ou compl\`etement obscur ? & [0,3]{{ esp|safe }} \\ \cline{2-{{ pool.passages.count|add:4 }}}
&\multicolumn{3}{|l|}{\bf TOTAL \'ECRIT (/20)} {{ esp|safe }} \\ \hline \hline
%ORAL
\multirow{8}{3mm}{\centering\bf O\\ R\\ A\\ L} & \multirow{4}{20mm}{Partie scientifique} & Compr\'ehension du mat\'eriel, connaissance des sujets math\'ematiques correspondants \emph{lors de la pr\'esentation} & [0,3] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
&& P\'edagogie, notamment clart\'e, exactitude et justesse des d\'emonstrations \emph{lors de la pr\'esentation} & [0,3] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
&& Capacit\'e \`a r\'eagir aux questions et remarques de l'Opposant\textperiodcentered{}e et de læ Rapporteur\textperiodcentered{}e & [0,4] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
&& Capacit\'e \`a r\'eagir aux questions et remarques du jury & [0,2] {{ esp|safe }}\\ \cline{2-{{ pool.passages.count|add:4 }}}
&\multirow{3}{20mm}{Forme} & Bri\`evet\'e et propret\'e de la pr\'esentation & [0,2] {{ esp|safe }} \\ \cline{3-{{ pool.passages.count|add:4 }}}
&& Capacit\'e de faire avancer le d\'ebat & [0,2] {{ esp|safe }} \\ \cline{3-{{ pool.passages.count|add:4 }}}
&& \emph{Conformit\'e} entre la pr\'esentation et le mat\'eriel \'ecrit & [--5,0] {{ esp|safe }} \\ \cline{2-{{ pool.passages.count|add:4 }}}
&\multicolumn{3}{|l|}{\bf TOTAL ORAL (/16)} {{ esp|safe }} \\ \hline
\end{tabular}
\newpage
%%%%%%%%%%%%%%%%%OPPOSANT
\begin{tabular}{|c|p{20mm}|p{11cm}|c{% for passage in pool.passages.all %}|p{2cm}{% endfor %}|}\hline
\multicolumn{4}{|l|}{L' {\bf Opposant\textperiodcentered{}e} \normalsize fournit une analyse critique de la solution et de la pr\'esentation.}
{% for passage in pool.passages.all %}& Passage {{ forloop.counter }} {% endfor %} \\ \hline \hline
%ECRIT
\multirow{4}{3mm}{\centering\bf\'E\\ C\\ R\\ I\\ T} &\multirow{2}{20mm}{Partie scientifique} & Compr\'ehension du probl\`eme, savoir \'evaluer la qualit\'e g\'en\'erale de la solution & [0,4] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
&& Rep\'erer les erreurs et leur importance & [0,3] {{ esp|safe }}\\ \cline{2-{{ pool.passages.count|add:4 }}}
& Forme & Pr\'esentation (lisibilit\'e, etc.) & [0,2] {{ esp|safe }}\\ \cline{2-{{ pool.passages.count|add:4 }}}
&\multicolumn{3}{|l|}{\bf TOTAL \'ECRIT (/9)} {{ esp|safe }} \\ \hline \hline
%ORAL
\multirow{6}{3mm}{\centering\bf O\\ R\\ A\\ L} & \multirow{3}{20mm}{Partie scientifique} & Compr\'ehension du probl\`eme, savoir \'evaluer la qualit\'e g\'en\'erale de la pr\'esentation de læ D\'efenseur\textperiodcentered{}se
& [0,2] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
&& Rep\'erer les erreurs et leur importance & [0,2] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
&& Pertinence des questions & [0,3] {{ esp|safe }}\\ \cline{2-{{ pool.passages.count|add:4 }}}
& Forme & M\`ene un d\'ebat de fa\c con comp\'etente et propre. & [0,3] {{ esp|safe }}\\ \cline{2-{{ pool.passages.count|add:4 }}}
&\multicolumn{3}{|l|}{\bf TOTAL ORAL (/10)} {{ esp|safe }}\\ \hline
\end{tabular}
\vfill
%%%%%%%%%%%%%%%%%%%%%%RAPPORTEUR
\begin{tabular}{|c|p{20mm}|p{11cm}|c{% for passage in pool.passages.all %}|p{2cm}{% endfor %}|}\hline
\multicolumn{4}{|l|}{{\bf Rapporteur\textperiodcentered{}e} \normalsize \'evalue le d\'ebat entre læ D\'efenseur\textperiodcentered{}se et l'Opposant\textperiodcentered{}e.} {% for passage in pool.passages.all %}& Passage {{ forloop.counter }} {% endfor %}\\ \hline \hline
%ECRIT
\multirow{4}{3mm}{\centering\bf\'E\\ C\\ R\\ I\\ T} &\multirow{2}{20mm}{Partie scientifique} & Compr\'ehension du probl\`eme, savoir \'evaluer la qualit\'e g\'en\'erale de la solution & [0,4] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
& & Rep\'erer les erreurs et leur importance & [0,3] {{ esp|safe }}\\ \cline{2-{{ pool.passages.count|add:4 }}}
& Forme & Pr\'esentation (lisibilit\'e, etc.) & [0,2] {{ esp|safe }}\\ \cline{2-{{ pool.passages.count|add:4 }}}
&\multicolumn{3}{|l|}{\bf TOTAL \'ECRIT (/9)} {{ esp|safe }}\\ \hline \hline
%ORAL
\multirow{6}{3mm}{\centering\bf O\\ R\\ A\\ L} &\multirow{4}{20mm}{Partie scientifique} & Compr\'ehension du probl\`eme, savoir \'evaluer la qualit\'e g\'en\'erale de la pr\'esentation de læ D\'efenseur\textperiodcentered{}se & [0,1] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
&& Savoir \'evaluer la qualit\'e g\'en\'erale du d\'ebat & [0,2] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
&& Rep\'erer les points importants non abord\'es & [0,2] {{ esp|safe }}\\ \cline{3-{{ pool.passages.count|add:4 }}}
&& Pertinence des questions & [0,2] {{ esp|safe }}\\ \cline{2-{{ pool.passages.count|add:4 }}}
& Forme & M\`ene un d\'ebat de fa\c con comp\'etente et propre. & [0,3] {{ esp|safe }}\\ \cline{2-{{ pool.passages.count|add:4 }}}
& \multicolumn{3}{|l|}{\bf TOTAL ORAL (/10)} {{ esp|safe }}\\ \hline
\end{tabular}
\vfill
{% if pool.passages.count == 4 %}
%%%%%%% INTERVENTION EXCEPTIONNELLE
\begin{tabular}{|c|p{11cm}|c|p{2cm}|p{2cm}|p{2cm}|p{2cm}|}\hline
\multicolumn{3}{|l|}{L'{\bf Intervention exceptionnelle} \normalsize permet de signaler une erreur grave omise par tous.} {% for passage in pool.passages.all %}& Passage {{ forloop.counter }} {% endfor %}\\ \hline \hline
%ORAL
\multirow{1}{3mm}{\centering\bf O\\ R\\ A\\ L}
& Toute intervention exceptionnelle non pertinente est sanctionn\'ee par une note n\'egative, l'absence d'intervention re\c coit un z\'ero forfaitaire. \phantom{pour avoir oral en entier dans la} \phantom{colonne il} \phantom{faut blablater un peu}& [-4,4] {{ esp|safe }}\\ \hline
\end{tabular}
{% endif %}
\end{document}

View File

@ -0,0 +1,90 @@
\documentclass[10pt,a4paper,landscape]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8x]{inputenc}
\usepackage[french]{babel}
\usepackage[a4paper]{geometry}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{amsthm}
\usepackage{hyperref}
\usepackage{color}
\usepackage{mathtools}
\usepackage{comment}
\usepackage{array}
\usepackage{multirow}
\usepackage{footnote}
\usepackage{tabularx}
\usepackage{xintexpr}
\addtolength{\textwidth}{6cm}
\addtolength{\oddsidemargin}{-3cm}
\addtolength{\textheight}{2cm}
\addtolength{\topmargin}{-0.5cm}
\setlength{\parindent}{0mm}
\newcommand{\tfjm}{$\mathbb{TFJM}^2$}
\renewcommand{\leq}{\leqslant}
\def\tfjmedition{~{{ tfjm_number }}}
\begin{document}
\pagenumbering{gobble}
\centering
\Large {\bf \tfjmedition$^{e}$ Tournoi Fran\c cais des Jeunes Math\'ematiciennes et Math\'ematiciens \tfjm}\\
\vspace{3mm}
Tour {{ pool.round }} \;-- Poule {{ pool.get_letter_display }} \;-- {% if pool.round == 1 %}{{ pool.tournament.date_start }}{% else %}{{ pool.tournament.date_end }}{% endif %}
\vspace{15mm}
\begin{tabular}{|p{35mm}{% for passage in pool.passages.all %}{% if pool.passages.count == 3 %}|p{3cm}|p{3cm}{% else %}|p{2.5cm}|p{2.5cm}{% endif %}{% endfor %}|}\hline
\multirow{2}{35mm}{\LARGE R\^ole} {% for passage in pool.passages.all %}& \multicolumn{2}{c|}{ \Large Probl\`eme {{ passage.solution_number }}}{% endfor %} \\ \cline{2-{{ pool.passages.count|add:pool.passages.count|add:1 }}}
{% for passage in pool.passages.all %}& \hspace{4mm} {\Large \'ECRIT} & \hspace{4mm} {\Large ORAL}{% endfor %} \\ \hline
\multirow{2}{35mm}{\LARGE D\'efenseur\textperiodcentered{}se} {% for passage in pool.passages.all %}& \multicolumn{2}{c|}{\Large {{ passage.defender.team.trigram }}}{% endfor %} \\ \cline{2-{{ pool.passages.count|add:pool.passages.count|add:1 }}}
{% for passage in pool.passages.all %}
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 20$
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 16$
{% endfor %} & \hline
\multirow{2}{35mm}{\LARGE Opposant\textperiodcentered{}e} {% for passage in pool.passages.all %}& \multicolumn{2}{c|}{\Large {{ passage.opponent.team.trigram }}}{% endfor %} \\ \cline{2-{{ pool.passages.count|add:pool.passages.count|add:1 }}}
{% for passage in pool.passages.all %}
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 9$
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$
{% endfor %} & \hline
\multirow{2}{35mm}{\LARGE Rapporteur\textperiodcentered{}e} {% for passage in pool.passages.all %}& \multicolumn{2}{c|}{\Large {{ passage.reporter.team.trigram }}}{% endfor %} \\ \cline{2-{{ pool.passages.count|add:pool.passages.count|add:1 }}}
{% for passage in pool.passages.all %}
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 9$
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$
{% endfor %} & \hline
{% if pool.passages.count == 4 %}
\multirow{4}{35mm}{\Large Intervention exceptionnelle}& \multicolumn{2}{c|}{\Large {{ pool.passages.last.defender.team.trigram }}}{% for passage in pool.passages.all %}{% if forloop.counter < 4 %} & \multicolumn{2}{c|}{\Large {{ passage.defender.team.trigram }}}{% endif %}{% endfor %} \\ \cline{2-{{ pool.passages.count|add:pool.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}}
& \multicolumn{2}{c|}{\phantom{asd asd} \phantom{asd asd}}
& \multicolumn{2}{c|}{\phantom{asd asd} \phantom{asd asd}}\\
& \multicolumn{2}{c|}{\centering \normalsize$-4\leq x\leq 4$}
& \multicolumn{2}{c|}{\centering \normalsize$-4\leq x\leq 4$}
& \multicolumn{2}{c|}{\centering \normalsize$-4\leq x\leq 4$}
& \multicolumn{2}{c|}{\centering \normalsize$-4\leq x\leq 4$} & \hline
{% endif %}
\end{tabular}
\vspace{15mm}
\LARGE Nom de læ jur\'e\textperiodcentered{}e :
{% if is_jury %}\underline{ {{ user.first_name|safe }} {{ user.last_name|safe }} }{% else %}\underline{\phantom{Phrase suffisamment longue pour le nom}}{% endif %}
$\qquad$ Signature : \underline{\phantom{Phrase moins longue}}
\newpage
%}
\end{document}

View File

@ -4,9 +4,10 @@
from django.urls import path from django.urls import path
from django.views.generic import TemplateView from django.views.generic import TemplateView
from .views import CreateTeamView, JoinTeamView, MyParticipationDetailView, MyTeamDetailView, NoteUpdateView, \ from .views import CreateTeamView, FinalNotationSheetTemplateView, JoinTeamView, MyParticipationDetailView, \
ParticipationDetailView, PassageCreateView, PassageDetailView, PassageUpdateView, PoolAddJurysView, PoolCreateView,\ MyTeamDetailView, NoteUpdateView, ParticipationDetailView, PassageCreateView, PassageDetailView, \
PoolDetailView, PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, SolutionUploadView, SynthesisUploadView,\ PassageUpdateView, PoolAddJurysView, PoolCreateView, PoolDetailView, PoolUpdateTeamsView, PoolUpdateView, \
PoolUploadNotesView, ScaleNotationSheetTemplateView, SolutionUploadView, SynthesisUploadView,\
TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \ TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \
TeamUploadMotivationLetterView, TournamentCreateView, TournamentDetailView, TournamentExportCSVView, \ TeamUploadMotivationLetterView, TournamentCreateView, TournamentDetailView, TournamentExportCSVView, \
TournamentListView, TournamentUpdateView TournamentListView, TournamentUpdateView
@ -36,6 +37,8 @@ urlpatterns = [
path("pools/create/", PoolCreateView.as_view(), name="pool_create"), path("pools/create/", PoolCreateView.as_view(), name="pool_create"),
path("pools/<int:pk>/", PoolDetailView.as_view(), name="pool_detail"), path("pools/<int:pk>/", PoolDetailView.as_view(), name="pool_detail"),
path("pools/<int:pk>/update/", PoolUpdateView.as_view(), name="pool_update"), path("pools/<int:pk>/update/", PoolUpdateView.as_view(), name="pool_update"),
path("pools/<int:pk>/notation/scale/", ScaleNotationSheetTemplateView.as_view(), name="pool_scale_note_sheet"),
path("pools/<int:pk>/notation/final/", FinalNotationSheetTemplateView.as_view(), name="pool_final_note_sheet"),
path("pools/<int:pk>/update-teams/", PoolUpdateTeamsView.as_view(), name="pool_update_teams"), path("pools/<int:pk>/update-teams/", PoolUpdateTeamsView.as_view(), name="pool_update_teams"),
path("pools/<int:pk>/add-jurys/", PoolAddJurysView.as_view(), name="pool_add_jurys"), path("pools/<int:pk>/add-jurys/", PoolAddJurysView.as_view(), name="pool_add_jurys"),
path("pools/<int:pk>/upload-notes/", PoolUploadNotesView.as_view(), name="pool_upload_notes"), path("pools/<int:pk>/upload-notes/", PoolUploadNotesView.as_view(), name="pool_upload_notes"),

View File

@ -4,6 +4,8 @@
import csv import csv
from io import BytesIO from io import BytesIO
import os import os
import subprocess
from tempfile import mkdtemp
from zipfile import ZipFile from zipfile import ZipFile
from django.conf import settings from django.conf import settings
@ -818,6 +820,41 @@ class PoolUploadNotesView(VolunteerMixin, FormView, DetailView):
return reverse_lazy('participation:pool_detail', args=(self.kwargs['pk'],)) return reverse_lazy('participation:pool_detail', args=(self.kwargs['pk'],))
class NotationSheetTemplateView(VolunteerMixin, DetailView):
"""
Generate a PDF from a LaTeX template for the notation papers.
"""
model = Pool
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['esp'] = self.object.passages.count() * '&'
context['is_jury'] = self.request.user.registration in self.object.juries.all() \
and 'blank' not in self.request.GET
context['tfjm_number'] = timezone.now().year - 2010
return context
def render_to_response(self, context, **response_kwargs):
tex = render_to_string(self.template_name, context=context, request=self.request)
temp_dir = mkdtemp()
with open(os.path.join(temp_dir, "texput.tex"), "w") as f:
f.write(tex)
process = subprocess.Popen(["pdflatex", "-interaction=nonstopmode", f"-output-directory={temp_dir}",
os.path.join(temp_dir, "texput.tex"), ])
process.wait()
return FileResponse(streaming_content=open(os.path.join(temp_dir, "texput.pdf"), "rb"),
content_type="application/pdf",
filename=self.template_name.split("/")[-1][:-3] + "pdf")
class ScaleNotationSheetTemplateView(NotationSheetTemplateView):
template_name = 'participation/tex/bareme.tex'
class FinalNotationSheetTemplateView(NotationSheetTemplateView):
template_name = 'participation/tex/finale.tex'
class PassageCreateView(VolunteerMixin, CreateView): class PassageCreateView(VolunteerMixin, CreateView):
model = Passage model = Passage
form_class = PassageForm form_class = PassageForm