From 81c2df7f1041719af7953bf2ee72b6b08f84f501 Mon Sep 17 00:00:00 2001 From: Emmy D'Anello Date: Sat, 23 Mar 2024 11:23:02 +0100 Subject: [PATCH] Restructure add juree page Signed-off-by: Emmy D'Anello --- locale/fr/LC_MESSAGES/django.po | 226 ++++++++---------- participation/forms.py | 16 +- .../participation/pool_add_jurys.html | 47 ---- .../templates/participation/pool_detail.html | 2 +- .../templates/participation/pool_jury.html | 47 ++++ participation/urls.py | 13 +- participation/views.py | 106 +++++--- 7 files changed, 239 insertions(+), 218 deletions(-) delete mode 100644 participation/templates/participation/pool_add_jurys.html create mode 100644 participation/templates/participation/pool_jury.html diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index c0a204b..2772d0c 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-03 15:15+0100\n" +"POT-Creation-Date: 2024-03-23 11:22+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Emmy D'Anello \n" "Language-Team: LANGUAGE \n" @@ -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:154 participation/views.py:440 -#: participation/views.py:471 +#: draw/views.py:31 participation/views.py:155 participation/views.py:441 +#: participation/views.py:472 msgid "You are not in a team." msgstr "Vous n'êtes pas dans une équipe." @@ -474,76 +474,67 @@ msgstr "rapporteur⋅e" msgid "problem" msgstr "numéro de problème" -#: participation/forms.py:32 +#: participation/forms.py:31 msgid "This name is already used." msgstr "Ce nom est déjà utilisé." -#: participation/forms.py:39 participation/models.py:39 +#: participation/forms.py:38 participation/models.py:39 msgid "The trigram must be composed of three uppercase letters." msgstr "Le trigramme doit être composé de trois lettres majuscules." -#: participation/forms.py:42 +#: participation/forms.py:41 msgid "This trigram is already used." msgstr "Ce trigramme est déjà utilisé." -#: participation/forms.py:57 +#: participation/forms.py:56 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:86 participation/forms.py:351 +#: participation/forms.py:85 participation/forms.py:352 #: registration/forms.py:122 registration/forms.py:144 #: registration/forms.py:166 registration/forms.py:188 #: registration/forms.py:237 registration/forms.py:270 msgid "The uploaded file size must be under 2 Mo." msgstr "Le fichier envoyé doit peser moins de 2 Mo." -#: participation/forms.py:88 registration/forms.py:124 +#: participation/forms.py:87 registration/forms.py:124 #: registration/forms.py:146 registration/forms.py:168 #: registration/forms.py:190 registration/forms.py:239 #: registration/forms.py:272 msgid "The uploaded file must be a PDF, PNG of JPEG file." msgstr "Le fichier envoyé doit être au format PDF, PNG ou JPEG." -#: participation/forms.py:106 +#: participation/forms.py:105 msgid "I engage myself to participate to the whole TFJM²." msgstr "Je m'engage à participer à l'intégralité du TFJM²." -#: participation/forms.py:121 +#: participation/forms.py:120 msgid "Message to address to the team:" msgstr "Message à adresser à l'équipe :" -#: participation/forms.py:156 +#: participation/forms.py:155 msgid "The uploaded file size must be under 5 Mo." msgstr "Le fichier envoyé doit peser moins de 5 Mo." -#: participation/forms.py:158 participation/forms.py:353 +#: participation/forms.py:157 participation/forms.py:354 msgid "The uploaded file must be a PDF file." msgstr "Le fichier envoyé doit être au format PDF." -#: participation/forms.py:162 +#: participation/forms.py:161 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:212 -msgid "Add new jury" -msgstr "Ajouter un⋅e nouvelleau juré⋅e" - -#: participation/forms.py:227 +#: participation/forms.py:228 #: participation/templates/participation/pool_detail.html:123 #: participation/templates/participation/tournament_detail.html:119 msgid "Add" msgstr "Ajouter" -#: participation/forms.py:240 registration/forms.py:35 registration/forms.py:60 -#: registration/forms.py:91 -msgid "This email address is already used." -msgstr "Cette adresse e-mail est déjà utilisée." - -#: participation/forms.py:250 +#: participation/forms.py:251 msgid "CSV file:" msgstr "Tableur au format CSV :" -#: participation/forms.py:274 +#: participation/forms.py:275 msgid "" "This file contains non-UTF-8 and non-ISO-8859-1 content. Please send your " "sheet as a CSV file." @@ -551,30 +542,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:289 +#: participation/forms.py:290 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:309 +#: participation/forms.py:310 msgid "The following note is higher of the maximum expected value:" msgstr "La note suivante est supérieure au maximum attendu :" -#: participation/forms.py:317 +#: participation/forms.py:318 msgid "The following user was not found:" msgstr "L'utilisateur⋅rice suivant n'a pas été trouvé :" -#: participation/forms.py:334 +#: participation/forms.py:335 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:338 +#: participation/forms.py:339 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:357 +#: participation/forms.py:358 msgid "The PDF file must not have more than 2 pages." msgstr "Le fichier PDF ne doit pas avoir plus de 2 pages." @@ -1091,7 +1082,6 @@ msgstr "Rejoindre" #: participation/templates/participation/passage_detail.html:54 #: 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:110 #: participation/templates/participation/pool_detail.html:128 #: participation/templates/participation/pool_detail.html:133 @@ -1281,37 +1271,6 @@ msgstr "Points de l'équipe observatrice :" msgid "Update passage" msgstr "Modifier le passage" -#: participation/templates/participation/pool_add_jurys.html:9 -msgid "You can here register juries for the pool." -msgstr "Vous pouvez inscrire ici les juré⋅es de la poule." - -#: participation/templates/participation/pool_add_jurys.html:10 -msgid "" -"Be careful: this form register new users. To add existing users into the " -"jury, please use this form:" -msgstr "" -"Attention : ce formulaire inscrit des nouvelleaux utilisateur⋅rices. Pour " -"ajouter des utilisateur⋅rices au jury, utilisez ce formulaire :" - -#: participation/templates/participation/pool_add_jurys.html:11 -#: participation/templates/participation/pool_add_jurys.html:34 -#: participation/templates/participation/pool_detail.html:127 -#: participation/templates/participation/pool_form.html:11 -msgid "Update pool" -msgstr "Modifier la poule" - -#: participation/templates/participation/pool_add_jurys.html:14 -msgid "For now, the registered juries for the tournament are:" -msgstr "Pour l'instant, les juré⋅es inscrit⋅es au tournoi sont :" - -#: participation/templates/participation/pool_add_jurys.html:19 -msgid "There is no jury yet." -msgstr "Il n'y a pas de juré⋅e pour le moment." - -#: participation/templates/participation/pool_add_jurys.html:30 -msgid "Back to pool detail" -msgstr "Retour aux détails de la poule" - #: participation/templates/participation/pool_detail.html:15 msgid "Round:" msgstr "Tour :" @@ -1376,10 +1335,19 @@ msgstr "Modifier les équipes" msgid "Passages" msgstr "Passages" +#: participation/templates/participation/pool_detail.html:127 +#: participation/templates/participation/pool_form.html:11 +msgid "Update pool" +msgstr "Modifier la poule" + #: participation/templates/participation/pool_detail.html:137 msgid "Upload notes" msgstr "Envoyer les notes" +#: participation/templates/participation/pool_jury.html:35 +msgid "Back to pool detail" +msgstr "Retour aux détails de la poule" + #: participation/templates/participation/team_detail.html:13 msgid "Name:" msgstr "Nom :" @@ -1468,7 +1436,7 @@ msgstr "groupé" #: participation/templates/participation/team_detail.html:140 #: registration/templates/registration/user_detail.html:163 -#: registration/views.py:460 +#: registration/views.py:464 msgid "Update payment" msgstr "Mettre à jour le paiement" @@ -1527,7 +1495,7 @@ msgid "Invalidate" msgstr "Invalider" #: participation/templates/participation/team_detail.html:209 -#: participation/views.py:325 +#: participation/views.py:326 msgid "Upload motivation letter" msgstr "Envoyer la lettre de motivation" @@ -1536,7 +1504,7 @@ msgid "Update team" msgstr "Modifier l'équipe" #: participation/templates/participation/team_detail.html:219 -#: participation/views.py:434 +#: participation/views.py:435 msgid "Leave team" msgstr "Quitter l'équipe" @@ -1663,44 +1631,44 @@ msgstr "Modèles :" msgid "Warning: non-free format" msgstr "Attention : format non libre" -#: participation/views.py:54 tfjm/templates/base.html:79 +#: participation/views.py:55 tfjm/templates/base.html:79 #: tfjm/templates/navbar.html:35 msgid "Create team" msgstr "Créer une équipe" -#: participation/views.py:63 participation/views.py:104 +#: participation/views.py:64 participation/views.py:105 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:65 participation/views.py:106 +#: participation/views.py:66 participation/views.py:107 msgid "You are already in a team." msgstr "Vous êtes déjà dans une équipe." -#: participation/views.py:95 tfjm/templates/base.html:74 +#: participation/views.py:96 tfjm/templates/base.html:74 #: tfjm/templates/navbar.html:40 msgid "Join team" msgstr "Rejoindre une équipe" -#: participation/views.py:155 participation/views.py:472 +#: participation/views.py:156 participation/views.py:473 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:181 +#: participation/views.py:182 #, python-brace-format msgid "Detail of team {trigram}" msgstr "Détails de l'équipe {trigram}" -#: participation/views.py:210 +#: participation/views.py:211 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:213 +#: participation/views.py:214 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:216 +#: participation/views.py:217 msgid "" "The team can't be validated: missing email address confirmations, " "authorizations, people, motivation letter or the tournament is not set." @@ -1709,108 +1677,117 @@ 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:238 +#: participation/views.py:239 msgid "You are not an organizer of the tournament." msgstr "Vous n'êtes pas un⋅e organisateur⋅rice du tournoi." -#: participation/views.py:241 +#: participation/views.py:242 msgid "This team has no pending validation." msgstr "L'équipe n'a pas de validation en attente." -#: participation/views.py:268 +#: participation/views.py:269 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:303 +#: participation/views.py:304 #, python-brace-format msgid "Update team {trigram}" msgstr "Mise à jour de l'équipe {trigram}" -#: participation/views.py:364 participation/views.py:420 +#: participation/views.py:365 participation/views.py:421 #, python-brace-format msgid "Motivation letter of {team}.{ext}" msgstr "Lettre de motivation de {team}.{ext}" -#: participation/views.py:395 +#: participation/views.py:396 #, python-brace-format msgid "Photo authorization of {participant}.{ext}" msgstr "Autorisation de droit à l'image de {participant}.{ext}" -#: participation/views.py:401 +#: participation/views.py:402 #, python-brace-format msgid "Parental authorization of {participant}.{ext}" msgstr "Autorisation parentale de {participant}.{ext}" -#: participation/views.py:408 +#: participation/views.py:409 #, python-brace-format msgid "Health sheet of {participant}.{ext}" msgstr "Fiche sanitaire de {participant}.{ext}" -#: participation/views.py:414 +#: participation/views.py:415 #, python-brace-format msgid "Vaccine sheet of {participant}.{ext}" msgstr "Carnet de vaccination de {participant}.{ext}" -#: participation/views.py:424 +#: participation/views.py:425 #, python-brace-format msgid "Photo authorizations of team {trigram}.zip" msgstr "Autorisations de droit à l'image de l'équipe {trigram}.zip" -#: participation/views.py:442 +#: participation/views.py:443 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/views.py:486 +#: participation/views.py:487 msgid "The team is not validated yet." msgstr "L'équipe n'est pas encore validée." -#: participation/views.py:500 +#: participation/views.py:501 #, python-brace-format msgid "Participation of team {trigram}" msgstr "Participation de l'équipe {trigram}" -#: participation/views.py:581 +#: participation/views.py:582 #, python-brace-format msgid "Payments of {tournament}" msgstr "Paiements de {tournament}" -#: participation/views.py:661 +#: participation/views.py:663 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:769 +#: participation/views.py:771 #, 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:770 +#: participation/views.py:772 #, 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:788 +#: participation/views.py:798 #, python-brace-format -msgid "Jurys of {pool}" -msgstr "Juré⋅es de la {pool}" +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:815 +#: participation/views.py:814 +msgid "This user already exists, but is a participant." +msgstr "Cet⋅te utilisateur⋅rice existe déjà, mais en tant que participant⋅e." + +#: participation/views.py:833 msgid "New TFJM² jury account" msgstr "Nouveau compte de juré⋅e pour le TFJM²" -#: participation/views.py:828 +#: participation/views.py:850 #, 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:865 +#: participation/views.py:882 +#, 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:910 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:879 +#: participation/views.py:924 msgid "Notes were successfully uploaded." msgstr "Les notes ont bien été envoyées." -#: participation/views.py:1543 +#: participation/views.py:1588 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." @@ -1853,6 +1830,10 @@ msgstr "participant⋅e" msgid "coach" msgstr "encadrant⋅e" +#: registration/forms.py:35 registration/forms.py:60 registration/forms.py:91 +msgid "This email address is already used." +msgstr "Cette adresse e-mail est déjà utilisée." + #: registration/forms.py:228 msgid "Pending" msgstr "En attente" @@ -2610,8 +2591,9 @@ msgid "" "You must pay %(amount)s € for your participation in the team %(team)s for " "the tournament %(tournament)s. This includes the housing and the meals." msgstr "" -"Vous devez payer %(amount)s € pour votre participation dans l'équipe %(team)s " -"pour le tournoi %(tournament)s. Cela comprend l'hébergement et les repas." +"Vous devez payer %(amount)s € pour votre participation dans l'équipe " +"%(team)s pour le tournoi %(tournament)s. Cela comprend l'hébergement et les " +"repas." #: registration/templates/registration/payment_form.html:18 msgid "" @@ -3032,11 +3014,11 @@ msgstr "Détails de l'utilisateur⋅rice {user}" msgid "Update user {user}" msgstr "Mise à jour de l'utilisateur⋅rice {user}" -#: registration/views.py:482 registration/views.py:516 +#: registration/views.py:486 registration/views.py:520 msgid "This payment is already valid or pending validation." msgstr "Le paiement est déjà validé ou en attente de validation." -#: registration/views.py:508 +#: registration/views.py:512 msgid "" "Since one payment is already validated, or pending validation, grouping is " "not possible." @@ -3044,34 +3026,34 @@ msgstr "" "Puisque un paiement est déjà validé, ou en attente de validation, le " "regroupement n'est pas possible." -#: registration/views.py:583 +#: registration/views.py:587 msgid "The payment is already valid or pending validation." msgstr "Le paiement est déjà validé ou en attente de validation." -#: registration/views.py:597 +#: registration/views.py:601 msgid "The payment is not found or is already validated." msgstr "Le paiement n'est pas trouvé ou déjà validé." -#: registration/views.py:616 +#: registration/views.py:620 #, python-brace-format msgid "An error occurred during the payment: {error}" msgstr "Une erreur est survenue lors du paiement : {error}" -#: registration/views.py:622 +#: registration/views.py:626 msgid "The payment has been refused." msgstr "Le paiement a été refusé." -#: registration/views.py:625 +#: registration/views.py:629 #, python-brace-format msgid "The return code is unknown: {code}" msgstr "Le code de retour est inconnu : {code}" -#: registration/views.py:628 +#: registration/views.py:632 #, python-brace-format msgid "The return type is unknown: {type}" msgstr "Le type de retour est inconnu : {type}" -#: registration/views.py:637 +#: registration/views.py:641 msgid "" "The payment has been successfully validated! Your registration is now " "complete." @@ -3079,7 +3061,7 @@ msgstr "" "Le paiement a été validé avec succès ! Votre inscription est désormais " "complète." -#: registration/views.py:644 +#: registration/views.py:648 msgid "" "Your payment is done! The validation of your payment may takes a few " "minutes, and will be automatically done. If it is not the case, please " @@ -3089,27 +3071,27 @@ msgstr "" "quelques minutes, et sera faite automatiquement. Si ce n'est pas le cas, " "merci de nous contacter." -#: registration/views.py:675 +#: registration/views.py:679 #, python-brace-format msgid "Photo authorization of {student}.{ext}" msgstr "Autorisation de droit à l'image de {student}.{ext}" -#: registration/views.py:699 +#: registration/views.py:703 #, python-brace-format msgid "Health sheet of {student}.{ext}" msgstr "Fiche sanitaire de {student}.{ext}" -#: registration/views.py:723 +#: registration/views.py:727 #, python-brace-format msgid "Vaccine sheet of {student}.{ext}" msgstr "Carnet de vaccination de {student}.{ext}" -#: registration/views.py:747 +#: registration/views.py:751 #, python-brace-format msgid "Parental authorization of {student}.{ext}" msgstr "Autorisation parentale de {student}.{ext}" -#: registration/views.py:771 +#: registration/views.py:775 #, python-brace-format msgid "Payment receipt of {registrations}.{ext}" msgstr "Justificatif de paiement de {registrations}.{ext}" @@ -3275,11 +3257,3 @@ msgstr "Aucun résultat." #: tfjm/templates/sidebar.html:10 tfjm/templates/sidebar.html:21 msgid "Informations" msgstr "Informations" - -#, python-format -#~ msgid "" -#~ "We successfully received the payment of %(amount)s € for the TFJM² " -#~ "registration in the team %(team)s!" -#~ msgstr "" -#~ "Nous avons bien reçu le paiement de %(amount)s € pour l'inscription au " -#~ "TFJM² dans l'équipe %(team)s !" diff --git a/participation/forms.py b/participation/forms.py index 39593b0..0719fcc 100644 --- a/participation/forms.py +++ b/participation/forms.py @@ -6,9 +6,8 @@ from io import StringIO import re from typing import Iterable -from crispy_forms.bootstrap import InlineField from crispy_forms.helper import FormHelper -from crispy_forms.layout import Div, Fieldset, Submit +from crispy_forms.layout import Div, Submit, Field from django import forms from django.contrib.auth.models import User from django.core.exceptions import ValidationError @@ -206,25 +205,28 @@ class PoolTeamsForm(forms.ModelForm): class AddJuryForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.fields['first_name'].required = True + self.fields['last_name'].required = True + self.fields['email'].required = True self.helper = FormHelper() self.helper.form_class = 'form-inline' self.helper.layout = Div( Div( Div( - InlineField('first_name', autofocus="autofocus"), + Field('first_name', autofocus="autofocus"), css_class='col-md-3', ), Div( - InlineField('last_name'), + Field('last_name'), css_class='col-md-3', ), Div( - InlineField('email'), + Field('email'), css_class='col-md-5', ), Div( Submit('submit', _("Add")), - css_class='col-md-1', + css_class='col-md-1 py-md-4', ), css_class='row', ) @@ -236,7 +238,7 @@ class AddJuryForm(forms.ModelForm): """ email = self.data["email"] if User.objects.filter(email=email).exists(): - self.add_error("email", _("This email address is already used.")) + self.instance = User.objects.get(email=email) return email class Meta: diff --git a/participation/templates/participation/pool_add_jurys.html b/participation/templates/participation/pool_add_jurys.html deleted file mode 100644 index 9b1259c..0000000 --- a/participation/templates/participation/pool_add_jurys.html +++ /dev/null @@ -1,47 +0,0 @@ -{% extends "base.html" %} - -{% load crispy_forms_tags %} -{% load i18n %} - -{% block content %} -
-

- {% trans "You can here register juries for the pool." %} - {% trans "Be careful: this form register new users. To add existing users into the jury, please use this form:" %} - -

-

- {% trans "For now, the registered juries for the tournament are:" %} -

    - {% for jury in pool.juries.all %} -
  • {{ jury.user.first_name }} {{ jury.user.last_name }} ({{ jury.user.email }})
  • - {% empty %} -
  • {% trans "There is no jury yet." %}
  • - {% endfor %} -
-

-
- {% crispy form %} - -
- - - - {% trans "Update pool" as modal_title %} - {% trans "Update" as modal_button %} - {% url "participation:pool_update" pk=pool.pk as modal_action %} - {% include "base_modal.html" with modal_id="updatePool" %} -{% endblock %} - -{% block extrajavascript %} - -{% endblock %} - diff --git a/participation/templates/participation/pool_detail.html b/participation/templates/participation/pool_detail.html index 9c7307f..e4c0bc8 100644 --- a/participation/templates/participation/pool_detail.html +++ b/participation/templates/participation/pool_detail.html @@ -28,7 +28,7 @@
{% trans "Juries:" %}
{{ pool.juries.all|join:", " }} - + {% trans "Add jurys" %}
diff --git a/participation/templates/participation/pool_jury.html b/participation/templates/participation/pool_jury.html new file mode 100644 index 0000000..ba69137 --- /dev/null +++ b/participation/templates/participation/pool_jury.html @@ -0,0 +1,47 @@ +{% extends "base.html" %} + +{% load crispy_forms_tags crispy_forms_filters %} +{% load i18n %} + +{% block content %} +
+ + {% for jury in pool.juries.all %} +
+
+ +
+
+ +
+
+ +
+ +
+ {% endfor %} + + {{ form|as_crispy_errors }} + {% crispy form %} + +
+ + +{% endblock %} + +{% block extrajavascript %} + +{% endblock %} + diff --git a/participation/urls.py b/participation/urls.py index e344c2c..959b2f9 100644 --- a/participation/urls.py +++ b/participation/urls.py @@ -6,11 +6,11 @@ from django.views.generic import TemplateView from .views import CreateTeamView, FinalNotationSheetTemplateView, JoinTeamView, MyParticipationDetailView, \ MyTeamDetailView, NoteUpdateView, ParticipationDetailView, PassageCreateView, PassageDetailView, \ - PassageUpdateView, PoolAddJurysView, PoolCreateView, PoolDetailView, PoolDownloadView, PoolNotesTemplateView, \ - PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, ScaleNotationSheetTemplateView, SolutionUploadView, \ - SynthesisUploadView, TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \ - TeamUploadMotivationLetterView, TournamentCreateView, TournamentDetailView, TournamentExportCSVView, \ - TournamentListView, TournamentPaymentsView, TournamentUpdateView + PassageUpdateView, PoolCreateView, PoolDetailView, PoolDownloadView, PoolJuryView, PoolNotesTemplateView, \ + PoolRemoveJuryView, PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, ScaleNotationSheetTemplateView, \ + SolutionUploadView, SynthesisUploadView, TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, \ + TeamUpdateView, TeamUploadMotivationLetterView, TournamentCreateView, TournamentDetailView, \ + TournamentExportCSVView, TournamentListView, TournamentPaymentsView, TournamentUpdateView app_name = "participation" @@ -43,7 +43,8 @@ urlpatterns = [ path("pools//notation/scale/", ScaleNotationSheetTemplateView.as_view(), name="pool_scale_note_sheet"), path("pools//notation/final/", FinalNotationSheetTemplateView.as_view(), name="pool_final_note_sheet"), path("pools//update-teams/", PoolUpdateTeamsView.as_view(), name="pool_update_teams"), - path("pools//add-jurys/", PoolAddJurysView.as_view(), name="pool_add_jurys"), + path("pools//jury/", PoolJuryView.as_view(), name="pool_jury"), + path("pools//jury/remove//", PoolRemoveJuryView.as_view(), name="pool_remove_jury"), path("pools//upload-notes/", PoolUploadNotesView.as_view(), name="pool_upload_notes"), path("pools//upload-notes/template/", PoolNotesTemplateView.as_view(), name="pool_notes_template"), path("pools/passages/add//", PassageCreateView.as_view(), name="passage_create"), diff --git a/participation/views.py b/participation/views.py index fc555cf..bfa2d90 100644 --- a/participation/views.py +++ b/participation/views.py @@ -12,6 +12,7 @@ from zipfile import ZipFile from django.conf import settings from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin +from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.core.exceptions import PermissionDenied from django.core.mail import send_mail @@ -776,55 +777,75 @@ class PoolDownloadView(VolunteerMixin, DetailView): return response -class PoolAddJurysView(VolunteerMixin, FormView, DetailView): +class PoolJuryView(VolunteerMixin, FormView, DetailView): """ This view lets organizers set jurys for a pool, without multiplying clicks. """ model = Pool form_class = AddJuryForm - template_name = 'participation/pool_add_jurys.html' + template_name = 'participation/pool_jury.html' + + 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(): + return super().dispatch(request, *args, **kwargs) + return self.handle_no_permission() def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['title'] = _("Jurys of {pool}").format(pool=self.object) + context['title'] = _("Jury of pool {pool} for {tournament} with teams {teams}") \ + .format(pool=f"{self.object.get_letter_display()}{self.object.round}", + tournament=self.object.tournament.name, + teams=", ".join(participation.team.trigram for participation in self.object.participations.all())) return context @transaction.atomic def form_valid(self, form): self.object = self.get_object() - # Save the user object first - form.save() user = form.instance - # Create associated registration object to the new user - reg = VolunteerRegistration.objects.create( - user=user, - professional_activity="Juré⋅e du tournoi " + self.object.tournament.name, - ) + if user.id: + # The user already exists, so we don't recreate it + user.refresh_from_db() + reg = user.registration + if reg.participates: + form.add_error(None, _("This user already exists, but is a participant.")) + return self.form_invalid(form) + else: + # Save the user object first + form.save() + # Create associated registration object to the new user + reg = VolunteerRegistration.objects.create( + user=user, + professional_activity="Juré⋅e du tournoi " + self.object.tournament.name, + ) + + reg.send_email_validation_link() + + # Generate new password for the user + password = get_random_string(16) + user.set_password(password) + user.save() + + # Send welcome mail + subject = "[TFJM²] " + str(_("New TFJM² jury account")) + site = Site.objects.first() + message = render_to_string('registration/mails/add_organizer.txt', dict(user=user, + inviter=self.request.user, + password=password, + domain=site.domain)) + html = render_to_string('registration/mails/add_organizer.html', dict(user=user, + inviter=self.request.user, + password=password, + domain=site.domain)) + user.email_user(subject, message, html_message=html) + # Add the user in the jury self.object.juries.add(reg) self.object.save() - reg.send_email_validation_link() - - # Generate new password for the user - password = get_random_string(16) - user.set_password(password) - user.save() - - # Send welcome mail - subject = "[TFJM²] " + str(_("New TFJM² jury account")) - site = Site.objects.first() - message = render_to_string('registration/mails/add_organizer.txt', dict(user=user, - inviter=self.request.user, - password=password, - domain=site.domain)) - html = render_to_string('registration/mails/add_organizer.html', dict(user=user, - inviter=self.request.user, - password=password, - domain=site.domain)) - user.email_user(subject, message, html_message=html) - # Add notification messages.success(self.request, _("The jury {name} has been successfully added!") .format(name=f"{user.first_name} {user.last_name}")) @@ -837,7 +858,30 @@ class PoolAddJurysView(VolunteerMixin, FormView, DetailView): return super().form_invalid(form) def get_success_url(self): - return reverse_lazy('participation:pool_add_jurys', args=(self.kwargs['pk'],)) + return reverse_lazy('participation:pool_jury', args=(self.kwargs['pk'],)) + + +class PoolRemoveJuryView(VolunteerMixin, DetailView): + 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(): + return super().dispatch(request, *args, **kwargs) + return self.handle_no_permission() + + def get(self, request, *args, **kwargs): + pool = self.get_object() + if not pool.juries.filter(pk=kwargs['jury_id']).exists(): + raise Http404 + jury = pool.juries.get(pk=kwargs['jury_id']) + pool.juries.remove(jury) + pool.save() + messages.success(request, _("The jury {name} has been successfully removed!") + .format(name=f"{jury.user.first_name} {jury.user.last_name}")) + return redirect(reverse_lazy('participation:pool_jury', args=(pool.pk,))) class PoolUploadNotesView(VolunteerMixin, FormView, DetailView):