Add button to download all solutions and syntheses in a ZIP file

Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
Emmy D'Anello 2023-05-19 14:44:31 +02:00
parent 9bc0e99d6d
commit 29074c4bfd
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
5 changed files with 193 additions and 116 deletions

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: TFJM\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-04-11 22:22+0200\n"
"POT-Creation-Date: 2023-05-19 14:40+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -22,19 +22,19 @@ msgid "API"
msgstr "API"
#: draw/admin.py:16 draw/admin.py:28 draw/admin.py:44 participation/admin.py:44
#: participation/models.py:126 participation/tables.py:86
#: participation/models.py:126 participation/tables.py:87
msgid "teams"
msgstr "équipes"
#: draw/admin.py:40 draw/admin.py:56 draw/models.py:24
#: participation/admin.py:16 participation/admin.py:73
#: participation/admin.py:104 participation/models.py:295
#: participation/models.py:319 participation/models.py:351
#: participation/models.py:319 participation/models.py:352
msgid "tournament"
msgstr "tournoi"
#: draw/admin.py:60 draw/models.py:231 draw/models.py:426
#: participation/models.py:355
#: participation/models.py:356
msgid "round"
msgstr "tour"
@ -46,64 +46,64 @@ msgstr "Tirage au sort"
msgid "You are not an organizer."
msgstr "Vous n'êtes pas un⋅e organisateur⋅rice."
#: draw/consumers.py:144
#: draw/consumers.py:151
msgid "The draw is already started."
msgstr "Le tirage a déjà commencé."
#: draw/consumers.py:150
#: draw/consumers.py:157
msgid "Invalid format"
msgstr "Format invalide"
#: draw/consumers.py:155
#: draw/consumers.py:162
#, python-brace-format
msgid "The sum must be equal to the number of teams: expected {len}, got {sum}"
msgstr ""
"La somme doit être égale au nombre d'équipes : attendu {len}, obtenu {sum}"
#: draw/consumers.py:160
#: draw/consumers.py:167
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."
#: draw/consumers.py:188
#: draw/consumers.py:207
msgid "Draw started!"
msgstr "Le tirage a commencé !"
#: draw/consumers.py:208
#: draw/consumers.py:229
#, python-brace-format
msgid "The draw for the tournament {tournament} will start."
msgstr "Le tirage au sort du tournoi {tournament} va commencer."
#: draw/consumers.py:219 draw/consumers.py:244 draw/consumers.py:578
#: draw/consumers.py:767 draw/consumers.py:849 draw/consumers.py:866
#: draw/consumers.py:936 draw/templates/draw/tournament_content.html:5
#: draw/consumers.py:240 draw/consumers.py:266 draw/consumers.py:639
#: draw/consumers.py:856 draw/consumers.py:945 draw/consumers.py:963
#: draw/consumers.py:1053 draw/templates/draw/tournament_content.html:5
msgid "The draw has not started yet."
msgstr "Le tirage au sort n'a pas encore commencé."
#: draw/consumers.py:231
#: draw/consumers.py:253
#, python-brace-format
msgid "The draw for the tournament {tournament} is aborted."
msgstr "Le tirage au sort du tournoi {tournament} est annulé."
#: draw/consumers.py:271 draw/consumers.py:292 draw/consumers.py:524
#: draw/consumers.py:583 draw/consumers.py:772
#: draw/consumers.py:293 draw/consumers.py:314 draw/consumers.py:579
#: draw/consumers.py:644 draw/consumers.py:861
msgid "This is not the time for this."
msgstr "Ce n'est pas le moment pour cela."
#: draw/consumers.py:284 draw/consumers.py:287
#: draw/consumers.py:306 draw/consumers.py:309
msgid "You've already launched the dice."
msgstr "Vous avez déjà lancé le dé."
#: draw/consumers.py:290
#: draw/consumers.py:312
msgid "It is not your turn."
msgstr "Ce n'est pas votre tour."
#: draw/consumers.py:371
#: draw/consumers.py:395
#, python-brace-format
msgid "Dices from teams {teams} are identical. Please relaunch your dices."
msgstr ""
"Les dés des équipes {teams} sont identiques. Merci de relancer vos dés."
#: draw/consumers.py:869
#: draw/consumers.py:966
msgid "This is only available for the final tournament."
msgstr "Cela n'est possible que pour la finale."
@ -168,7 +168,7 @@ msgstr "La poule en cours, où les équipes choisissent leurs problèmes"
msgid "rounds"
msgstr "tours"
#: draw/models.py:254 participation/models.py:369
#: draw/models.py:254 participation/models.py:370
msgid "letter"
msgstr "lettre"
@ -207,17 +207,17 @@ msgid "Pool {letter}{number}"
msgstr "Poule {letter}{number}"
#: draw/models.py:407 draw/models.py:434 participation/admin.py:69
#: participation/admin.py:88 participation/models.py:421
#: participation/models.py:430 participation/tables.py:82
#: participation/admin.py:88 participation/models.py:423
#: participation/models.py:432 participation/tables.py:83
msgid "pool"
msgstr "poule"
#: draw/models.py:408 participation/models.py:422
#: draw/models.py:408 participation/models.py:424
msgid "pools"
msgstr "poules"
#: draw/models.py:420 participation/models.py:342 participation/models.py:591
#: participation/models.py:621 participation/models.py:659
#: draw/models.py:420 participation/models.py:342 participation/models.py:593
#: participation/models.py:623 participation/models.py:661
msgid "participation"
msgstr "participation"
@ -241,8 +241,8 @@ msgid ""
msgstr ""
"L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1."
#: draw/models.py:457 draw/models.py:480 participation/models.py:444
#: participation/models.py:628
#: draw/models.py:457 draw/models.py:480 participation/models.py:446
#: participation/models.py:630
#, python-brace-format
msgid "Problem #{problem}"
msgstr "Problème n°{problem}"
@ -331,10 +331,10 @@ msgstr "équipe"
#: draw/templates/draw/tournament_content.html:228
#: draw/templates/draw/tournament_content.html:229
#: draw/templates/draw/tournament_content.html:230
#: participation/templates/participation/pool_detail.html:62
#: participation/templates/participation/pool_detail.html:66
#: participation/templates/participation/pool_detail.html:72
#: participation/templates/participation/pool_detail.html:76
#: participation/templates/participation/pool_detail.html:84
#: participation/templates/participation/pool_detail.html:88
#: participation/templates/participation/pool_detail.html:94
#: participation/templates/participation/pool_detail.html:98
msgid "Room"
msgstr "Salle"
@ -443,21 +443,21 @@ msgid "selected for final"
msgstr "sélectionnée pour la finale"
#: participation/admin.py:57 participation/admin.py:116
#: participation/models.py:451 participation/tables.py:109
#: participation/models.py:453 participation/tables.py:111
msgid "defender"
msgstr "défenseur⋅se"
#: participation/admin.py:61 participation/models.py:458
#: participation/models.py:671
#: participation/admin.py:61 participation/models.py:460
#: participation/models.py:673
msgid "opponent"
msgstr "opposant⋅e"
#: participation/admin.py:65 participation/models.py:465
#: participation/models.py:672
#: participation/admin.py:65 participation/models.py:467
#: participation/models.py:674
msgid "reporter"
msgstr "rapporteur⋅e"
#: participation/admin.py:120 participation/models.py:626
#: participation/admin.py:120 participation/models.py:628
msgid "problem"
msgstr "numéro de problème"
@ -515,7 +515,7 @@ msgid "Add new jury"
msgstr "Ajouter un⋅e nouvelleau juré⋅e"
#: participation/forms.py:227
#: participation/templates/participation/pool_detail.html:101
#: participation/templates/participation/pool_detail.html:123
#: participation/templates/participation/tournament_detail.html:111
msgid "Add"
msgstr "Ajouter"
@ -676,32 +676,32 @@ msgstr "L'équipe est sélectionnée pour la finale."
msgid "Participation of the team {name} ({trigram})"
msgstr "Participation de l'équipe {name} ({trigram})"
#: participation/models.py:343 participation/models.py:375
#: participation/models.py:343 participation/models.py:376
msgid "participations"
msgstr "participations"
#: participation/models.py:357 participation/models.py:358
#: participation/models.py:358 participation/models.py:359
#, python-brace-format
msgid "Round {round}"
msgstr "Tour {round}"
#: participation/models.py:381
#: participation/models.py:382
msgid "juries"
msgstr "jurys"
#: participation/models.py:388
#: participation/models.py:389
msgid "BigBlueButton URL"
msgstr "Lien BigBlueButton"
#: participation/models.py:389
#: participation/models.py:390
msgid "The link of the BBB visio for this pool."
msgstr "Le lien du salon BBB pour cette poule."
#: participation/models.py:394
#: participation/models.py:395
msgid "results available"
msgstr "résultats disponibles"
#: participation/models.py:395
#: participation/models.py:396
msgid ""
"Check this case when results become accessible to teams. They stay "
"accessible to you. Only averages are given."
@ -710,28 +710,28 @@ msgstr ""
"Ils restent toujours accessibles pour vous. Seules les moyennes sont "
"communiquées."
#: participation/models.py:415
#: participation/models.py:417
#, python-brace-format
msgid "Pool of day {round} for tournament {tournament} with teams {teams}"
msgstr "Poule du jour {round} du tournoi {tournament} avec les équipes {teams}"
#: participation/models.py:435
#: participation/models.py:437
msgid "position"
msgstr "position"
#: participation/models.py:442
#: participation/models.py:444
msgid "defended solution"
msgstr "solution défendue"
#: participation/models.py:475
#: participation/models.py:477
msgid "observer"
msgstr "observateur⋅rice"
#: participation/models.py:480
#: participation/models.py:482
msgid "penalties"
msgstr "pénalités"
#: participation/models.py:482
#: participation/models.py:484
msgid ""
"Number of penalties for the defender. The defender will loose a 0.5 "
"coefficient per penalty."
@ -739,124 +739,124 @@ msgstr ""
"Nombre de pénalités pour læ défenseur⋅se. Læ défenseur⋅se perd un "
"coefficient 0.5 sur sa présentation orale par pénalité."
#: participation/models.py:558 participation/models.py:561
#: participation/models.py:564 participation/models.py:567
#: participation/models.py:560 participation/models.py:563
#: participation/models.py:566 participation/models.py:569
#, 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:572
#: participation/models.py:574
#, python-brace-format
msgid "Passage of {defender} for problem {problem}"
msgstr "Passage de {defender} pour le problème {problem}"
#: participation/models.py:576 participation/models.py:585
#: participation/models.py:666 participation/models.py:708
#: participation/models.py:578 participation/models.py:587
#: participation/models.py:668 participation/models.py:710
msgid "passage"
msgstr "passage"
#: participation/models.py:577
#: participation/models.py:579
msgid "passages"
msgstr "passages"
#: participation/models.py:596
#: participation/models.py:598
msgid "difference"
msgstr "différence"
#: participation/models.py:597
#: participation/models.py:599
msgid "Score to add/remove on the final score"
msgstr "Score à ajouter/retrancher au score final"
#: participation/models.py:604
#: participation/models.py:606
msgid "tweak"
msgstr "harmonisation"
#: participation/models.py:605
#: participation/models.py:607
msgid "tweaks"
msgstr "harmonisations"
#: participation/models.py:633
#: participation/models.py:635
msgid "solution for the final tournament"
msgstr "solution pour la finale"
#: participation/models.py:638 participation/models.py:677
#: participation/models.py:640 participation/models.py:679
msgid "file"
msgstr "fichier"
#: participation/models.py:644
#: participation/models.py:646
#, 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:646
#: participation/models.py:648
msgid "for final"
msgstr "pour la finale"
#: participation/models.py:649
#: participation/models.py:651
msgid "solution"
msgstr "solution"
#: participation/models.py:650
#: participation/models.py:652
msgid "solutions"
msgstr "solutions"
#: participation/models.py:683
#: participation/models.py:685
#, python-brace-format
msgid "Synthesis of {team} as {type} for problem {problem} of {defender}"
msgstr ""
"Note de synthèse de l'équipe {team} en tant que {type} pour le problème "
"{problem} de {defender}"
#: participation/models.py:691
#: participation/models.py:693
msgid "synthesis"
msgstr "note de synthèse"
#: participation/models.py:692
#: participation/models.py:694
msgid "syntheses"
msgstr "notes de synthèse"
#: participation/models.py:701
#: participation/models.py:703
msgid "jury"
msgstr "jury"
#: participation/models.py:713
#: participation/models.py:715
msgid "defender writing note"
msgstr "note d'écrit de læ défenseur⋅se"
#: participation/models.py:719
#: participation/models.py:721
msgid "defender oral note"
msgstr "note d'oral de læ défenseur⋅se"
#: participation/models.py:725
#: participation/models.py:727
msgid "opponent writing note"
msgstr "note d'écrit de l'opposant⋅e"
#: participation/models.py:731
#: participation/models.py:733
msgid "opponent oral note"
msgstr "note d'oral de l'opposant⋅e"
#: participation/models.py:737
#: participation/models.py:739
msgid "reporter writing note"
msgstr "note d'écrit de læ rapporteur⋅e"
#: participation/models.py:743
#: participation/models.py:745
msgid "reporter oral note"
msgstr "note d'oral de læ rapporteur⋅e"
#: participation/models.py:749
#: participation/models.py:751
msgid "observer note"
msgstr "note de l'observateur⋅rice"
#: participation/models.py:778
#: participation/models.py:780
#, python-brace-format
msgid "Notes of {jury} for {passage}"
msgstr "Notes de {jury} pour le {passage}"
#: participation/models.py:785
#: participation/models.py:787
msgid "note"
msgstr "note"
#: participation/models.py:786
#: participation/models.py:788
msgid "notes"
msgstr "notes"
@ -872,21 +872,21 @@ msgstr "Validation en attente"
msgid "Not validated"
msgstr "Non validée"
#: participation/tables.py:62
#: participation/tables.py:63
msgid "date"
msgstr "date"
#: participation/tables.py:65
#: participation/tables.py:66
#, python-brace-format
msgid "From {start} to {end}"
msgstr "Du {start} au {end}"
#: participation/tables.py:91
#: participation/tables.py:93
#, python-brace-format
msgid "Pool {letter}{round}"
msgstr "Poule {letter}{round}"
#: participation/tables.py:95
#: participation/tables.py:97
msgid "No defined team"
msgstr "Pas d'équipe définie"
@ -940,9 +940,9 @@ msgstr "Rejoindre"
#: participation/templates/participation/passage_detail.html:120
#: participation/templates/participation/passage_detail.html:126
#: participation/templates/participation/pool_add_jurys.html:35
#: participation/templates/participation/pool_detail.html:88
#: participation/templates/participation/pool_detail.html:106
#: participation/templates/participation/pool_detail.html:111
#: participation/templates/participation/pool_detail.html:110
#: participation/templates/participation/pool_detail.html:128
#: participation/templates/participation/pool_detail.html:133
#: participation/templates/participation/team_detail.html:128
#: participation/templates/participation/team_detail.html:192
#: participation/templates/participation/tournament_form.html:12
@ -1006,7 +1006,7 @@ msgstr "Envoyer une solution"
#: participation/templates/participation/participation_detail.html:59
#: participation/templates/participation/passage_detail.html:132
#: participation/templates/participation/pool_detail.html:116
#: participation/templates/participation/pool_detail.html:138
#: participation/templates/participation/team_detail.html:187
#: participation/templates/participation/upload_motivation_letter.html:13
#: participation/templates/participation/upload_notes.html:17
@ -1057,10 +1057,12 @@ msgid "Defender penalties count:"
msgstr "Nombre de pénalités :"
#: participation/templates/participation/passage_detail.html:39
#: participation/templates/participation/pool_detail.html:46
msgid "Syntheses:"
msgstr "Notes de synthèse :"
#: participation/templates/participation/passage_detail.html:44
#: participation/templates/participation/pool_detail.html:55
msgid "No synthesis was uploaded yet."
msgstr "Aucune note de synthèse n'a encore été envoyée."
@ -1141,7 +1143,7 @@ msgstr ""
#: participation/templates/participation/pool_add_jurys.html:11
#: participation/templates/participation/pool_add_jurys.html:34
#: participation/templates/participation/pool_detail.html:105
#: participation/templates/participation/pool_detail.html:127
#: participation/templates/participation/pool_form.html:11
msgid "Update pool"
msgstr "Modifier la poule"
@ -1182,42 +1184,47 @@ msgstr "Ajouter des juré⋅es"
msgid "Defended solutions:"
msgstr "Solutions défendues :"
#: participation/templates/participation/pool_detail.html:43
#: participation/templates/participation/pool_detail.html:42
#: participation/templates/participation/pool_detail.html:61
msgid "Download all"
msgstr "Tout télécharger"
#: participation/templates/participation/pool_detail.html:65
msgid "BigBlueButton link:"
msgstr "Lien BigBlueButton :"
#: participation/templates/participation/pool_detail.html:49
#: participation/templates/participation/pool_detail.html:71
#: participation/templates/participation/tournament_detail.html:97
msgid "Ranking"
msgstr "Classement"
#: participation/templates/participation/pool_detail.html:62
#: participation/templates/participation/pool_detail.html:84
msgid "Download the scale sheet"
msgstr "Télécharger la feuille de barème"
#: participation/templates/participation/pool_detail.html:72
#: participation/templates/participation/pool_detail.html:94
msgid "Download the final notation sheet"
msgstr "Télécharger la fiche de notation finale"
#: participation/templates/participation/pool_detail.html:80
#: participation/templates/participation/pool_detail.html:102
msgid "Upload notes from a CSV file"
msgstr "Soumettre les notes à partir d'un fichier CSV"
#: participation/templates/participation/pool_detail.html:87
#: participation/templates/participation/pool_detail.html:100
#: participation/templates/participation/pool_detail.html:109
#: participation/templates/participation/pool_detail.html:122
msgid "Add passage"
msgstr "Ajouter un passage"
#: participation/templates/participation/pool_detail.html:89
#: participation/templates/participation/pool_detail.html:110
#: participation/templates/participation/pool_detail.html:111
#: participation/templates/participation/pool_detail.html:132
msgid "Update teams"
msgstr "Modifier les équipes"
#: participation/templates/participation/pool_detail.html:96
#: participation/templates/participation/pool_detail.html:118
msgid "Passages"
msgstr "Passages"
#: participation/templates/participation/pool_detail.html:115
#: participation/templates/participation/pool_detail.html:137
msgid "Upload notes"
msgstr "Envoyer les notes"
@ -1582,33 +1589,43 @@ msgstr "L'équipe n'est pas encore validée."
msgid "Participation of team {trigram}"
msgstr "Participation de l'équipe {trigram}"
#: participation/views.py:647
#: participation/views.py:655
msgid "You can't upload a solution after the deadline."
msgstr "Vous ne pouvez pas envoyer de solution après la date limite."
#: participation/views.py:738
#: participation/views.py:763
#, 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:764
#, python-brace-format
msgid "Syntheses for pool {pool} of tournament {tournament}.zip"
msgstr "Notes de synthèses pour la poule {pool} du tournoi {tournament}.zip"
#: participation/views.py:782
#, python-brace-format
msgid "Jurys of {pool}"
msgstr "Juré⋅es de la {pool}"
#: participation/views.py:765
#: participation/views.py:809
msgid "New TFJM² jury account"
msgstr "Nouveau compte de juré⋅e pour le TFJM²"
#: participation/views.py:778
#: participation/views.py:822
#, python-brace-format
msgid "The jury {name} has been successfully added!"
msgstr "Læ juré⋅e {name} a été ajouté⋅e avec succès !"
#: participation/views.py:815
#: participation/views.py:859
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:829
#: participation/views.py:873
msgid "Notes were successfully uploaded."
msgstr "Les notes ont bien été envoyées."
#: participation/views.py:1493
#: participation/views.py:1537
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."
@ -2317,11 +2334,11 @@ msgstr "Autorisation parentale de {student}.{ext}"
msgid "Scholarship attestation of {user}.{ext}"
msgstr "Notification de bourse de {user}.{ext}"
#: tfjm/settings.py:165
#: tfjm/settings.py:170
msgid "English"
msgstr "Anglais"
#: tfjm/settings.py:166
#: tfjm/settings.py:171
msgid "French"
msgstr "Français"

View File

@ -399,7 +399,7 @@ class Pool(models.Model):
@property
def solutions(self):
return Solution.objects.filter(participation__in=self.participations, final_solution=self.tournament.final)
return [passage.defended_solution for passage in self.passages.all()]
def average(self, participation):
return sum(passage.average(participation) for passage in self.passages.all()) \

View File

@ -36,8 +36,30 @@
<dt class="col-sm-3">{% trans "Defended solutions:" %}</dt>
<dd class="col-sm-9">
{% for passage in pool.passages.all %}
<a href="{{ passage.defended_solution.file.url }}">{{ passage.defended_solution }}{% if not forloop.last %}, {% endif %}</a>
<a href="{{ passage.defended_solution.file.url }}">{{ passage.defender.team.trigram }} — {{ passage.get_solution_number_display }}</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
<a href="{% url 'participation:pool_download_solutions' pk=pool.pk %}" class="badge rounded-pill text-bg-secondary">
<i class="fas fa-download"></i> {% trans "Download all" %}
</a>
</dd>
<dt class="col-sm-3">{% trans "Syntheses:" %}</dt>
<dd class="col-sm-9">
<ul class="list-group list-group-flush">
{% for passage in pool.passages.all %}
<li class="list-group-item">
{{ passage.defender.team.trigram }} — {{ passage.get_solution_number_display }} :
{% for synthesis in passage.syntheses.all %}
<a href="{{ synthesis.file.url }}">{{ synthesis.participation.team.trigram }} ({{ synthesis.get_type_display }})</a>{% if not forloop.last %}, {% endif %}
{% empty %}
{% trans "No synthesis was uploaded yet." %}
{% endfor %}
</li>
{% endfor %}
</ul>
<a href="{% url 'participation:pool_download_syntheses' pk=pool.pk %}" class="badge rounded-pill text-bg-secondary">
<i class="fas fa-download"></i> {% trans "Download all" %}
</a>
</dd>
<dt class="col-sm-3">{% trans "BigBlueButton link:" %}</dt>

View File

@ -6,9 +6,9 @@ from django.views.generic import TemplateView
from .views import CreateTeamView, FinalNotationSheetTemplateView, JoinTeamView, MyParticipationDetailView, \
MyTeamDetailView, NoteUpdateView, ParticipationDetailView, PassageCreateView, PassageDetailView, \
PassageUpdateView, PoolAddJurysView, PoolCreateView, PoolDetailView, PoolNotesTemplateView, PoolUpdateTeamsView, \
PoolUpdateView, PoolUploadNotesView, ScaleNotationSheetTemplateView, SolutionUploadView, SynthesisUploadView, \
TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \
PassageUpdateView, PoolAddJurysView, PoolCreateView, PoolDetailView, PoolDownloadView, PoolNotesTemplateView, \
PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, ScaleNotationSheetTemplateView, SolutionUploadView, \
SynthesisUploadView, TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \
TeamUploadMotivationLetterView, TournamentCreateView, TournamentDetailView, TournamentExportCSVView, \
TournamentListView, TournamentUpdateView
@ -37,6 +37,8 @@ urlpatterns = [
path("pools/create/", PoolCreateView.as_view(), name="pool_create"),
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>/solutions/", PoolDownloadView.as_view(), name="pool_download_solutions"),
path("pools/<int:pk>/syntheses/", PoolDownloadView.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/final/", FinalNotationSheetTemplateView.as_view(), name="pool_final_note_sheet"),
path("pools/<int:pk>/update-teams/", PoolUpdateTeamsView.as_view(), name="pool_update_teams"),

View File

@ -733,6 +733,42 @@ class PoolUpdateTeamsView(VolunteerMixin, UpdateView):
return self.handle_no_permission()
class PoolDownloadView(VolunteerMixin, DetailView):
"""
Download all solutions or syntheses as a ZIP archive.
"""
model = Pool
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return self.handle_no_permission()
if request.user.registration.is_admin or request.user.registration.is_volunteer \
and (self.get_object().tournament in request.user.registration.organized_tournaments.all()
or request.user.registration in self.get_object().juries.all()):
return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission()
def get(self, request, *args, **kwargs):
pool = self.get_object()
is_solution = 'solutions' in request.path
output = BytesIO()
zf = ZipFile(output, "w")
for s in (pool.solutions if is_solution else Synthesis.objects.filter(passage__pool=pool).all()):
zf.write("media/" + s.file.name, f"{s}.pdf")
zf.close()
response = HttpResponse(content_type="application/zip")
filename = _("Solutions for pool {pool} of tournament {tournament}.zip") \
if is_solution else _("Syntheses for pool {pool} of tournament {tournament}.zip")
filename = filename.format(pool=pool.get_letter_display() + str(pool.round), tournament=pool.tournament.name)
response["Content-Disposition"] = "attachment; filename=\"{filename}\"" \
.format(filename=filename)
response.write(output.getvalue())
return response
class PoolAddJurysView(VolunteerMixin, FormView, DetailView):
"""
This view lets organizers set jurys for a pool, without multiplying clicks.