1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2025-02-24 20:21:19 +00:00

Compare commits

..

No commits in common. "1dd9a5cf9474a5b5df9f0b2986552c39ea7f5eb0" and "12d25b64fecf3da7d5e11b7bb04510d3e56f330f" have entirely different histories.

13 changed files with 231 additions and 376 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-23 23:02+0100\n" "POT-Creation-Date: 2024-03-03 15:15+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"
@ -377,8 +377,8 @@ msgstr "Êtes-vous sûr·e de vouloir annuler le tirage au sort ?"
msgid "Close" msgid "Close"
msgstr "Fermer" msgstr "Fermer"
#: draw/views.py:31 participation/views.py:155 participation/views.py:441 #: draw/views.py:31 participation/views.py:154 participation/views.py:440
#: participation/views.py:472 #: participation/views.py:471
msgid "You are not in a team." msgid "You are not in a team."
msgstr "Vous n'êtes pas dans une équipe." msgstr "Vous n'êtes pas dans une équipe."
@ -474,71 +474,76 @@ msgstr "rapporteur⋅e"
msgid "problem" msgid "problem"
msgstr "numéro de problème" msgstr "numéro de problème"
#: participation/forms.py:31 #: participation/forms.py:32
msgid "This name is already used." msgid "This name is already used."
msgstr "Ce nom est déjà utilisé." msgstr "Ce nom est déjà utilisé."
#: participation/forms.py:38 participation/models.py:39 #: participation/forms.py:39 participation/models.py:39
msgid "The trigram must be composed of three uppercase letters." msgid "The trigram must be composed of three uppercase letters."
msgstr "Le trigramme doit être composé de trois lettres majuscules." msgstr "Le trigramme doit être composé de trois lettres majuscules."
#: participation/forms.py:41 #: participation/forms.py:42
msgid "This trigram is already used." msgid "This trigram is already used."
msgstr "Ce trigramme est déjà utilisé." msgstr "Ce trigramme est déjà utilisé."
#: participation/forms.py:56 #: participation/forms.py:57
msgid "No team was found with this access code." msgid "No team was found with this access code."
msgstr "Aucune équipe n'a été trouvée avec ce code d'accès." msgstr "Aucune équipe n'a été trouvée avec ce code d'accès."
#: participation/forms.py:85 participation/forms.py:355 #: participation/forms.py:86 participation/forms.py:351
#: registration/forms.py:122 registration/forms.py:144 #: registration/forms.py:122 registration/forms.py:144
#: registration/forms.py:166 registration/forms.py:188 #: registration/forms.py:166 registration/forms.py:188
#: registration/forms.py:237 registration/forms.py:270 #: registration/forms.py:237 registration/forms.py:270
msgid "The uploaded file size must be under 2 Mo." msgid "The uploaded file size must be under 2 Mo."
msgstr "Le fichier envoyé doit peser moins de 2 Mo." msgstr "Le fichier envoyé doit peser moins de 2 Mo."
#: participation/forms.py:87 registration/forms.py:124 #: participation/forms.py:88 registration/forms.py:124
#: registration/forms.py:146 registration/forms.py:168 #: registration/forms.py:146 registration/forms.py:168
#: registration/forms.py:190 registration/forms.py:239 #: registration/forms.py:190 registration/forms.py:239
#: registration/forms.py:272 #: registration/forms.py:272
msgid "The uploaded file must be a PDF, PNG of JPEG file." msgid "The uploaded file must be a PDF, PNG of JPEG file."
msgstr "Le fichier envoyé doit être au format PDF, PNG ou JPEG." msgstr "Le fichier envoyé doit être au format PDF, PNG ou JPEG."
#: participation/forms.py:105 #: participation/forms.py:106
msgid "I engage myself to participate to the whole TFJM²." msgid "I engage myself to participate to the whole TFJM²."
msgstr "Je m'engage à participer à l'intégralité du TFJM²." msgstr "Je m'engage à participer à l'intégralité du TFJM²."
#: participation/forms.py:120 #: participation/forms.py:121
msgid "Message to address to the team:" msgid "Message to address to the team:"
msgstr "Message à adresser à l'équipe :" msgstr "Message à adresser à l'équipe :"
#: participation/forms.py:155 #: participation/forms.py:156
msgid "The uploaded file size must be under 5 Mo." msgid "The uploaded file size must be under 5 Mo."
msgstr "Le fichier envoyé doit peser moins de 5 Mo." msgstr "Le fichier envoyé doit peser moins de 5 Mo."
#: participation/forms.py:157 participation/forms.py:357 #: participation/forms.py:158 participation/forms.py:353
msgid "The uploaded file must be a PDF file." msgid "The uploaded file must be a PDF file."
msgstr "Le fichier envoyé doit être au format PDF." msgstr "Le fichier envoyé doit être au format PDF."
#: participation/forms.py:161 #: participation/forms.py:162
msgid "The PDF file must not have more than 30 pages." 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:228 #: participation/forms.py:212
msgid "Add new jury"
msgstr "Ajouter un⋅e nouvelleau juré⋅e"
#: participation/forms.py:227
#: participation/templates/participation/pool_detail.html:123 #: participation/templates/participation/pool_detail.html:123
#: participation/templates/participation/tournament_detail.html:119 #: participation/templates/participation/tournament_detail.html:119
msgid "Add" msgid "Add"
msgstr "Ajouter" msgstr "Ajouter"
#: participation/forms.py:243 #: participation/forms.py:240 registration/forms.py:35 registration/forms.py:60
msgid "This user already exists, but is a participant." #: registration/forms.py:91
msgstr "Cet⋅te utilisateur⋅rice existe déjà, mais en tant que participant⋅e." msgid "This email address is already used."
msgstr "Cette adresse e-mail est déjà utilisée."
#: participation/forms.py:254 #: participation/forms.py:250
msgid "CSV file:" msgid "CSV file:"
msgstr "Tableur au format CSV :" msgstr "Tableur au format CSV :"
#: participation/forms.py:278 #: participation/forms.py:274
msgid "" msgid ""
"This file contains non-UTF-8 and non-ISO-8859-1 content. Please send your " "This file contains non-UTF-8 and non-ISO-8859-1 content. Please send your "
"sheet as a CSV file." "sheet as a CSV file."
@ -546,30 +551,30 @@ msgstr ""
"Ce fichier contient des éléments non-UTF-8 et non-ISO-8859-1. Merci " "Ce fichier contient des éléments non-UTF-8 et non-ISO-8859-1. Merci "
"d'envoyer votre tableur au format CSV." "d'envoyer votre tableur au format CSV."
#: participation/forms.py:293 #: participation/forms.py:289
msgid "Can't determine the pool size. Are you sure your file is correct?" msgid "Can't determine the pool size. Are you sure your file is correct?"
msgstr "" msgstr ""
"Impossible de déterminer la taille de la poule. Êtes-vous sûr⋅e que le " "Impossible de déterminer la taille de la poule. Êtes-vous sûr⋅e que le "
"fichier est correct ?" "fichier est correct ?"
#: participation/forms.py:313 #: participation/forms.py:309
msgid "The following note is higher of the maximum expected value:" msgid "The following note is higher of the maximum expected value:"
msgstr "La note suivante est supérieure au maximum attendu :" msgstr "La note suivante est supérieure au maximum attendu :"
#: participation/forms.py:321 #: participation/forms.py:317
msgid "The following user was not found:" msgid "The following user was not found:"
msgstr "L'utilisateur⋅rice suivant n'a pas été trouvé :" msgstr "L'utilisateur⋅rice suivant n'a pas été trouvé :"
#: participation/forms.py:338 #: participation/forms.py:334
msgid "The defender, the opponent and the reporter must be different." msgid "The defender, the opponent and the reporter must be different."
msgstr "" msgstr ""
"Les équipes défenseuse, opposante et rapportrice doivent être différent⋅es." "Les équipes défenseuse, opposante et rapportrice doivent être différent⋅es."
#: participation/forms.py:342 #: participation/forms.py:338
msgid "This defender did not work on this problem." msgid "This defender did not work on this problem."
msgstr "Ce⋅tte défenseur⋅se ne travaille pas sur ce problème." msgstr "Ce⋅tte défenseur⋅se ne travaille pas sur ce problème."
#: participation/forms.py:361 #: participation/forms.py:357
msgid "The PDF file must not have more than 2 pages." msgid "The PDF file must not have more than 2 pages."
msgstr "Le fichier PDF ne doit pas avoir plus de 2 pages." msgstr "Le fichier PDF ne doit pas avoir plus de 2 pages."
@ -1086,6 +1091,7 @@ msgstr "Rejoindre"
#: 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_add_jurys.html:35
#: participation/templates/participation/pool_detail.html:110 #: participation/templates/participation/pool_detail.html:110
#: participation/templates/participation/pool_detail.html:128 #: participation/templates/participation/pool_detail.html:128
#: participation/templates/participation/pool_detail.html:133 #: participation/templates/participation/pool_detail.html:133
@ -1275,6 +1281,37 @@ msgstr "Points de l'équipe observatrice :"
msgid "Update passage" msgid "Update passage"
msgstr "Modifier le 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 #: participation/templates/participation/pool_detail.html:15
msgid "Round:" msgid "Round:"
msgstr "Tour :" msgstr "Tour :"
@ -1339,19 +1376,10 @@ msgstr "Modifier les équipes"
msgid "Passages" msgid "Passages"
msgstr "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 #: participation/templates/participation/pool_detail.html:137
msgid "Upload notes" msgid "Upload notes"
msgstr "Envoyer les notes" msgstr "Envoyer les notes"
#: participation/templates/participation/pool_jury.html:44
msgid "Back to pool detail"
msgstr "Retour aux détails de la poule"
#: participation/templates/participation/team_detail.html:13 #: participation/templates/participation/team_detail.html:13
msgid "Name:" msgid "Name:"
msgstr "Nom :" msgstr "Nom :"
@ -1440,7 +1468,7 @@ msgstr "groupé"
#: participation/templates/participation/team_detail.html:140 #: participation/templates/participation/team_detail.html:140
#: registration/templates/registration/user_detail.html:163 #: registration/templates/registration/user_detail.html:163
#: registration/views.py:464 #: registration/views.py:460
msgid "Update payment" msgid "Update payment"
msgstr "Mettre à jour le paiement" msgstr "Mettre à jour le paiement"
@ -1499,7 +1527,7 @@ msgid "Invalidate"
msgstr "Invalider" msgstr "Invalider"
#: participation/templates/participation/team_detail.html:209 #: participation/templates/participation/team_detail.html:209
#: participation/views.py:326 #: participation/views.py:325
msgid "Upload motivation letter" msgid "Upload motivation letter"
msgstr "Envoyer la lettre de motivation" msgstr "Envoyer la lettre de motivation"
@ -1508,7 +1536,7 @@ msgid "Update team"
msgstr "Modifier l'équipe" msgstr "Modifier l'équipe"
#: participation/templates/participation/team_detail.html:219 #: participation/templates/participation/team_detail.html:219
#: participation/views.py:435 #: participation/views.py:434
msgid "Leave team" msgid "Leave team"
msgstr "Quitter l'équipe" msgstr "Quitter l'équipe"
@ -1635,44 +1663,44 @@ msgstr "Modèles :"
msgid "Warning: non-free format" msgid "Warning: non-free format"
msgstr "Attention : format non libre" msgstr "Attention : format non libre"
#: participation/views.py:55 tfjm/templates/base.html:79 #: participation/views.py:54 tfjm/templates/base.html:79
#: tfjm/templates/navbar.html:35 #: tfjm/templates/navbar.html:35
msgid "Create team" msgid "Create team"
msgstr "Créer une équipe" msgstr "Créer une équipe"
#: participation/views.py:64 participation/views.py:105 #: participation/views.py:63 participation/views.py:104
msgid "You don't participate, so you can't create a team." msgid "You don't participate, so you can't create a team."
msgstr "Vous ne participez pas, vous ne pouvez pas créer d'équipe." msgstr "Vous ne participez pas, vous ne pouvez pas créer d'équipe."
#: participation/views.py:66 participation/views.py:107 #: participation/views.py:65 participation/views.py:106
msgid "You are already in a team." msgid "You are already in a team."
msgstr "Vous êtes déjà dans une équipe." msgstr "Vous êtes déjà dans une équipe."
#: participation/views.py:96 tfjm/templates/base.html:74 #: participation/views.py:95 tfjm/templates/base.html:74
#: tfjm/templates/navbar.html:40 #: tfjm/templates/navbar.html:40
msgid "Join team" msgid "Join team"
msgstr "Rejoindre une équipe" msgstr "Rejoindre une équipe"
#: participation/views.py:156 participation/views.py:473 #: participation/views.py:155 participation/views.py:472
msgid "You don't participate, so you don't have any team." msgid "You don't participate, so you don't have any team."
msgstr "Vous ne participez pas, vous n'avez donc pas d'équipe." msgstr "Vous ne participez pas, vous n'avez donc pas d'équipe."
#: participation/views.py:182 #: participation/views.py:181
#, python-brace-format #, python-brace-format
msgid "Detail of team {trigram}" msgid "Detail of team {trigram}"
msgstr "Détails de l'équipe {trigram}" msgstr "Détails de l'équipe {trigram}"
#: participation/views.py:211 #: participation/views.py:210
msgid "You don't participate, so you can't request the validation of the team." msgid "You don't participate, so you can't request the validation of the team."
msgstr "" msgstr ""
"Vous ne participez pas, vous ne pouvez pas demander la validation de " "Vous ne participez pas, vous ne pouvez pas demander la validation de "
"l'équipe." "l'équipe."
#: participation/views.py:214 #: participation/views.py:213
msgid "The validation of the team is already done or pending." msgid "The validation of the team is already done or pending."
msgstr "La validation de l'équipe est déjà faite ou en cours." msgstr "La validation de l'équipe est déjà faite ou en cours."
#: participation/views.py:217 #: participation/views.py:216
msgid "" msgid ""
"The team can't be validated: missing email address confirmations, " "The team can't be validated: missing email address confirmations, "
"authorizations, people, motivation letter or the tournament is not set." "authorizations, people, motivation letter or the tournament is not set."
@ -1681,118 +1709,108 @@ msgstr ""
"d'adresse e-mail, soit une autorisation, soit des personnes, soit la lettre " "d'adresse e-mail, soit une autorisation, soit des personnes, soit la lettre "
"de motivation, soit le tournoi n'a pas été choisi." "de motivation, soit le tournoi n'a pas été choisi."
#: participation/views.py:239 #: participation/views.py:238
msgid "You are not an organizer of the tournament." msgid "You are not an organizer of the tournament."
msgstr "Vous n'êtes pas un⋅e organisateur⋅rice du tournoi." msgstr "Vous n'êtes pas un⋅e organisateur⋅rice du tournoi."
#: participation/views.py:242 #: participation/views.py:241
msgid "This team has no pending validation." msgid "This team has no pending validation."
msgstr "L'équipe n'a pas de validation en attente." msgstr "L'équipe n'a pas de validation en attente."
#: participation/views.py:269 #: participation/views.py:268
msgid "You must specify if you validate the registration or not." msgid "You must specify if you validate the registration or not."
msgstr "Vous devez spécifier si vous validez l'inscription ou non." msgstr "Vous devez spécifier si vous validez l'inscription ou non."
#: participation/views.py:304 #: participation/views.py:303
#, python-brace-format #, python-brace-format
msgid "Update team {trigram}" msgid "Update team {trigram}"
msgstr "Mise à jour de l'équipe {trigram}" msgstr "Mise à jour de l'équipe {trigram}"
#: participation/views.py:365 participation/views.py:421 #: participation/views.py:364 participation/views.py:420
#, python-brace-format #, python-brace-format
msgid "Motivation letter of {team}.{ext}" msgid "Motivation letter of {team}.{ext}"
msgstr "Lettre de motivation de {team}.{ext}" msgstr "Lettre de motivation de {team}.{ext}"
#: participation/views.py:396 #: participation/views.py:395
#, python-brace-format #, python-brace-format
msgid "Photo authorization of {participant}.{ext}" msgid "Photo authorization of {participant}.{ext}"
msgstr "Autorisation de droit à l'image de {participant}.{ext}" msgstr "Autorisation de droit à l'image de {participant}.{ext}"
#: participation/views.py:402 #: participation/views.py:401
#, python-brace-format #, python-brace-format
msgid "Parental authorization of {participant}.{ext}" msgid "Parental authorization of {participant}.{ext}"
msgstr "Autorisation parentale de {participant}.{ext}" msgstr "Autorisation parentale de {participant}.{ext}"
#: participation/views.py:409 #: participation/views.py:408
#, python-brace-format #, python-brace-format
msgid "Health sheet of {participant}.{ext}" msgid "Health sheet of {participant}.{ext}"
msgstr "Fiche sanitaire de {participant}.{ext}" msgstr "Fiche sanitaire de {participant}.{ext}"
#: participation/views.py:415 #: participation/views.py:414
#, python-brace-format #, python-brace-format
msgid "Vaccine sheet of {participant}.{ext}" msgid "Vaccine sheet of {participant}.{ext}"
msgstr "Carnet de vaccination de {participant}.{ext}" msgstr "Carnet de vaccination de {participant}.{ext}"
#: participation/views.py:425 #: participation/views.py:424
#, python-brace-format #, python-brace-format
msgid "Photo authorizations of team {trigram}.zip" msgid "Photo authorizations of team {trigram}.zip"
msgstr "Autorisations de droit à l'image de l'équipe {trigram}.zip" msgstr "Autorisations de droit à l'image de l'équipe {trigram}.zip"
#: participation/views.py:443 #: participation/views.py:442
msgid "The team is already validated or the validation is pending." msgid "The team is already validated or the validation is pending."
msgstr "La validation de l'équipe est déjà faite ou en cours." msgstr "La validation de l'équipe est déjà faite ou en cours."
#: participation/views.py:487 #: participation/views.py:486
msgid "The team is not validated yet." msgid "The team is not validated yet."
msgstr "L'équipe n'est pas encore validée." msgstr "L'équipe n'est pas encore validée."
#: participation/views.py:501 #: participation/views.py:500
#, python-brace-format #, python-brace-format
msgid "Participation of team {trigram}" msgid "Participation of team {trigram}"
msgstr "Participation de l'équipe {trigram}" msgstr "Participation de l'équipe {trigram}"
#: participation/views.py:582 #: participation/views.py:581
#, python-brace-format #, python-brace-format
msgid "Payments of {tournament}" msgid "Payments of {tournament}"
msgstr "Paiements de {tournament}" msgstr "Paiements de {tournament}"
#: participation/views.py:663 #: participation/views.py:661
msgid "You can't upload a solution after the deadline." msgid "You can't upload a solution after the deadline."
msgstr "Vous ne pouvez pas envoyer de solution après la date limite." msgstr "Vous ne pouvez pas envoyer de solution après la date limite."
#: participation/views.py:771 #: participation/views.py:769
#, python-brace-format #, python-brace-format
msgid "Solutions for pool {pool} of tournament {tournament}.zip" msgid "Solutions for pool {pool} of tournament {tournament}.zip"
msgstr "Solutions pour la poule {pool} du tournoi {tournament}.zip" msgstr "Solutions pour la poule {pool} du tournoi {tournament}.zip"
#: participation/views.py:772 #: participation/views.py:770
#, python-brace-format #, python-brace-format
msgid "Syntheses for pool {pool} of tournament {tournament}.zip" msgid "Syntheses for pool {pool} of tournament {tournament}.zip"
msgstr "Notes de synthèses pour la poule {pool} du tournoi {tournament}.zip" msgstr "Notes de synthèses pour la poule {pool} du tournoi {tournament}.zip"
#: participation/views.py:798 #: participation/views.py:788
#, python-brace-format #, python-brace-format
msgid "Jury of pool {pool} for {tournament} with teams {teams}" msgid "Jurys of {pool}"
msgstr "Jury de la poule {pool} pour {tournament} avec les équipes {teams}" msgstr "Juré⋅es de la {pool}"
#: participation/views.py:814 #: participation/views.py:815
#, python-brace-format
msgid "The jury {name} is already in the pool!"
msgstr "{name} est déjà dans la poule !"
#: participation/views.py:834
msgid "New TFJM² jury account" msgid "New TFJM² jury account"
msgstr "Nouveau compte de juré⋅e pour le TFJM²" msgstr "Nouveau compte de juré⋅e pour le TFJM²"
#: participation/views.py:851 #: participation/views.py:828
#, python-brace-format #, python-brace-format
msgid "The jury {name} has been successfully added!" msgid "The jury {name} has been successfully added!"
msgstr "{name} a été ajouté⋅e avec succès en tant que juré⋅e !" msgstr "{name} a été ajouté⋅e avec succès en tant que juré⋅e !"
#: participation/views.py:883 #: participation/views.py:865
#, 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:911
msgid "The following user is not registered as a jury:" msgid "The following user is not registered as a jury:"
msgstr "L'utilisateur⋅rice suivant n'est pas inscrit⋅e en tant que juré⋅e :" msgstr "L'utilisateur⋅rice suivant n'est pas inscrit⋅e en tant que juré⋅e :"
#: participation/views.py:925 #: participation/views.py:879
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:1589 #: participation/views.py:1543
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."
@ -1835,10 +1853,6 @@ msgstr "participant⋅e"
msgid "coach" msgid "coach"
msgstr "encadrant⋅e" 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 #: registration/forms.py:228
msgid "Pending" msgid "Pending"
msgstr "En attente" msgstr "En attente"
@ -2596,9 +2610,8 @@ msgid ""
"You must pay %(amount)s € for your participation in the team %(team)s for " "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." "the tournament %(tournament)s. This includes the housing and the meals."
msgstr "" msgstr ""
"Vous devez payer %(amount)s € pour votre participation dans l'équipe " "Vous devez payer %(amount)s € pour votre participation dans l'équipe %(team)s "
"%(team)s pour le tournoi %(tournament)s. Cela comprend l'hébergement et les " "pour le tournoi %(tournament)s. Cela comprend l'hébergement et les repas."
"repas."
#: registration/templates/registration/payment_form.html:18 #: registration/templates/registration/payment_form.html:18
msgid "" msgid ""
@ -3019,11 +3032,11 @@ msgstr "Détails de l'utilisateur⋅rice {user}"
msgid "Update user {user}" msgid "Update user {user}"
msgstr "Mise à jour de l'utilisateur⋅rice {user}" msgstr "Mise à jour de l'utilisateur⋅rice {user}"
#: registration/views.py:486 registration/views.py:520 #: registration/views.py:482 registration/views.py:516
msgid "This payment is already valid or pending validation." msgid "This payment is already valid or pending validation."
msgstr "Le paiement est déjà validé ou en attente de validation." msgstr "Le paiement est déjà validé ou en attente de validation."
#: registration/views.py:512 #: registration/views.py:508
msgid "" msgid ""
"Since one payment is already validated, or pending validation, grouping is " "Since one payment is already validated, or pending validation, grouping is "
"not possible." "not possible."
@ -3031,34 +3044,34 @@ msgstr ""
"Puisque un paiement est déjà validé, ou en attente de validation, le " "Puisque un paiement est déjà validé, ou en attente de validation, le "
"regroupement n'est pas possible." "regroupement n'est pas possible."
#: registration/views.py:587 #: registration/views.py:583
msgid "The payment is already valid or pending validation." msgid "The payment is already valid or pending validation."
msgstr "Le paiement est déjà validé ou en attente de validation." msgstr "Le paiement est déjà validé ou en attente de validation."
#: registration/views.py:601 #: registration/views.py:597
msgid "The payment is not found or is already validated." msgid "The payment is not found or is already validated."
msgstr "Le paiement n'est pas trouvé ou déjà validé." msgstr "Le paiement n'est pas trouvé ou déjà validé."
#: registration/views.py:620 #: registration/views.py:616
#, python-brace-format #, python-brace-format
msgid "An error occurred during the payment: {error}" msgid "An error occurred during the payment: {error}"
msgstr "Une erreur est survenue lors du paiement : {error}" msgstr "Une erreur est survenue lors du paiement : {error}"
#: registration/views.py:626 #: registration/views.py:622
msgid "The payment has been refused." msgid "The payment has been refused."
msgstr "Le paiement a été refusé." msgstr "Le paiement a été refusé."
#: registration/views.py:629 #: registration/views.py:625
#, python-brace-format #, python-brace-format
msgid "The return code is unknown: {code}" msgid "The return code is unknown: {code}"
msgstr "Le code de retour est inconnu : {code}" msgstr "Le code de retour est inconnu : {code}"
#: registration/views.py:632 #: registration/views.py:628
#, python-brace-format #, python-brace-format
msgid "The return type is unknown: {type}" msgid "The return type is unknown: {type}"
msgstr "Le type de retour est inconnu : {type}" msgstr "Le type de retour est inconnu : {type}"
#: registration/views.py:641 #: registration/views.py:637
msgid "" msgid ""
"The payment has been successfully validated! Your registration is now " "The payment has been successfully validated! Your registration is now "
"complete." "complete."
@ -3066,7 +3079,7 @@ msgstr ""
"Le paiement a été validé avec succès ! Votre inscription est désormais " "Le paiement a été validé avec succès ! Votre inscription est désormais "
"complète." "complète."
#: registration/views.py:648 #: registration/views.py:644
msgid "" msgid ""
"Your payment is done! The validation of your payment may takes a few " "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 " "minutes, and will be automatically done. If it is not the case, please "
@ -3076,27 +3089,27 @@ msgstr ""
"quelques minutes, et sera faite automatiquement. Si ce n'est pas le cas, " "quelques minutes, et sera faite automatiquement. Si ce n'est pas le cas, "
"merci de nous contacter." "merci de nous contacter."
#: registration/views.py:679 #: registration/views.py:675
#, python-brace-format #, python-brace-format
msgid "Photo authorization of {student}.{ext}" msgid "Photo authorization of {student}.{ext}"
msgstr "Autorisation de droit à l'image de {student}.{ext}" msgstr "Autorisation de droit à l'image de {student}.{ext}"
#: registration/views.py:703 #: registration/views.py:699
#, python-brace-format #, python-brace-format
msgid "Health sheet of {student}.{ext}" msgid "Health sheet of {student}.{ext}"
msgstr "Fiche sanitaire de {student}.{ext}" msgstr "Fiche sanitaire de {student}.{ext}"
#: registration/views.py:727 #: registration/views.py:723
#, python-brace-format #, python-brace-format
msgid "Vaccine sheet of {student}.{ext}" msgid "Vaccine sheet of {student}.{ext}"
msgstr "Carnet de vaccination de {student}.{ext}" msgstr "Carnet de vaccination de {student}.{ext}"
#: registration/views.py:751 #: registration/views.py:747
#, python-brace-format #, python-brace-format
msgid "Parental authorization of {student}.{ext}" msgid "Parental authorization of {student}.{ext}"
msgstr "Autorisation parentale de {student}.{ext}" msgstr "Autorisation parentale de {student}.{ext}"
#: registration/views.py:775 #: registration/views.py:771
#, python-brace-format #, python-brace-format
msgid "Payment receipt of {registrations}.{ext}" msgid "Payment receipt of {registrations}.{ext}"
msgstr "Justificatif de paiement de {registrations}.{ext}" msgstr "Justificatif de paiement de {registrations}.{ext}"
@ -3262,3 +3275,11 @@ msgstr "Aucun résultat."
#: tfjm/templates/sidebar.html:10 tfjm/templates/sidebar.html:21 #: tfjm/templates/sidebar.html:10 tfjm/templates/sidebar.html:21
msgid "Informations" msgid "Informations"
msgstr "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 !"

View File

@ -61,9 +61,3 @@ class TournamentSerializer(serializers.ModelSerializer):
'inscription_limit', 'solution_limit', 'solutions_draw', 'syntheses_first_phase_limit', 'inscription_limit', 'solution_limit', 'solutions_draw', 'syntheses_first_phase_limit',
'solutions_available_second_phase', 'syntheses_second_phase_limit', 'solutions_available_second_phase', 'syntheses_second_phase_limit',
'description', 'organizers', 'final', 'participations',) 'description', 'organizers', 'final', 'participations',)
class TweakSerializer(serializers.ModelSerializer):
class Meta:
model = Team
fields = '__all__'

View File

@ -2,7 +2,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from .views import NoteViewSet, ParticipationViewSet, PassageViewSet, PoolViewSet, \ from .views import NoteViewSet, ParticipationViewSet, PassageViewSet, PoolViewSet, \
SolutionViewSet, SynthesisViewSet, TeamViewSet, TournamentViewSet, TweakViewSet SolutionViewSet, SynthesisViewSet, TeamViewSet, TournamentViewSet
def register_participation_urls(router, path): def register_participation_urls(router, path):
@ -17,4 +17,3 @@ def register_participation_urls(router, path):
router.register(path + "/synthesis", SynthesisViewSet) router.register(path + "/synthesis", SynthesisViewSet)
router.register(path + "/team", TeamViewSet) router.register(path + "/team", TeamViewSet)
router.register(path + "/tournament", TournamentViewSet) router.register(path + "/tournament", TournamentViewSet)
router.register(path + "/tweak", TweakViewSet)

View File

@ -4,8 +4,8 @@ from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from .serializers import NoteSerializer, ParticipationSerializer, PassageSerializer, PoolSerializer, \ from .serializers import NoteSerializer, ParticipationSerializer, PassageSerializer, PoolSerializer, \
SolutionSerializer, SynthesisSerializer, TeamSerializer, TournamentSerializer, TweakSerializer SolutionSerializer, SynthesisSerializer, TeamSerializer, TournamentSerializer
from ..models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament, Tweak from ..models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament
class NoteViewSet(ModelViewSet): class NoteViewSet(ModelViewSet):
@ -67,11 +67,3 @@ class TournamentViewSet(ModelViewSet):
'inscription_limit', 'solution_limit', 'solutions_draw', 'syntheses_first_phase_limit', 'inscription_limit', 'solution_limit', 'solutions_draw', 'syntheses_first_phase_limit',
'solutions_available_second_phase', 'syntheses_second_phase_limit', 'solutions_available_second_phase', 'syntheses_second_phase_limit',
'description', 'organizers', 'final', ] 'description', 'organizers', 'final', ]
class TweakViewSet(ModelViewSet):
queryset = Tweak.objects.all()
serializer_class = TweakSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['pool', 'pool__tournament', 'pool__tournament__name', 'participation',
'participation__team__trigram', 'diff', ]

View File

@ -6,8 +6,9 @@ from io import StringIO
import re import re
from typing import Iterable from typing import Iterable
from crispy_forms.bootstrap import InlineField
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import Div, Submit, Field from crispy_forms.layout import Div, Fieldset, Submit
from django import forms from django import forms
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
@ -78,7 +79,7 @@ class ParticipationForm(forms.ModelForm):
class MotivationLetterForm(forms.ModelForm): class MotivationLetterForm(forms.ModelForm):
def clean_motivation_letter(self): def clean_file(self):
if "motivation_letter" in self.files: if "motivation_letter" in self.files:
file = self.files["motivation_letter"] file = self.files["motivation_letter"]
if file.size > 2e6: if file.size > 2e6:
@ -205,28 +206,26 @@ class PoolTeamsForm(forms.ModelForm):
class AddJuryForm(forms.ModelForm): class AddJuryForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*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 = FormHelper()
self.helper.form_class = 'form-inline' self.helper.form_class = 'form-inline'
self.helper.layout = Div( self.helper.layout = Fieldset(
_("Add new jury"),
Div( Div(
Div( Div(
Field('email', autofocus="autofocus", list="juries-email"), InlineField('first_name', autofocus="autofocus"),
css_class='col-md-5', css_class='col-xl-3',
), ),
Div( Div(
Field('first_name', list="juries-first-name"), InlineField('last_name'),
css_class='col-md-3', css_class='col-xl-3',
), ),
Div( Div(
Field('last_name', list="juries-last-name"), InlineField('email'),
css_class='col-md-3', css_class='col-xl-5',
), ),
Div( Div(
Submit('submit', _("Add")), Submit('submit', _("Add")),
css_class='col-md-1 py-md-4', css_class='col-xl-1',
), ),
css_class='row', css_class='row',
) )
@ -238,10 +237,7 @@ class AddJuryForm(forms.ModelForm):
""" """
email = self.data["email"] email = self.data["email"]
if User.objects.filter(email=email).exists(): if User.objects.filter(email=email).exists():
self.instance = User.objects.get(email=email) self.add_error("email", _("This email address is already used."))
if self.instance.registration.participates:
self.add_error(None, _("This user already exists, but is a participant."))
return
return email return email
class Meta: class Meta:

View File

@ -0,0 +1,47 @@
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load i18n %}
{% block content %}
<div class="alert alert-info">
<p>
{% 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:" %}
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#updatePoolModal">{% trans "Update pool" %}</button>
</p>
<p>
{% trans "For now, the registered juries for the tournament are:" %}
<ul>
{% for jury in pool.juries.all %}
<li>{{ jury.user.first_name }} {{ jury.user.last_name }} (<a class="alert-link" href="mailto:{{ jury.user.email }}">{{ jury.user.email }}</a>)</li>
{% empty %}
<li><i>{% trans "There is no jury yet." %}</i></li>
{% endfor %}
</ul>
</p>
</div>
{% crispy form %}
<hr>
<div class="row text-center">
<a href="{% url 'participation:pool_detail' pk=pool.pk %}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> {% trans "Back to pool detail" %}
</a>
</div>
{% 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 %}
<script>
document.addEventListener('DOMContentLoaded', () => {
initModal("updatePool", "{% url "participation:pool_update" pk=pool.pk %}")
})
</script>
{% endblock %}

View File

@ -28,7 +28,7 @@
<dt class="col-sm-3">{% trans "Juries:" %}</dt> <dt class="col-sm-3">{% trans "Juries:" %}</dt>
<dd class="col-sm-9"> <dd class="col-sm-9">
{{ pool.juries.all|join:", " }} {{ pool.juries.all|join:", " }}
<a class="badge rounded-pill text-bg-info" href="{% url 'participation:pool_jury' pk=pool.pk %}"> <a class="badge rounded-pill text-bg-info" href="{% url 'participation:pool_add_jurys' pk=pool.pk %}">
<i class="fas fa-plus"></i> {% trans "Add jurys" %} <i class="fas fa-plus"></i> {% trans "Add jurys" %}
</a> </a>
</dd> </dd>

View File

@ -1,108 +0,0 @@
{% extends "base.html" %}
{% load crispy_forms_tags crispy_forms_filters %}
{% load i18n %}
{% block content %}
<hr>
{% for jury in pool.juries.all %}
<div class="row my-3">
<div class="col-md-5">
<input type="email" class="form-control" value="{{ jury.user.email }}" disabled>
</div>
<div class="col-md-3">
<input type="text" class="form-control" value="{{ jury.user.first_name }}" disabled>
</div>
<div class="col-md-3">
<input type="text" class="form-control" value="{{ jury.user.last_name }}" disabled>
</div>
<div class="col-md-1">
<a href="{% url 'participation:pool_remove_jury' pk=pool.pk jury_id=jury.id %}" class="btn btn-danger">
Retirer
</a>
</div>
</div>
{% endfor %}
{{ form|as_crispy_errors }}
{% crispy form %}
<datalist id="juries-email">
</datalist>
<datalist id="juries-first-name">
</datalist>
<datalist id="juries-last-name">
</datalist>
<hr>
<div class="row text-center">
<a href="{% url 'participation:pool_detail' pk=pool.pk %}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> {% trans "Back to pool detail" %}
</a>
</div>
{% endblock %}
{% block extrajavascript %}
<script>
const emailField = document.getElementById('id_email')
const firstNameField = document.getElementById('id_first_name')
const lastNameField = document.getElementById('id_last_name')
const juriesEmailList = document.getElementById('juries-email')
const juriesFirstNameList = document.getElementById('juries-first-name')
const juriesLastNameList = document.getElementById('juries-last-name')
function updateJuries(filter) {
fetch(`/api/registration/volunteers/?search=${filter}`)
.then(response => response.json())
.then(response => response.results)
.then(data => {
juriesEmailList.innerHTML = ''
juriesFirstNameList.innerHTML = ''
juriesLastNameList.innerHTML = ''
data.forEach(jury => {
const optionEmail = document.createElement('option')
optionEmail.value = jury.email
optionEmail.setAttribute('data-id', jury.id)
juriesEmailList.appendChild(optionEmail)
const optionFirstName = document.createElement('option')
optionFirstName.value = jury.first_name
optionFirstName.setAttribute('data-id', jury.id)
juriesFirstNameList.appendChild(optionFirstName)
const optionLastName = document.createElement('option')
optionLastName.value = jury.last_name
optionLastName.setAttribute('data-id', jury.id)
juriesLastNameList.appendChild(optionLastName)
})
})
}
emailField.addEventListener('input', event => {
let emailOption = document.querySelector(`datalist[id="juries-email"] > option[value="${event.target.value}"]`)
if (emailOption) {
let id = emailOption.getAttribute('data-id')
let firstNameOption = document.querySelector(`datalist[id="juries-first-name"] > option[data-id="${id}"]`)
let lastNameOption = document.querySelector(`datalist[id="juries-last-name"] > option[data-id="${id}"]`)
if (firstNameOption && lastNameOption) {
firstNameField.value = firstNameOption.value
lastNameField.value = lastNameOption.value
}
}
updateJuries(event.target.value)
})
firstNameField.addEventListener('input', event => {
updateJuries(event.target.value)
})
lastNameField.addEventListener('input', event => {
updateJuries(event.target.value)
})
</script>
{% endblock %}

View File

@ -6,11 +6,11 @@ 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, NoteUpdateView, ParticipationDetailView, PassageCreateView, PassageDetailView, \
PassageUpdateView, PoolCreateView, PoolDetailView, PoolDownloadView, PoolJuryView, PoolNotesTemplateView, \ PassageUpdateView, PoolAddJurysView, PoolCreateView, PoolDetailView, PoolDownloadView, PoolNotesTemplateView, \
PoolRemoveJuryView, PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, ScaleNotationSheetTemplateView, \ PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, ScaleNotationSheetTemplateView, SolutionUploadView, \
SolutionUploadView, SynthesisUploadView, TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, \ SynthesisUploadView, TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \
TeamUpdateView, TeamUploadMotivationLetterView, TournamentCreateView, TournamentDetailView, \ TeamUploadMotivationLetterView, TournamentCreateView, TournamentDetailView, TournamentExportCSVView, \
TournamentExportCSVView, TournamentListView, TournamentPaymentsView, TournamentUpdateView TournamentListView, TournamentPaymentsView, TournamentUpdateView
app_name = "participation" app_name = "participation"
@ -43,8 +43,7 @@ urlpatterns = [
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: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>/add-jurys/", PoolAddJurysView.as_view(), name="pool_add_jurys"),
path("pools/<int:pk>/jury/remove/<int:jury_id>/", PoolRemoveJuryView.as_view(), name="pool_remove_jury"),
path("pools/<int:pk>/upload-notes/", PoolUploadNotesView.as_view(), name="pool_upload_notes"), path("pools/<int:pk>/upload-notes/", PoolUploadNotesView.as_view(), name="pool_upload_notes"),
path("pools/<int:pk>/upload-notes/template/", PoolNotesTemplateView.as_view(), name="pool_notes_template"), path("pools/<int:pk>/upload-notes/template/", PoolNotesTemplateView.as_view(), name="pool_notes_template"),
path("pools/passages/add/<int:pk>/", PassageCreateView.as_view(), name="passage_create"), path("pools/passages/add/<int:pk>/", PassageCreateView.as_view(), name="passage_create"),

View File

@ -12,7 +12,6 @@ from zipfile import ZipFile
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.core.mail import send_mail from django.core.mail import send_mail
@ -777,76 +776,55 @@ class PoolDownloadView(VolunteerMixin, DetailView):
return response return response
class PoolJuryView(VolunteerMixin, FormView, DetailView): class PoolAddJurysView(VolunteerMixin, FormView, DetailView):
""" """
This view lets organizers set jurys for a pool, without multiplying clicks. This view lets organizers set jurys for a pool, without multiplying clicks.
""" """
model = Pool model = Pool
form_class = AddJuryForm form_class = AddJuryForm
template_name = 'participation/pool_jury.html' template_name = 'participation/pool_add_jurys.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): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['title'] = _("Jury of pool {pool} for {tournament} with teams {teams}") \ context['title'] = _("Jurys of {pool}").format(pool=self.object)
.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 return context
@transaction.atomic @transaction.atomic
def form_valid(self, form): def form_valid(self, form):
self.object = self.get_object() self.object = self.get_object()
# Save the user object first
form.save()
user = form.instance user = form.instance
if user.id: # Create associated registration object to the new user
# The user already exists, so we don't recreate it reg = VolunteerRegistration.objects.create(
user.refresh_from_db() user=user,
reg = user.registration professional_activity="Juré⋅e du tournoi " + self.object.tournament.name,
if reg in self.object.juries.all(): )
messages.warning(self.request, _("The jury {name} is already in the pool!")
.format(name=f"{user.first_name} {user.last_name}"))
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 # Add the user in the jury
self.object.juries.add(reg) self.object.juries.add(reg)
self.object.save() 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 # Add notification
messages.success(self.request, _("The jury {name} has been successfully added!") messages.success(self.request, _("The jury {name} has been successfully added!")
.format(name=f"{user.first_name} {user.last_name}")) .format(name=f"{user.first_name} {user.last_name}"))
@ -859,30 +837,7 @@ class PoolJuryView(VolunteerMixin, FormView, DetailView):
return super().form_invalid(form) return super().form_invalid(form)
def get_success_url(self): def get_success_url(self):
return reverse_lazy('participation:pool_jury', args=(self.kwargs['pk'],)) return reverse_lazy('participation:pool_add_jurys', 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): class PoolUploadNotesView(VolunteerMixin, FormView, DetailView):

View File

@ -1,12 +1,11 @@
# Copyright (C) 2020 by Animath # Copyright (C) 2020 by Animath
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from django.contrib.auth.models import User
from rest_framework import serializers from rest_framework import serializers
from rest_polymorphic.serializers import PolymorphicSerializer from rest_polymorphic.serializers import PolymorphicSerializer
from ..models import CoachRegistration, ParticipantRegistration, \ from ..models import CoachRegistration, ParticipantRegistration, \
Payment, StudentRegistration, VolunteerRegistration StudentRegistration, VolunteerRegistration
class CoachSerializer(serializers.ModelSerializer): class CoachSerializer(serializers.ModelSerializer):
@ -39,15 +38,3 @@ class RegistrationSerializer(PolymorphicSerializer):
StudentRegistration: StudentSerializer, StudentRegistration: StudentSerializer,
VolunteerRegistration: VolunteerSerializer, VolunteerRegistration: VolunteerSerializer,
} }
class PaymentSerializer(serializers.ModelSerializer):
class Meta:
model = Payment
fields = '__all__'
class BasicUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'first_name', 'last_name', 'email', ]

View File

@ -1,13 +1,11 @@
# Copyright (C) 2020 by Animath # Copyright (C) 2020 by Animath
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from .views import PaymentViewSet, RegistrationViewSet, VolunteersViewSet from .views import RegistrationViewSet
def register_registration_urls(router, path): def register_registration_urls(router, path):
""" """
Configure router for registration REST API. Configure router for registration REST API.
""" """
router.register(path + "/payment", PaymentViewSet)
router.register(path + "/registration", RegistrationViewSet) router.register(path + "/registration", RegistrationViewSet)
router.register(path + "/volunteers", VolunteersViewSet)

View File

@ -1,14 +1,11 @@
# Copyright (C) 2020 by Animath # Copyright (C) 2020 by Animath
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from django.contrib.auth.models import User
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from .serializers import BasicUserSerializer, PaymentSerializer, RegistrationSerializer from .serializers import RegistrationSerializer
from ..models import Payment, Registration from ..models import Registration
class RegistrationViewSet(ModelViewSet): class RegistrationViewSet(ModelViewSet):
@ -16,25 +13,3 @@ class RegistrationViewSet(ModelViewSet):
serializer_class = RegistrationSerializer serializer_class = RegistrationSerializer
filter_backends = [DjangoFilterBackend] filter_backends = [DjangoFilterBackend]
filterset_fields = ['user', 'participantregistration__team', ] filterset_fields = ['user', 'participantregistration__team', ]
class PaymentViewSet(ModelViewSet):
queryset = Payment.objects.all()
serializer_class = PaymentSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['registrations', 'grouped', 'amount', 'final', 'type', 'valid', ]
class IsTournamentOrganizer(BasePermission):
def has_permission(self, request, view):
reg = request.user.registration
return request.method in SAFE_METHODS and reg.is_volunteer and reg.organized_tournaments.exists()
class VolunteersViewSet(ReadOnlyModelViewSet):
queryset = User.objects.filter(registration__volunteerregistration__isnull=False)
serializer_class = BasicUserSerializer
permission_classes = [IsAuthenticated & IsTournamentOrganizer]
filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ['first_name', 'last_name', 'email', ]
search_fields = ['$first_name', '$last_name', '$email', ]