diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index b5f7ac5..23344c5 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: TFJM\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-03-24 15:35+0100\n" +"POT-Creation-Date: 2024-03-24 18:13+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Emmy D'Anello \n" "Language-Team: LANGUAGE \n" @@ -224,7 +224,7 @@ msgid "pools" msgstr "poules" #: draw/models.py:421 participation/models.py:503 participation/models.py:767 -#: participation/models.py:797 participation/models.py:835 +#: participation/models.py:797 participation/models.py:839 msgid "participation" msgstr "participation" @@ -377,8 +377,8 @@ msgstr "Êtes-vous sûr·e de vouloir annuler le tirage au sort ?" msgid "Close" msgstr "Fermer" -#: draw/views.py:31 participation/views.py:155 participation/views.py:441 -#: participation/views.py:472 +#: draw/views.py:31 participation/views.py:156 participation/views.py:442 +#: participation/views.py:473 msgid "You are not in a team." msgstr "Vous n'êtes pas dans une équipe." @@ -461,12 +461,12 @@ msgid "defender" msgstr "défenseur⋅se" #: participation/admin.py:128 participation/models.py:634 -#: participation/models.py:847 +#: participation/models.py:851 msgid "opponent" msgstr "opposant⋅e" #: participation/admin.py:132 participation/models.py:641 -#: participation/models.py:848 +#: participation/models.py:852 msgid "reporter" msgstr "rapporteur⋅e" @@ -490,11 +490,11 @@ msgstr "Ce trigramme est déjà utilisé." msgid "No team was found with this access code." msgstr "Aucune équipe n'a été trouvée avec ce code d'accès." -#: participation/forms.py:60 participation/views.py:443 +#: participation/forms.py:60 participation/views.py:444 msgid "The team is already validated or the validation is pending." msgstr "La validation de l'équipe est déjà faite ou en cours." -#: participation/forms.py:89 participation/forms.py:359 +#: participation/forms.py:89 participation/forms.py:364 #: registration/forms.py:122 registration/forms.py:144 #: registration/forms.py:166 registration/forms.py:188 #: registration/forms.py:237 registration/forms.py:270 @@ -520,7 +520,7 @@ msgstr "Message à adresser à l'équipe :" msgid "The uploaded file size must be under 5 Mo." msgstr "Le fichier envoyé doit peser moins de 5 Mo." -#: participation/forms.py:161 participation/forms.py:361 +#: participation/forms.py:161 participation/forms.py:366 msgid "The uploaded file must be a PDF file." msgstr "Le fichier envoyé doit être au format PDF." @@ -528,21 +528,21 @@ msgstr "Le fichier envoyé doit être au format PDF." msgid "The PDF file must not have more than 30 pages." msgstr "Le fichier PDF ne doit pas avoir plus de 30 pages." -#: participation/forms.py:232 +#: participation/forms.py:237 #: participation/templates/participation/pool_detail.html:123 -#: participation/templates/participation/tournament_detail.html:119 +#: participation/templates/participation/tournament_detail.html:139 msgid "Add" msgstr "Ajouter" -#: participation/forms.py:247 +#: participation/forms.py:252 msgid "This user already exists, but is a participant." msgstr "Cet⋅te utilisateur⋅rice existe déjà, mais en tant que participant⋅e." -#: participation/forms.py:258 +#: participation/forms.py:263 msgid "CSV file:" msgstr "Tableur au format CSV :" -#: participation/forms.py:282 +#: participation/forms.py:287 msgid "" "This file contains non-UTF-8 and non-ISO-8859-1 content. Please send your " "sheet as a CSV file." @@ -550,30 +550,30 @@ msgstr "" "Ce fichier contient des éléments non-UTF-8 et non-ISO-8859-1. Merci " "d'envoyer votre tableur au format CSV." -#: participation/forms.py:297 +#: participation/forms.py:302 msgid "Can't determine the pool size. Are you sure your file is correct?" msgstr "" "Impossible de déterminer la taille de la poule. Êtes-vous sûr⋅e que le " "fichier est correct ?" -#: participation/forms.py:317 +#: participation/forms.py:322 msgid "The following note is higher of the maximum expected value:" msgstr "La note suivante est supérieure au maximum attendu :" -#: participation/forms.py:325 +#: participation/forms.py:330 msgid "The following user was not found:" msgstr "L'utilisateur⋅rice suivant n'a pas été trouvé :" -#: participation/forms.py:342 +#: participation/forms.py:347 msgid "The defender, the opponent and the reporter must be different." msgstr "" "Les équipes défenseuse, opposante et rapportrice doivent être différent⋅es." -#: participation/forms.py:346 +#: participation/forms.py:351 msgid "This defender did not work on this problem." msgstr "Ce⋅tte défenseur⋅se ne travaille pas sur ce problème." -#: participation/forms.py:365 +#: participation/forms.py:370 msgid "The PDF file must not have more than 2 pages." msgstr "Le fichier PDF ne doit pas avoir plus de 2 pages." @@ -934,7 +934,7 @@ msgid "Passage of {defender} for problem {problem}" msgstr "Passage de {defender} pour le problème {problem}" #: participation/models.py:752 participation/models.py:761 -#: participation/models.py:842 participation/models.py:884 +#: participation/models.py:846 participation/models.py:888 msgid "passage" msgstr "passage" @@ -962,84 +962,84 @@ msgstr "harmonisations" msgid "solution for the final tournament" msgstr "solution pour la finale" -#: participation/models.py:814 participation/models.py:853 +#: participation/models.py:814 participation/models.py:857 msgid "file" msgstr "fichier" -#: participation/models.py:820 +#: participation/models.py:824 #, 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:822 +#: participation/models.py:826 msgid "for final" msgstr "pour la finale" -#: participation/models.py:825 +#: participation/models.py:829 msgid "solution" msgstr "solution" -#: participation/models.py:826 +#: participation/models.py:830 msgid "solutions" msgstr "solutions" -#: participation/models.py:859 +#: participation/models.py:863 #, 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:867 +#: participation/models.py:871 msgid "synthesis" msgstr "note de synthèse" -#: participation/models.py:868 +#: participation/models.py:872 msgid "syntheses" msgstr "notes de synthèse" -#: participation/models.py:877 +#: participation/models.py:881 msgid "jury" msgstr "jury" -#: participation/models.py:889 +#: participation/models.py:893 msgid "defender writing note" msgstr "note d'écrit de la défense" -#: participation/models.py:895 +#: participation/models.py:899 msgid "defender oral note" msgstr "note d'oral de la défense" -#: participation/models.py:901 +#: participation/models.py:905 msgid "opponent writing note" msgstr "note d'écrit de l'opposition" -#: participation/models.py:907 +#: participation/models.py:911 msgid "opponent oral note" msgstr "note d'oral de l'opposition" -#: participation/models.py:913 +#: participation/models.py:917 msgid "reporter writing note" msgstr "note d'écrit du rapportage" -#: participation/models.py:919 +#: participation/models.py:923 msgid "reporter oral note" msgstr "note d'oral du rapportage" -#: participation/models.py:925 +#: participation/models.py:929 msgid "observer note" msgstr "note de l'observation" -#: participation/models.py:958 +#: participation/models.py:965 #, python-brace-format msgid "Notes of {jury} for {passage}" msgstr "Notes de {jury} pour le {passage}" -#: participation/models.py:961 +#: participation/models.py:968 msgid "note" msgstr "note" -#: participation/models.py:962 +#: participation/models.py:969 msgid "notes" msgstr "notes" @@ -1383,8 +1383,8 @@ msgid "" "the right to see all solutions and if necessary define the notes of other " "jury members." msgstr "" -"Sur cette page, vous pouvez aussi définir læ président⋅e du jury, qui aura le " -"droit de voir toutes les solutions et si nécessaire définir les notes des " +"Sur cette page, vous pouvez aussi définir læ président⋅e du jury, qui aura " +"le droit de voir toutes les solutions et si nécessaire définir les notes des " "autres membres du jury." #: participation/templates/participation/pool_jury.html:41 @@ -1550,7 +1550,7 @@ msgid "Invalidate" msgstr "Invalider" #: participation/templates/participation/team_detail.html:209 -#: participation/views.py:326 +#: participation/views.py:327 msgid "Upload motivation letter" msgstr "Envoyer la lettre de motivation" @@ -1559,7 +1559,7 @@ msgid "Update team" msgstr "Modifier l'équipe" #: participation/templates/participation/team_detail.html:219 -#: participation/views.py:435 +#: participation/views.py:436 msgid "Leave team" msgstr "Quitter l'équipe" @@ -1653,7 +1653,15 @@ msgstr "Poules" msgid "Add new pool" msgstr "Ajouter une nouvelle poule" -#: participation/templates/participation/tournament_detail.html:118 +#: participation/templates/participation/tournament_detail.html:121 +msgid "Publish notes for first round" +msgstr "Publier les notes pour le premier tour" + +#: participation/templates/participation/tournament_detail.html:127 +msgid "Publish notes for second round" +msgstr "Publier les notes pour le second tour" + +#: participation/templates/participation/tournament_detail.html:138 msgid "Add pool" msgstr "Ajouter une poule" @@ -1686,44 +1694,44 @@ msgstr "Modèles :" msgid "Warning: non-free format" msgstr "Attention : format non libre" -#: participation/views.py:55 tfjm/templates/base.html:79 +#: participation/views.py:56 tfjm/templates/base.html:79 #: tfjm/templates/navbar.html:35 msgid "Create team" msgstr "Créer une équipe" -#: participation/views.py:64 participation/views.py:105 +#: participation/views.py:65 participation/views.py:106 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." -#: participation/views.py:66 participation/views.py:107 +#: participation/views.py:67 participation/views.py:108 msgid "You are already in a team." msgstr "Vous êtes déjà dans une équipe." -#: participation/views.py:96 tfjm/templates/base.html:74 +#: participation/views.py:97 tfjm/templates/base.html:74 #: tfjm/templates/navbar.html:40 msgid "Join team" msgstr "Rejoindre une équipe" -#: participation/views.py:156 participation/views.py:473 +#: participation/views.py:157 participation/views.py:474 msgid "You don't participate, so you don't have any team." msgstr "Vous ne participez pas, vous n'avez donc pas d'équipe." -#: participation/views.py:182 +#: participation/views.py:183 #, python-brace-format msgid "Detail of team {trigram}" msgstr "Détails de l'équipe {trigram}" -#: participation/views.py:211 +#: participation/views.py:212 msgid "You don't participate, so you can't request the validation of the team." msgstr "" "Vous ne participez pas, vous ne pouvez pas demander la validation de " "l'équipe." -#: participation/views.py:214 +#: participation/views.py:215 msgid "The validation of the team is already done or pending." msgstr "La validation de l'équipe est déjà faite ou en cours." -#: participation/views.py:217 +#: participation/views.py:218 msgid "" "The team can't be validated: missing email address confirmations, " "authorizations, people, motivation letter or the tournament is not set." @@ -1732,119 +1740,123 @@ msgstr "" "d'adresse e-mail, soit une autorisation, soit des personnes, soit la lettre " "de motivation, soit le tournoi n'a pas été choisi." -#: participation/views.py:239 +#: participation/views.py:240 msgid "You are not an organizer of the tournament." msgstr "Vous n'êtes pas un⋅e organisateur⋅rice du tournoi." -#: participation/views.py:242 +#: participation/views.py:243 msgid "This team has no pending validation." msgstr "L'équipe n'a pas de validation en attente." -#: participation/views.py:269 +#: participation/views.py:270 msgid "You must specify if you validate the registration or not." msgstr "Vous devez spécifier si vous validez l'inscription ou non." -#: participation/views.py:304 +#: participation/views.py:305 #, python-brace-format msgid "Update team {trigram}" msgstr "Mise à jour de l'équipe {trigram}" -#: participation/views.py:365 participation/views.py:421 +#: participation/views.py:366 participation/views.py:422 #, python-brace-format msgid "Motivation letter of {team}.{ext}" msgstr "Lettre de motivation de {team}.{ext}" -#: participation/views.py:396 +#: participation/views.py:397 #, python-brace-format msgid "Photo authorization of {participant}.{ext}" msgstr "Autorisation de droit à l'image de {participant}.{ext}" -#: participation/views.py:402 +#: participation/views.py:403 #, python-brace-format msgid "Parental authorization of {participant}.{ext}" msgstr "Autorisation parentale de {participant}.{ext}" -#: participation/views.py:409 +#: participation/views.py:410 #, python-brace-format msgid "Health sheet of {participant}.{ext}" msgstr "Fiche sanitaire de {participant}.{ext}" -#: participation/views.py:415 +#: participation/views.py:416 #, python-brace-format msgid "Vaccine sheet of {participant}.{ext}" msgstr "Carnet de vaccination de {participant}.{ext}" -#: participation/views.py:425 +#: participation/views.py:426 #, python-brace-format msgid "Photo authorizations of team {trigram}.zip" msgstr "Autorisations de droit à l'image de l'équipe {trigram}.zip" -#: participation/views.py:487 +#: participation/views.py:488 msgid "The team is not validated yet." msgstr "L'équipe n'est pas encore validée." -#: participation/views.py:501 +#: participation/views.py:502 #, python-brace-format msgid "Participation of team {trigram}" msgstr "Participation de l'équipe {trigram}" -#: participation/views.py:582 +#: participation/views.py:584 #, python-brace-format msgid "Payments of {tournament}" msgstr "Paiements de {tournament}" -#: participation/views.py:663 +#: participation/views.py:657 +msgid "Notes published!" +msgstr "Notes publiées !" + +#: participation/views.py:693 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:771 +#: participation/views.py:802 #, 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:772 +#: participation/views.py:803 #, 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:798 +#: participation/views.py:833 #, python-brace-format msgid "Jury of pool {pool} for {tournament} with teams {teams}" msgstr "Jury de la poule {pool} pour {tournament} avec les équipes {teams}" -#: participation/views.py:814 +#: participation/views.py:849 #, python-brace-format msgid "The jury {name} is already in the pool!" msgstr "{name} est déjà dans la poule !" -#: participation/views.py:834 +#: participation/views.py:869 msgid "New TFJM² jury account" msgstr "Nouveau compte de juré⋅e pour le TFJM²" -#: participation/views.py:851 +#: participation/views.py:886 #, python-brace-format msgid "The jury {name} has been successfully added!" msgstr "{name} a été ajouté⋅e avec succès en tant que juré⋅e !" -#: participation/views.py:883 +#: participation/views.py:921 #, python-brace-format msgid "The jury {name} has been successfully removed!" msgstr "{name} a été retiré⋅e avec succès du jury !" -#: participation/views.py:906 +#: participation/views.py:947 #, python-brace-format msgid "The jury {name} has been successfully promoted president!" msgstr "{name} a été nommé⋅e président⋅e du jury !" -#: participation/views.py:934 +#: participation/views.py:975 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:948 +#: participation/views.py:989 msgid "Notes were successfully uploaded." msgstr "Les notes ont bien été envoyées." -#: participation/views.py:1612 +#: participation/views.py:1672 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." diff --git a/participation/templates/participation/tournament_detail.html b/participation/templates/participation/tournament_detail.html index 0a9b075..e29f47c 100644 --- a/participation/templates/participation/tournament_detail.html +++ b/participation/templates/participation/tournament_detail.html @@ -111,6 +111,26 @@ {% endfor %} + {% if not available_notes_1 or not available_notes_2 %} + {% if user.registration.is_admin or user.registration in tournament.organizers.all %} + + {% endif %} + {% endif %} {% endif %} diff --git a/participation/urls.py b/participation/urls.py index 1ddbb0e..8a37dbb 100644 --- a/participation/urls.py +++ b/participation/urls.py @@ -10,7 +10,8 @@ from .views import CreateTeamView, FinalNotationSheetTemplateView, JoinTeamView, PoolPresideJuryView, PoolRemoveJuryView, PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, \ ScaleNotationSheetTemplateView, SolutionUploadView, SynthesisUploadView, TeamAuthorizationsView, TeamDetailView, \ TeamLeaveView, TeamListView, TeamUpdateView, TeamUploadMotivationLetterView, TournamentCreateView, \ - TournamentDetailView, TournamentExportCSVView, TournamentListView, TournamentPaymentsView, TournamentUpdateView + TournamentDetailView, TournamentExportCSVView, TournamentListView, TournamentPaymentsView, \ + TournamentPublishNotesView, TournamentUpdateView app_name = "participation" @@ -35,6 +36,8 @@ urlpatterns = [ path("tournament//update/", TournamentUpdateView.as_view(), name="tournament_update"), path("tournament//payments/", TournamentPaymentsView.as_view(), name="tournament_payments"), path("tournament//csv/", TournamentExportCSVView.as_view(), name="tournament_csv"), + path("tournament//publish-notes//", TournamentPublishNotesView.as_view(), + name="tournament_publish_notes"), path("pools/create/", PoolCreateView.as_view(), name="pool_create"), path("pools//", PoolDetailView.as_view(), name="pool_detail"), path("pools//update/", PoolUpdateView.as_view(), name="pool_update"), diff --git a/participation/views.py b/participation/views.py index aa54845..949ebfe 100644 --- a/participation/views.py +++ b/participation/views.py @@ -26,6 +26,7 @@ from django.utils import timezone from django.utils.crypto import get_random_string from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView, DetailView, FormView, RedirectView, TemplateView, UpdateView, View +from django.views.generic.detail import SingleObjectMixin from django.views.generic.edit import FormMixin, ProcessFormView from django_tables2 import MultiTableMixin, SingleTableMixin, SingleTableView from magic import Magic @@ -543,13 +544,6 @@ class TournamentDetailView(MultiTableMixin, DetailView): """ model = Tournament - def dispatch(self, request, *args, **kwargs): - self.tables = [ - ParticipationTable(self.get_object().participations.all()), - PoolTable(self.get_object().pools.order_by('id').all()), - ] - return super().dispatch(request, *args, **kwargs) - def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) tables = context['tables'] @@ -565,9 +559,17 @@ class TournamentDetailView(MultiTableMixin, DetailView): if note: notes[participation] = note context["notes"] = sorted(notes.items(), key=lambda x: x[1], reverse=True) + context["available_notes_1"] = all(pool.results_available for pool in self.object.pools.filter(round=1).all()) + context["available_notes_2"] = all(pool.results_available for pool in self.object.pools.filter(round=2).all()) return context + def get_tables(self): + return [ + ParticipationTable(self.object.participations.all()), + PoolTable(self.object.pools.order_by('id').all()), + ] + class TournamentPaymentsView(VolunteerMixin, SingleTableMixin, DetailView): """ @@ -631,6 +633,34 @@ class TournamentExportCSVView(VolunteerMixin, DetailView): return resp +class TournamentPublishNotesView(VolunteerMixin, SingleObjectMixin, RedirectView): + """ + Publish notes of a tournament for a given round. + """ + model = Tournament + + def dispatch(self, request, *args, **kwargs): + if not request.user.is_authenticated: + return self.handle_no_permission() + tournament = self.get_object() + reg = request.user.registration + if not reg.is_admin and (not reg.is_volunteer or tournament not in reg.organized_tournaments.all()): + return self.handle_no_permission() + return super().dispatch(request, *args, **kwargs) + + def get(self, request, *args, **kwargs): + if int(kwargs["round"]) not in (1, 2): + raise Http404 + + tournament = Tournament.objects.get(pk=kwargs["pk"]) + tournament.pools.filter(round=kwargs["round"]).update(results_available=True) + messages.success(request, _("Notes published!")) + return super().get(request, *args, **kwargs) + + def get_redirect_url(self, *args, **kwargs): + return reverse_lazy("participation:tournament_detail", args=(kwargs['pk'],)) + + class SolutionUploadView(LoginRequiredMixin, FormView): template_name = "participation/upload_solution.html" form_class = SolutionForm