Add archive with all notation sheets

Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
Emmy D'Anello 2024-03-29 18:59:37 +01:00
parent a44439671e
commit 6b16ed3cc8
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
7 changed files with 222 additions and 99 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: 2024-03-27 00:47+0100\n" "POT-Creation-Date: 2024-03-29 18:56+0100\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"
@ -214,17 +214,17 @@ msgid "Pool {letter}{number}"
msgstr "Poule {letter}{number}" msgstr "Poule {letter}{number}"
#: draw/models.py:408 draw/models.py:435 participation/admin.py:136 #: draw/models.py:408 draw/models.py:435 participation/admin.py:136
#: participation/admin.py:155 participation/models.py:597 #: participation/admin.py:155 participation/models.py:601
#: participation/models.py:606 participation/tables.py:84 #: participation/models.py:610 participation/tables.py:84
msgid "pool" msgid "pool"
msgstr "poule" msgstr "poule"
#: draw/models.py:409 participation/models.py:598 #: draw/models.py:409 participation/models.py:602
msgid "pools" msgid "pools"
msgstr "poules" msgstr "poules"
#: draw/models.py:421 participation/models.py:503 participation/models.py:767 #: draw/models.py:421 participation/models.py:503 participation/models.py:771
#: participation/models.py:797 participation/models.py:839 #: participation/models.py:801 participation/models.py:843
msgid "participation" msgid "participation"
msgstr "participation" msgstr "participation"
@ -248,8 +248,8 @@ msgid ""
msgstr "" msgstr ""
"L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1." "L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1."
#: draw/models.py:458 draw/models.py:481 participation/models.py:620 #: draw/models.py:458 draw/models.py:481 participation/models.py:624
#: participation/models.py:804 #: participation/models.py:808
#, python-brace-format #, python-brace-format
msgid "Problem #{problem}" msgid "Problem #{problem}"
msgstr "Problème n°{problem}" msgstr "Problème n°{problem}"
@ -344,8 +344,8 @@ msgstr "équipe"
#: 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 #: draw/templates/draw/tournament_content.html:230
#: participation/templates/participation/pool_detail.html:84 #: participation/templates/participation/pool_detail.html:85
#: participation/templates/participation/pool_detail.html:88 #: participation/templates/participation/pool_detail.html:89
#: participation/templates/participation/pool_detail.html:94 #: participation/templates/participation/pool_detail.html:94
#: participation/templates/participation/pool_detail.html:98 #: participation/templates/participation/pool_detail.html:98
msgid "Room" msgid "Room"
@ -456,21 +456,21 @@ msgid "selected for final"
msgstr "sélectionnée pour la finale" msgstr "sélectionnée pour la finale"
#: participation/admin.py:124 participation/admin.py:183 #: participation/admin.py:124 participation/admin.py:183
#: participation/models.py:627 participation/tables.py:112 #: participation/models.py:631 participation/tables.py:112
msgid "defender" msgid "defender"
msgstr "défenseur⋅se" msgstr "défenseur⋅se"
#: participation/admin.py:128 participation/models.py:634 #: participation/admin.py:128 participation/models.py:638
#: participation/models.py:851 #: participation/models.py:855
msgid "opponent" msgid "opponent"
msgstr "opposant⋅e" msgstr "opposant⋅e"
#: participation/admin.py:132 participation/models.py:641 #: participation/admin.py:132 participation/models.py:645
#: participation/models.py:852 #: participation/models.py:856
msgid "reporter" msgid "reporter"
msgstr "rapporteur⋅e" msgstr "rapporteur⋅e"
#: participation/admin.py:187 participation/models.py:802 #: participation/admin.py:187 participation/models.py:806
msgid "problem" msgid "problem"
msgstr "numéro de problème" msgstr "numéro de problème"
@ -529,7 +529,7 @@ msgid "The PDF file must not have more than 30 pages."
msgstr "Le fichier PDF ne doit pas avoir plus de 30 pages." msgstr "Le fichier PDF ne doit pas avoir plus de 30 pages."
#: participation/forms.py:236 #: participation/forms.py:236
#: participation/templates/participation/pool_detail.html:123 #: participation/templates/participation/pool_detail.html:130
msgid "Add" msgid "Add"
msgstr "Ajouter" msgstr "Ajouter"
@ -888,32 +888,32 @@ msgstr ""
"Ils restent toujours accessibles pour vous. Seules les moyennes sont " "Ils restent toujours accessibles pour vous. Seules les moyennes sont "
"communiquées." "communiquées."
#: participation/models.py:587 #: participation/models.py:591
msgid "The president of the jury must be part of the jury." msgid "The president of the jury must be part of the jury."
msgstr "Læ président⋅e du jury doit faire partie du jury." msgstr "Læ président⋅e du jury doit faire partie du jury."
#: participation/models.py:591 #: participation/models.py:595
#, python-brace-format #, python-brace-format
msgid "Pool of day {round} for tournament {tournament} with teams {teams}" msgid "Pool of day {round} for tournament {tournament} with teams {teams}"
msgstr "Poule du jour {round} du tournoi {tournament} avec les équipes {teams}" msgstr "Poule du jour {round} du tournoi {tournament} avec les équipes {teams}"
#: participation/models.py:611 #: participation/models.py:615
msgid "position" msgid "position"
msgstr "position" msgstr "position"
#: participation/models.py:618 #: participation/models.py:622
msgid "defended solution" msgid "defended solution"
msgstr "solution défendue" msgstr "solution défendue"
#: participation/models.py:651 #: participation/models.py:655
msgid "observer" msgid "observer"
msgstr "observateur⋅rice" msgstr "observateur⋅rice"
#: participation/models.py:656 #: participation/models.py:660
msgid "penalties" msgid "penalties"
msgstr "pénalités" msgstr "pénalités"
#: participation/models.py:658 #: participation/models.py:662
msgid "" msgid ""
"Number of penalties for the defender. The defender will loose a 0.5 " "Number of penalties for the defender. The defender will loose a 0.5 "
"coefficient per penalty." "coefficient per penalty."
@ -921,124 +921,124 @@ msgstr ""
"Nombre de pénalités pour l'équipe défenseuse. Elle perd un coefficient 0.5 " "Nombre de pénalités pour l'équipe défenseuse. Elle perd un coefficient 0.5 "
"sur sa présentation orale par pénalité." "sur sa présentation orale par pénalité."
#: participation/models.py:734 participation/models.py:737 #: participation/models.py:738 participation/models.py:741
#: participation/models.py:740 participation/models.py:743 #: participation/models.py:744 participation/models.py:747
#, python-brace-format #, python-brace-format
msgid "Team {trigram} is not registered in the pool." msgid "Team {trigram} is not registered in the pool."
msgstr "L'équipe {trigram} n'est pas inscrite dans la poule." msgstr "L'équipe {trigram} n'est pas inscrite dans la poule."
#: participation/models.py:748 #: participation/models.py:752
#, python-brace-format #, python-brace-format
msgid "Passage of {defender} for problem {problem}" msgid "Passage of {defender} for problem {problem}"
msgstr "Passage de {defender} pour le problème {problem}" msgstr "Passage de {defender} pour le problème {problem}"
#: participation/models.py:752 participation/models.py:761 #: participation/models.py:756 participation/models.py:765
#: participation/models.py:846 participation/models.py:888 #: participation/models.py:850 participation/models.py:892
msgid "passage" msgid "passage"
msgstr "passage" msgstr "passage"
#: participation/models.py:753 #: participation/models.py:757
msgid "passages" msgid "passages"
msgstr "passages" msgstr "passages"
#: participation/models.py:772 #: participation/models.py:776
msgid "difference" msgid "difference"
msgstr "différence" msgstr "différence"
#: participation/models.py:773 #: participation/models.py:777
msgid "Score to add/remove on the final score" msgid "Score to add/remove on the final score"
msgstr "Score à ajouter/retrancher au score final" msgstr "Score à ajouter/retrancher au score final"
#: participation/models.py:780 #: participation/models.py:784
msgid "tweak" msgid "tweak"
msgstr "harmonisation" msgstr "harmonisation"
#: participation/models.py:781 #: participation/models.py:785
msgid "tweaks" msgid "tweaks"
msgstr "harmonisations" msgstr "harmonisations"
#: participation/models.py:809 #: participation/models.py:813
msgid "solution for the final tournament" msgid "solution for the final tournament"
msgstr "solution pour la finale" msgstr "solution pour la finale"
#: participation/models.py:814 participation/models.py:857 #: participation/models.py:818 participation/models.py:861
msgid "file" msgid "file"
msgstr "fichier" msgstr "fichier"
#: participation/models.py:824 #: participation/models.py:828
#, python-brace-format #, python-brace-format
msgid "Solution of team {team} for problem {problem}" msgid "Solution of team {team} for problem {problem}"
msgstr "Solution de l'équipe {team} pour le problème {problem}" msgstr "Solution de l'équipe {team} pour le problème {problem}"
#: participation/models.py:826 #: participation/models.py:830
msgid "for final" msgid "for final"
msgstr "pour la finale" msgstr "pour la finale"
#: participation/models.py:829 #: participation/models.py:833
msgid "solution" msgid "solution"
msgstr "solution" msgstr "solution"
#: participation/models.py:830 #: participation/models.py:834
msgid "solutions" msgid "solutions"
msgstr "solutions" msgstr "solutions"
#: participation/models.py:863 #: participation/models.py:867
#, python-brace-format #, python-brace-format
msgid "Synthesis of {team} as {type} for problem {problem} of {defender}" msgid "Synthesis of {team} as {type} for problem {problem} of {defender}"
msgstr "" msgstr ""
"Note de synthèse de l'équipe {team} en tant que {type} pour le problème " "Note de synthèse de l'équipe {team} en tant que {type} pour le problème "
"{problem} de {defender}" "{problem} de {defender}"
#: participation/models.py:871 #: participation/models.py:875
msgid "synthesis" msgid "synthesis"
msgstr "note de synthèse" msgstr "note de synthèse"
#: participation/models.py:872 #: participation/models.py:876
msgid "syntheses" msgid "syntheses"
msgstr "notes de synthèse" msgstr "notes de synthèse"
#: participation/models.py:881 #: participation/models.py:885
msgid "jury" msgid "jury"
msgstr "jury" msgstr "jury"
#: participation/models.py:893 #: participation/models.py:897
msgid "defender writing note" msgid "defender writing note"
msgstr "note d'écrit de la défense" msgstr "note d'écrit de la défense"
#: participation/models.py:899 #: participation/models.py:903
msgid "defender oral note" msgid "defender oral note"
msgstr "note d'oral de la défense" msgstr "note d'oral de la défense"
#: participation/models.py:905 #: participation/models.py:909
msgid "opponent writing note" msgid "opponent writing note"
msgstr "note d'écrit de l'opposition" msgstr "note d'écrit de l'opposition"
#: participation/models.py:911 #: participation/models.py:915
msgid "opponent oral note" msgid "opponent oral note"
msgstr "note d'oral de l'opposition" msgstr "note d'oral de l'opposition"
#: participation/models.py:917 #: participation/models.py:921
msgid "reporter writing note" msgid "reporter writing note"
msgstr "note d'écrit du rapportage" msgstr "note d'écrit du rapportage"
#: participation/models.py:923 #: participation/models.py:927
msgid "reporter oral note" msgid "reporter oral note"
msgstr "note d'oral du rapportage" msgstr "note d'oral du rapportage"
#: participation/models.py:929 #: participation/models.py:933
msgid "observer note" msgid "observer note"
msgstr "note de l'observation" msgstr "note de l'observation"
#: participation/models.py:965 #: participation/models.py:969
#, python-brace-format #, python-brace-format
msgid "Notes of {jury} for {passage}" msgid "Notes of {jury} for {passage}"
msgstr "Notes de {jury} pour le {passage}" msgstr "Notes de {jury} pour le {passage}"
#: participation/models.py:968 #: participation/models.py:972
msgid "note" msgid "note"
msgstr "note" msgstr "note"
#: participation/models.py:969 #: participation/models.py:973
msgid "notes" msgid "notes"
msgstr "notes" msgstr "notes"
@ -1077,9 +1077,9 @@ msgstr "Pas d'équipe définie"
#: participation/templates/participation/passage_detail.html:54 #: participation/templates/participation/passage_detail.html:54
#: participation/templates/participation/passage_detail.html:120 #: participation/templates/participation/passage_detail.html:120
#: participation/templates/participation/passage_detail.html:126 #: participation/templates/participation/passage_detail.html:126
#: participation/templates/participation/pool_detail.html:110 #: participation/templates/participation/pool_detail.html:117
#: participation/templates/participation/pool_detail.html:128 #: participation/templates/participation/pool_detail.html:135
#: participation/templates/participation/pool_detail.html:133 #: participation/templates/participation/pool_detail.html:140
#: participation/templates/participation/team_detail.html:151 #: participation/templates/participation/team_detail.html:151
#: participation/templates/participation/team_detail.html:215 #: participation/templates/participation/team_detail.html:215
#: participation/templates/participation/tournament_form.html:12 #: participation/templates/participation/tournament_form.html:12
@ -1172,7 +1172,7 @@ msgstr "Envoyer une solution"
#: participation/templates/participation/participation_detail.html:65 #: participation/templates/participation/participation_detail.html:65
#: participation/templates/participation/passage_detail.html:132 #: participation/templates/participation/passage_detail.html:132
#: participation/templates/participation/pool_detail.html:138 #: participation/templates/participation/pool_detail.html:145
#: participation/templates/participation/team_detail.html:210 #: participation/templates/participation/team_detail.html:210
#: participation/templates/participation/upload_motivation_letter.html:13 #: participation/templates/participation/upload_motivation_letter.html:13
#: participation/templates/participation/upload_notes.html:17 #: participation/templates/participation/upload_notes.html:17
@ -1333,7 +1333,7 @@ msgstr "Lien BigBlueButton :"
msgid "Ranking" msgid "Ranking"
msgstr "Classement" msgstr "Classement"
#: participation/templates/participation/pool_detail.html:84 #: participation/templates/participation/pool_detail.html:85
msgid "Download the scale sheet" msgid "Download the scale sheet"
msgstr "Télécharger la feuille de barème" msgstr "Télécharger la feuille de barème"
@ -1341,30 +1341,34 @@ msgstr "Télécharger la feuille de barème"
msgid "Download the final notation sheet" msgid "Download the final notation sheet"
msgstr "Télécharger la fiche de notation finale" msgstr "Télécharger la fiche de notation finale"
#: participation/templates/participation/pool_detail.html:102 #: participation/templates/participation/pool_detail.html:103
msgid "Download all notation sheets"
msgstr "Télécharger toutes les fiches de notation"
#: participation/templates/participation/pool_detail.html:108
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:109 #: participation/templates/participation/pool_detail.html:116
#: participation/templates/participation/pool_detail.html:122 #: participation/templates/participation/pool_detail.html:129
msgid "Add passage" msgid "Add passage"
msgstr "Ajouter un passage" msgstr "Ajouter un passage"
#: participation/templates/participation/pool_detail.html:111 #: participation/templates/participation/pool_detail.html:118
#: participation/templates/participation/pool_detail.html:132 #: participation/templates/participation/pool_detail.html:139
msgid "Update teams" msgid "Update teams"
msgstr "Modifier les équipes" msgstr "Modifier les équipes"
#: participation/templates/participation/pool_detail.html:118 #: participation/templates/participation/pool_detail.html:125
msgid "Passages" msgid "Passages"
msgstr "Passages" msgstr "Passages"
#: participation/templates/participation/pool_detail.html:127 #: participation/templates/participation/pool_detail.html:134
#: 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"
#: participation/templates/participation/pool_detail.html:137 #: participation/templates/participation/pool_detail.html:144
msgid "Upload notes" msgid "Upload notes"
msgstr "Envoyer les notes" msgstr "Envoyer les notes"
@ -1876,7 +1880,17 @@ msgstr "L'utilisateur⋅rice suivant n'est pas inscrit⋅e en tant que juré⋅e
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:1811 #: participation/views.py:1739
#, 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:1744
#, python-brace-format
msgid "Notation sheets of {tournament}.zip"
msgstr "Feuilles de notation de {tournament}.zip"
#: participation/views.py:1911
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

@ -567,6 +567,10 @@ class Pool(models.Model):
"They stay accessible to you. Only averages are given."), "They stay accessible to you. Only averages are given."),
) )
@property
def short_name(self):
return f"{self.get_letter_display()}{self.round}"
@property @property
def solutions(self): def solutions(self):
return [passage.defended_solution for passage in self.passages.all()] return [passage.defended_solution for passage in self.passages.all()]

View File

@ -80,7 +80,8 @@
{% if user.registration.is_volunteer %} {% if user.registration.is_volunteer %}
<div class="card-footer text-center"> <div class="card-footer text-center">
<div class="btn-group"> <div class="btn-group">
<a class="btn btn-info" href="{% url 'participation:pool_scale_note_sheet' pk=pool.pk %}"> <a class="btn btn-sm btn-info" href="{% url 'participation:pool_scale_note_sheet' pk=pool.pk %}">
<i class="fas fa-download"></i>
{% trans "Download the scale sheet" %}{% if pool.passages.count == 5 %} — {% trans "Room" %} 1{% endif %} {% trans "Download the scale sheet" %}{% if pool.passages.count == 5 %} — {% trans "Room" %} 1{% endif %}
</a> </a>
{% if pool.passages.count == 5 %} {% if pool.passages.count == 5 %}
@ -88,18 +89,24 @@
{% trans "Room" %} 2 {% trans "Room" %} 2
</a> </a>
{% endif %} {% endif %}
</div> <a class="btn btn-sm btn-info" href="{% url 'participation:pool_final_note_sheet' pk=pool.pk %}">
<div class="btn-group"> <i class="fas fa-download"></i>
<a class="btn btn-info" href="{% url 'participation:pool_final_note_sheet' pk=pool.pk %}">
{% trans "Download the final notation sheet" %}{% if pool.passages.count == 5 %} — {% trans "Room" %} 1{% endif %} {% trans "Download the final notation sheet" %}{% if pool.passages.count == 5 %} — {% trans "Room" %} 1{% endif %}
</a> </a>
{% if pool.passages.count == 5 %} {% if pool.passages.count == 5 %}
<a class="btn btn-info" href="{% url 'participation:pool_final_note_sheet' pk=pool.pk %}?page=2"> <a class="btn btn-sm btn-info" href="{% url 'participation:pool_final_note_sheet' pk=pool.pk %}?page=2">
{% trans "Room" %} 2 {% trans "Room" %} 2
</a> </a>
{% endif %} {% endif %}
<a class="btn btn-sm btn-info" href="{% url 'participation:pool_notation_sheets' pool_id=pool.id %}">
<i class="fas fa-archive"></i>
{% trans "Download all notation sheets" %}
</a>
</div> </div>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#uploadNotesModal">{% trans "Upload notes from a CSV file" %}</button> <button class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#uploadNotesModal">
<i class="fas fa-upload"></i>
{% trans "Upload notes from a CSV file" %}
</button>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -82,7 +82,7 @@ Tour {{ pool.round }} \;-- Poule {{ pool.get_letter_display }}{{ page }} \;-- {%
\vspace{15mm} \vspace{15mm}
\LARGE Nom jur\'e\textperiodcentered{}e : \LARGE Nom 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 %} {% if jury %}\underline{ {{ jury.user.first_name|safe }} {{ jury.user.last_name|safe }} }{% else %}\underline{\phantom{Phrase suffisamment longue pour le nom}}{% endif %}
$\qquad$ Signature : \underline{\phantom{Phrase moins longue}} $\qquad$ Signature : \underline{\phantom{Phrase moins longue}}
\newpage \newpage

View File

@ -195,13 +195,8 @@
</a> </a>
</li> </li>
<li> <li>
<a> <a href="{% url "participation:tournament_notation_sheets" tournament_id=tournament.id %}">
Archive de tous les barèmes de notes à imprimer triés par poule Archive de toutes les feuilles de notes à imprimer triées par poule
</a>
</li>
<li>
<a>
Archive de tous les tableurs de notes à saisir triés par poule
</a> </a>
</li> </li>
</ul> </ul>

View File

@ -5,8 +5,8 @@ from django.urls import path
from django.views.generic import TemplateView from django.views.generic import TemplateView
from .views import CreateTeamView, FinalNotationSheetTemplateView, JoinTeamView, MyParticipationDetailView, \ from .views import CreateTeamView, FinalNotationSheetTemplateView, JoinTeamView, MyParticipationDetailView, \
MyTeamDetailView, NoteUpdateView, ParticipationDetailView, PassageCreateView, PassageDetailView, \ MyTeamDetailView, NotationSheetsArchiveView, NoteUpdateView, ParticipationDetailView, PassageCreateView, \
PassageUpdateView, PoolCreateView, PoolDetailView, PoolJuryView, PoolNotesTemplateView, \ PassageDetailView, PassageUpdateView, PoolCreateView, PoolDetailView, PoolJuryView, PoolNotesTemplateView, \
PoolPresideJuryView, PoolRemoveJuryView, PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, \ PoolPresideJuryView, PoolRemoveJuryView, PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, \
ScaleNotationSheetTemplateView, SolutionsDownloadView, SolutionUploadView, SynthesisUploadView, \ ScaleNotationSheetTemplateView, SolutionsDownloadView, SolutionUploadView, SynthesisUploadView, \
TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \ TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \
@ -43,6 +43,8 @@ urlpatterns = [
name="tournament_solutions"), name="tournament_solutions"),
path("tournament/<int:tournament_id>/syntheses/", SolutionsDownloadView.as_view(), path("tournament/<int:tournament_id>/syntheses/", SolutionsDownloadView.as_view(),
name="tournament_syntheses"), name="tournament_syntheses"),
path("tournament/<int:tournament_id>/notation/sheets/", NotationSheetsArchiveView.as_view(),
name="tournament_notation_sheets"),
path("tournament/<int:pk>/publish-notes/<int:round>/", TournamentPublishNotesView.as_view(), path("tournament/<int:pk>/publish-notes/<int:round>/", TournamentPublishNotesView.as_view(),
name="tournament_publish_notes"), name="tournament_publish_notes"),
path("pools/create/", PoolCreateView.as_view(), name="pool_create"), path("pools/create/", PoolCreateView.as_view(), name="pool_create"),
@ -52,6 +54,7 @@ urlpatterns = [
path("pools/<int:pool_id>/syntheses/", SolutionsDownloadView.as_view(), name="pool_download_syntheses"), path("pools/<int:pool_id>/syntheses/", SolutionsDownloadView.as_view(), name="pool_download_syntheses"),
path("pools/<int:pk>/notation/scale/", ScaleNotationSheetTemplateView.as_view(), name="pool_scale_note_sheet"), 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>/notation/final/", FinalNotationSheetTemplateView.as_view(), name="pool_final_note_sheet"),
path("pools/<int:pool_id>/notation/sheets/", NotationSheetsArchiveView.as_view(), name="pool_notation_sheets"),
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>/jury/", PoolJuryView.as_view(), name="pool_jury"), path("pools/<int:pk>/jury/", PoolJuryView.as_view(), name="pool_jury"),
path("pools/<int:pk>/jury/remove/<int:jury_id>/", PoolRemoveJuryView.as_view(), name="pool_remove_jury"), path("pools/<int:pk>/jury/remove/<int:jury_id>/", PoolRemoveJuryView.as_view(), name="pool_remove_jury"),

View File

@ -650,7 +650,7 @@ class TournamentExportCSVView(VolunteerMixin, DetailView):
if 'all' not in request.GET: if 'all' not in request.GET:
participations = participations.filter(valid=True) participations = participations.filter(valid=True)
for participation in participations.order_by('-valid', 'team__trigram').all(): for participation in participations.order_by('-valid', 'team__trigram').all():
for registration in participation.team.participants\ for registration in participation.team.participants \
.order_by('coachregistration', 'user__last_name').all(): .order_by('coachregistration', 'user__last_name').all():
writer.writerow({ writer.writerow({
'Tournoi': tournament.name, 'Tournoi': tournament.name,
@ -939,8 +939,8 @@ class PoolJuryView(VolunteerMixin, FormView, DetailView):
if request.user.is_authenticated and \ if request.user.is_authenticated and \
(request.user.registration.is_admin or request.user.registration.is_volunteer (request.user.registration.is_admin or request.user.registration.is_volunteer
and (self.object.tournament in request.user.registration.organized_tournaments.all() and (self.object.tournament in request.user.registration.organized_tournaments.all()
or request.user.registration == self.object.jury_president)): or request.user.registration == self.object.jury_president)):
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission() return self.handle_no_permission()
@ -1022,8 +1022,8 @@ class PoolRemoveJuryView(VolunteerMixin, DetailView):
if request.user.is_authenticated and \ if request.user.is_authenticated and \
(request.user.registration.is_admin or request.user.registration.is_volunteer (request.user.registration.is_admin or request.user.registration.is_volunteer
and (self.object.tournament in request.user.registration.organized_tournaments.all() and (self.object.tournament in request.user.registration.organized_tournaments.all()
or request.user.registration == self.object.jury_president)): or request.user.registration == self.object.jury_president)):
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission() return self.handle_no_permission()
@ -1048,8 +1048,8 @@ class PoolPresideJuryView(VolunteerMixin, DetailView):
if request.user.is_authenticated and \ if request.user.is_authenticated and \
(request.user.registration.is_admin or request.user.registration.is_volunteer (request.user.registration.is_admin or request.user.registration.is_volunteer
and (self.object.tournament in request.user.registration.organized_tournaments.all() and (self.object.tournament in request.user.registration.organized_tournaments.all()
or request.user.registration == self.object.jury_president)): or request.user.registration == self.object.jury_president)):
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission() return self.handle_no_permission()
@ -1076,8 +1076,8 @@ class PoolUploadNotesView(VolunteerMixin, FormView, DetailView):
if request.user.is_authenticated and \ if request.user.is_authenticated and \
(request.user.registration.is_admin or request.user.registration.is_volunteer (request.user.registration.is_admin or request.user.registration.is_volunteer
and (self.object.tournament in request.user.registration.organized_tournaments.all() and (self.object.tournament in request.user.registration.organized_tournaments.all()
or request.user.registration == self.object.jury_president)): or request.user.registration == self.object.jury_president)):
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission() return self.handle_no_permission()
@ -1121,8 +1121,8 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
if request.user.is_authenticated and \ if request.user.is_authenticated and \
(request.user.registration.is_admin or request.user.registration.is_volunteer (request.user.registration.is_admin or request.user.registration.is_volunteer
and (self.object.tournament in request.user.registration.organized_tournaments.all() and (self.object.tournament in request.user.registration.organized_tournaments.all()
or request.user.registration == self.object.jury_president)): or request.user.registration == self.object.jury_president)):
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission() return self.handle_no_permission()
@ -1313,7 +1313,7 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
for i in range(line_length): for i in range(line_length):
table.addElement(TableColumn(stylename=obs_col_style if pool_size == 4 table.addElement(TableColumn(stylename=obs_col_style if pool_size == 4
and i % passage_width == passage_width - 1 else col_style)) and i % passage_width == passage_width - 1 else col_style))
# Add line for the problems for different passages # Add line for the problems for different passages
header_pb = TableRow() header_pb = TableRow()
@ -1652,6 +1652,17 @@ class NotationSheetTemplateView(VolunteerMixin, DetailView):
""" """
model = Pool model = Pool
def dispatch(self, request, *args, **kwargs):
self.object = self.get_object()
if request.user.is_authenticated and \
(request.user.registration.is_admin or request.user.registration.is_volunteer
and (self.object.tournament in request.user.registration.organized_tournaments.all()
or request.user.registration == self.object.jury_president)):
return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission()
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -1661,13 +1672,13 @@ class NotationSheetTemplateView(VolunteerMixin, DetailView):
if not page.isnumeric() or page not in ['1', '2']: if not page.isnumeric() or page not in ['1', '2']:
page = '1' page = '1'
passages = passages.filter(id__in=[passages[0].id, passages[2].id, passages[4].id] passages = passages.filter(id__in=[passages[0].id, passages[2].id, passages[4].id]
if page == '1' else [passages[1].id, passages[3].id]) if page == '1' else [passages[1].id, passages[3].id])
context['page'] = page context['page'] = page
context['passages'] = passages context['passages'] = passages
context['esp'] = passages.count() * '&' context['esp'] = passages.count() * '&'
context['is_jury'] = self.request.user.registration in self.object.juries.all() \ if self.request.user.registration in self.object.juries.all() and 'blank' not in self.request.GET:
and 'blank' not in self.request.GET context['jury'] = self.request.user.registration
context['tfjm_number'] = timezone.now().year - 2010 context['tfjm_number'] = timezone.now().year - 2010
return context return context
@ -1692,6 +1703,95 @@ class FinalNotationSheetTemplateView(NotationSheetTemplateView):
template_name = 'participation/tex/finale.tex' template_name = 'participation/tex/finale.tex'
class NotationSheetsArchiveView(VolunteerMixin, DetailView):
@property
def model(self):
return Pool if 'pool_id' in self.kwargs else Tournament
@property
def pk_url_kwarg(self):
return 'pool_id' if 'pool_id' in self.kwargs else 'tournament_id'
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return self.handle_no_permission()
reg = request.user.registration
if 'pool_id' in kwargs:
pool = self.get_object()
tournament = pool.tournament
if reg.is_admin or reg.is_volunteer \
and (tournament in reg.organized_tournaments.all() or reg in pool.juries.all()):
return super().dispatch(request, *args, **kwargs)
else:
tournament = self.get_object()
if reg.is_admin or reg.is_volunteer and tournament in reg.organized_tournaments.all():
return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission()
def get(self, request, *args, **kwargs):
if 'pool_id' in kwargs:
pool = self.get_object()
tournament = pool.tournament
pools = [pool]
filename = _("Notation sheets of pool {pool} of {tournament}.zip") \
.format(pool=pool.short_name, tournament=tournament.name)
else:
tournament = self.get_object()
pools = tournament.pools.all()
filename = _("Notation sheets of {tournament}.zip").format(tournament=tournament.name)
output = BytesIO()
with ZipFile(output, "w") as zf:
for pool in pools:
prefix = f"{pool.short_name}/" if len(pools) > 1 else ""
for template_name in ['bareme', 'finale']:
pages = [1] if pool.participations.count() < 5 else [1, 2]
for page in pages:
juries = list(pool.juries.all()) + [None]
for jury in juries:
if jury is not None and template_name == "bareme":
continue
context = {'jury': jury, 'page': page, 'pool': pool,
'tfjm_number': timezone.now().year - 2010}
passages = pool.passages.all()
if passages.count() == 5:
passages = passages.filter(id__in=[passages[0].id, passages[2].id, passages[4].id]
if page == '1' else [passages[1].id, passages[3].id])
context['passages'] = passages
context['esp'] = passages.count() * '&'
tex = render_to_string(f"participation/tex/{template_name}.tex",
context=context, request=self.request)
temp_dir = mkdtemp()
with open(os.path.join(temp_dir, "texput.tex"), "w") as f:
f.write(tex)
process = subprocess.Popen(
["pdflatex", "-interaction=nonstopmode", f"-output-directory={temp_dir}",
os.path.join(temp_dir, "texput.tex"), ])
process.wait()
sheet_name = f"Barème pour la poule {pool.short_name}" if template_name == "bareme" \
else (f"Feuille de notation pour la poule {pool.short_name}"
f" - {str(jury) if jury else 'Vierge'}")
sheet_name += " - page 2" if page == 2 else ""
zf.write(os.path.join(temp_dir, "texput.pdf"),
f"{prefix}{sheet_name}.pdf")
response = HttpResponse(content_type="application/zip")
response["Content-Disposition"] = f"attachment; filename=\"{filename}\""
response.write(output.getvalue())
return response
class PassageCreateView(VolunteerMixin, CreateView): class PassageCreateView(VolunteerMixin, CreateView):
model = Passage model = Passage
form_class = PassageForm form_class = PassageForm