Merge branch 'open-registrations' into 'dev'
Ouverture et fermeture des inscriptions See merge request animath/si/plateforme-tfjm!47
This commit is contained in:
commit
3015361835
|
@ -0,0 +1,194 @@
|
||||||
|
Transition d'années
|
||||||
|
===================
|
||||||
|
|
||||||
|
Entre deux sessions du TFJM², certaines opérations doivent être effectuées chaque année,
|
||||||
|
afin de réinitialiser les données et de passer à l'année suivante.
|
||||||
|
|
||||||
|
Réinitialisation de la base de données
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
Conservation des autorisations de droit à l'image
|
||||||
|
"""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
La base de données du TFJM² est supprimée chaque année, avant chaque tournoi. Il n'y a
|
||||||
|
pas de conservation de données personnelles à l'exception des autorisations de droit
|
||||||
|
à l'image qui doivent être conservées pour des raisons légales pendant 5 ans.
|
||||||
|
|
||||||
|
Elles doivent alors être stockées sur Owncloud. Pour cela, il faut commencer par créer
|
||||||
|
un dossier dans Owncloud, qui stockera lesdites autorisations.
|
||||||
|
|
||||||
|
Rendez-vous ensuite dans le conteneur Docker et exécuter le script :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
./manage.py export_photo_authorizations
|
||||||
|
|
||||||
|
Cela a pour effet de générer un dossier dans ``output/photo_authorizations``, qui contient
|
||||||
|
un dossier par équipe avec les différentes autorisations de droit à l'image.
|
||||||
|
|
||||||
|
Il faut maintenant récupérer ce dossier. Sortir du conteneur, et exécuter dans ``/srv/TFJM`` :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
sudo docker cp tfjm_plateforme_1:/code/output/photo_authorizations .
|
||||||
|
sudo mv photo_authorizations/* "data/owncloud/files/Emmy/Autorisations de droit à l'image/Autorisations de droit à l'image 2024/"
|
||||||
|
sudo chown -R www-data:root "data/owncloud/files/Emmy/Autorisations de droit à l'image/Autorisations de droit à l'image 2024"
|
||||||
|
sudo rmdir photo_authorizations
|
||||||
|
|
||||||
|
Il faut enfin réactualiser Owncloud. Exécuter en tant que www-data :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
sudo docker compose exec -u www-data cloud php occ files:scan Emmy
|
||||||
|
|
||||||
|
Vérifiez enfin que les fichiers sont bien accessibles dans l'interface Web.
|
||||||
|
Ne pas oublier enfin de partager le dossier.
|
||||||
|
|
||||||
|
|
||||||
|
Sauvegarde de secours
|
||||||
|
"""""""""""""""""""""
|
||||||
|
|
||||||
|
Si les données doivent être supprimées, il peut être utile de réaliser une sauvegarde à conserver
|
||||||
|
quelques mois.
|
||||||
|
|
||||||
|
.. danger::
|
||||||
|
|
||||||
|
Cette sauvegarde ne doit être faite qu'à des fins utiles et supprimée dès que plus nécessaire.
|
||||||
|
|
||||||
|
Sauvegardez alors le dossier ``/srv/TFJM/data/inscription/media`` et exportez la base de données :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
sudo cp -r data/inscription/media data/inscription/media-2024
|
||||||
|
sudo docker compose exec -u postgres postgres pg_dump inscription | sudo tee inscription_bkp_2024.sql
|
||||||
|
|
||||||
|
|
||||||
|
Réinitialisation effective
|
||||||
|
""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
Il est désormais possible de réinitialiser la base de données. Rendez-vous dans le conteneur de
|
||||||
|
la plateforme, et exécutez :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
rm -r media/*
|
||||||
|
./manage.py reset_db
|
||||||
|
|
||||||
|
Créez enfin un nouveau compte administrateur⋅rice :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
./manage.py createsuperuser
|
||||||
|
|
||||||
|
|
||||||
|
Nouveaux paramètres pour la nouvelle année
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
Certains paramètres doivent être modifiés pour prendre en compte la nouvelle année.
|
||||||
|
|
||||||
|
Dates d'inscription
|
||||||
|
"""""""""""""""""""
|
||||||
|
|
||||||
|
Les inscriptions sont permises uniquement entre l'ouverture et la fermeture, afin d'éviter
|
||||||
|
d'avoir des personnes s'inscrivant en dehors du TFJM².
|
||||||
|
|
||||||
|
Pour cela, dans votre projet local, rendez-vous dans ``tfjm/settings.py`` et cherchez
|
||||||
|
le paramètre ``REGISTRATION_DATES`` (pour le TFJM²). Modifiez alors les sous-paramètres
|
||||||
|
``open`` et ``close`` pour définir les dates pendant lesquelles les inscriptions des
|
||||||
|
participant⋅es sont permises pour cette nouvelle année. Elles doivent être au format ISO.
|
||||||
|
|
||||||
|
Exemple pour l'année 2025 où les inscriptions ouvrent au 8 janvier midi pour fermer
|
||||||
|
le 2 mars à 22h :
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
REGISTRATION_DATES = dict(
|
||||||
|
open=datetime.fromisoformat("2025-01-08T12:00:00+0100"),
|
||||||
|
close=datetime.fromisoformat("2025-03-02T22:00:00+0100"),
|
||||||
|
)
|
||||||
|
|
||||||
|
Il faudra ensuite commiter la modification et redémarrer le serveur pour que la modification
|
||||||
|
prenne effet.
|
||||||
|
|
||||||
|
|
||||||
|
Noms des problèmes
|
||||||
|
""""""""""""""""""
|
||||||
|
|
||||||
|
Toujours dans la configuration dans ``tfjm/settings.py``, la liste des problèmes doit être
|
||||||
|
modifiée pour que leurs noms s'affichent correctement lors du tirage au sort.
|
||||||
|
|
||||||
|
Cherchez le paramètre ``PROBLEMS`` et mettez alors à jour la liste, dans l'ordre, des noms
|
||||||
|
des problèmes.
|
||||||
|
|
||||||
|
À nouveau, il est nécessaire de commiter la modification et redémarrer le serveur.
|
||||||
|
|
||||||
|
|
||||||
|
Paramètres des tournois
|
||||||
|
"""""""""""""""""""""""
|
||||||
|
|
||||||
|
Il faut enfin paramétrer les différentes dates des tournois.
|
||||||
|
|
||||||
|
Pour cela, connectez-vous sur la plateforme (avec un compte administrateur⋅rice), et dans l'onglet
|
||||||
|
« Tournois », vous pouvez créer les différents tournois avec les différentes dates pour chaque tournoi.
|
||||||
|
Plus d'information sur les différents paramètres dans la `section concernée
|
||||||
|
<../orga.html#creer-un-tournoi>`_
|
||||||
|
|
||||||
|
|
||||||
|
À la fin du tournoi
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Lorsque le tournoi est terminé, il faut récupérer les informations à stocker de façon pérenne,
|
||||||
|
notamment les solutions des équipes, les résultats ainsi que les autorisation de droit à l'image
|
||||||
|
comme indiqué précédemment.
|
||||||
|
|
||||||
|
Conservation des autorisations de droit à l'image
|
||||||
|
"""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
Se référer à la section plus haut.
|
||||||
|
|
||||||
|
|
||||||
|
Conservation des solutions des équipes
|
||||||
|
""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
Le processus est très similaire à la conservation des autorisations de droit à l'image.
|
||||||
|
Il faut d'abord, dans le conteneur, lancer le script dédié pour récupérer les solutions
|
||||||
|
dans ``/code/output/solutions`` :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
./manage.py export_solutions
|
||||||
|
|
||||||
|
On sort du conteneur et on récupère les solutions pour les déplacer dans Owncloud :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
sudo docker cp tfjm_plateforme_1:/code/output/solutions .
|
||||||
|
sudo mv solutions/* "data/owncloud/files/Emmy/Solutions écrites 2024/"
|
||||||
|
sudo chown -R www-data:root "data/owncloud/files/Emmy/Solutions écrites 2024"
|
||||||
|
sudo rmdir solutions
|
||||||
|
|
||||||
|
Il faut enfin réactualiser Owncloud. Exécuter en tant que www-data :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
sudo docker compose exec -u www-data cloud php occ files:scan Emmy
|
||||||
|
|
||||||
|
Vérifiez enfin que les fichiers sont bien accessibles dans l'interface Web.
|
||||||
|
Ne pas oublier enfin de partager le dossier.
|
||||||
|
|
||||||
|
|
||||||
|
Génération de la page de résultats Wordpress
|
||||||
|
""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
Pour finir, il est possible de récupérer les notes pour chaque tournoi afin de générer
|
||||||
|
la page Wordpress dans la section *Éditions précédentes*.
|
||||||
|
|
||||||
|
Il suffit de lancer le script ``./manage.py export_results``, qui donne le texte brut pour
|
||||||
|
Wordpress à ajouter sur la page de l'édition qui vient de se terminer dans l'onglet
|
||||||
|
*Éditions précédentes*.
|
||||||
|
|
||||||
|
Pensez à bien inclure sur cette page le lien vers les problèmes de l'année, ainsi que le
|
||||||
|
lien vers le dossier partagé dans le Owncloud concernant les solutions des équipes.
|
||||||
|
|
||||||
|
Assurez-vous de mettre à jour la page *Éditions précédentes* afin d'inclure le lien vers
|
||||||
|
la page nouvellement créée.
|
|
@ -21,3 +21,4 @@ administrateur⋅rice.
|
||||||
|
|
||||||
dev/index
|
dev/index
|
||||||
dev/install
|
dev/install
|
||||||
|
dev/transition
|
||||||
|
|
|
@ -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-07-09 13:22+0200\n"
|
"POT-Creation-Date: 2024-10-28 20:14+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"
|
||||||
|
@ -217,7 +217,7 @@ msgstr ""
|
||||||
msgid "Toggle fullscreen mode"
|
msgid "Toggle fullscreen mode"
|
||||||
msgstr "Inverse le mode plein écran"
|
msgstr "Inverse le mode plein écran"
|
||||||
|
|
||||||
#: chat/templates/chat/content.html:76 tfjm/templates/navbar.html:125
|
#: chat/templates/chat/content.html:76 tfjm/templates/navbar.html:126
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "Déconnexion"
|
msgstr "Déconnexion"
|
||||||
|
|
||||||
|
@ -244,14 +244,14 @@ msgid "ETEAM Chat"
|
||||||
msgstr "Chat de l'ETEAM"
|
msgstr "Chat de l'ETEAM"
|
||||||
|
|
||||||
#: chat/templates/chat/login.html:10 chat/templates/chat/login.html:12
|
#: chat/templates/chat/login.html:10 chat/templates/chat/login.html:12
|
||||||
#: chat/urls.py:13 tfjm/templates/navbar.html:74
|
#: chat/urls.py:13 tfjm/templates/navbar.html:72
|
||||||
msgid "Chat"
|
msgid "Chat"
|
||||||
msgstr "Chat"
|
msgstr "Chat"
|
||||||
|
|
||||||
#: chat/templates/chat/login.html:10 chat/templates/chat/login.html:36
|
#: chat/templates/chat/login.html:10 chat/templates/chat/login.html:36
|
||||||
#: registration/templates/registration/password_reset_complete.html:10
|
#: registration/templates/registration/password_reset_complete.html:10
|
||||||
#: tfjm/templates/base.html:89 tfjm/templates/base.html:90
|
#: tfjm/templates/base.html:89 tfjm/templates/base.html:90
|
||||||
#: tfjm/templates/navbar.html:106
|
#: tfjm/templates/navbar.html:107
|
||||||
#: tfjm/templates/registration/includes/login.html:22
|
#: tfjm/templates/registration/includes/login.html:22
|
||||||
#: tfjm/templates/registration/login.html:7
|
#: tfjm/templates/registration/login.html:7
|
||||||
#: tfjm/templates/registration/login.html:8
|
#: tfjm/templates/registration/login.html:8
|
||||||
|
@ -269,7 +269,7 @@ msgstr "équipes"
|
||||||
msgid "round"
|
msgid "round"
|
||||||
msgstr "tour"
|
msgstr "tour"
|
||||||
|
|
||||||
#: draw/apps.py:10 draw/consumers.py:1042 tfjm/templates/navbar.html:68
|
#: draw/apps.py:10 draw/consumers.py:1042 tfjm/templates/navbar.html:66
|
||||||
msgid "Draw"
|
msgid "Draw"
|
||||||
msgstr "Tirage au sort"
|
msgstr "Tirage au sort"
|
||||||
|
|
||||||
|
@ -311,7 +311,7 @@ msgstr "Le tirage au sort du tournoi {tournament} va commencer."
|
||||||
|
|
||||||
#: draw/consumers.py:256 draw/consumers.py:282 draw/consumers.py:692
|
#: draw/consumers.py:256 draw/consumers.py:282 draw/consumers.py:692
|
||||||
#: draw/consumers.py:910 draw/consumers.py:1000 draw/consumers.py:1022
|
#: draw/consumers.py:910 draw/consumers.py:1000 draw/consumers.py:1022
|
||||||
#: draw/consumers.py:1125 draw/templates/draw/tournament_content.html:5
|
#: draw/consumers.py:1124 draw/templates/draw/tournament_content.html:5
|
||||||
msgid "The draw has not started yet."
|
msgid "The draw has not started yet."
|
||||||
msgstr "Le tirage au sort n'a pas encore commencé."
|
msgstr "Le tirage au sort n'a pas encore commencé."
|
||||||
|
|
||||||
|
@ -446,9 +446,9 @@ msgid ""
|
||||||
"from the ranking of the first round, in order to mix the teams between the "
|
"from the ranking of the first round, in order to mix the teams between the "
|
||||||
"two days."
|
"two days."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Le tirage au sort du tour {round} commence. L'ordre de passage est déterminé à "
|
"Le tirage au sort du tour {round} commence. L'ordre de passage est déterminé "
|
||||||
"partir du classement du premier tour, afin de mélanger les équipes entre les "
|
"à partir du classement du premier tour, afin de mélanger les équipes entre "
|
||||||
"deux jours."
|
"les deux jours."
|
||||||
|
|
||||||
#: draw/consumers.py:1034
|
#: draw/consumers.py:1034
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
|
@ -456,8 +456,8 @@ msgid ""
|
||||||
"The draw of the round {round} is starting. The passage order is another time "
|
"The draw of the round {round} is starting. The passage order is another time "
|
||||||
"randomly drawn."
|
"randomly drawn."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Le tirage au sort du tour {round} commence. L'ordre de passage est à nouveau tiré "
|
"Le tirage au sort du tour {round} commence. L'ordre de passage est à nouveau "
|
||||||
"au hasard."
|
"tiré au hasard."
|
||||||
|
|
||||||
#: draw/consumers.py:1043
|
#: draw/consumers.py:1043
|
||||||
msgid "The draw of the second round is starting!"
|
msgid "The draw of the second round is starting!"
|
||||||
|
@ -1034,18 +1034,18 @@ 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/forms.py:94 participation/forms.py:367
|
#: participation/forms.py:94 participation/forms.py:367
|
||||||
#: registration/forms.py:126 registration/forms.py:148
|
#: registration/forms.py:141 registration/forms.py:163
|
||||||
#: registration/forms.py:170 registration/forms.py:192
|
#: registration/forms.py:185 registration/forms.py:207
|
||||||
#: registration/forms.py:214 registration/forms.py:236
|
#: registration/forms.py:229 registration/forms.py:251
|
||||||
#: registration/forms.py:295 registration/forms.py:328
|
#: registration/forms.py:310 registration/forms.py:343
|
||||||
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:96 registration/forms.py:128
|
#: participation/forms.py:96 registration/forms.py:143
|
||||||
#: registration/forms.py:150 registration/forms.py:172
|
#: registration/forms.py:165 registration/forms.py:187
|
||||||
#: registration/forms.py:194 registration/forms.py:216
|
#: registration/forms.py:209 registration/forms.py:231
|
||||||
#: registration/forms.py:238 registration/forms.py:297
|
#: registration/forms.py:253 registration/forms.py:312
|
||||||
#: registration/forms.py:330
|
#: registration/forms.py:345
|
||||||
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."
|
||||||
|
|
||||||
|
@ -2509,7 +2509,7 @@ msgid "Edit tournament"
|
||||||
msgstr "Modifier le tournoi"
|
msgstr "Modifier le tournoi"
|
||||||
|
|
||||||
#: participation/templates/participation/tournament_detail.html:80
|
#: participation/templates/participation/tournament_detail.html:80
|
||||||
#: tfjm/templates/navbar.html:37
|
#: tfjm/templates/navbar.html:35
|
||||||
msgid "Teams"
|
msgid "Teams"
|
||||||
msgstr "Équipes"
|
msgstr "Équipes"
|
||||||
|
|
||||||
|
@ -2652,7 +2652,7 @@ msgid "Warning: non-free format"
|
||||||
msgstr "Attention : format non libre"
|
msgstr "Attention : format non libre"
|
||||||
|
|
||||||
#: participation/views.py:62 tfjm/templates/base.html:84
|
#: participation/views.py:62 tfjm/templates/base.html:84
|
||||||
#: tfjm/templates/navbar.html:43
|
#: tfjm/templates/navbar.html:41
|
||||||
msgid "Create team"
|
msgid "Create team"
|
||||||
msgstr "Créer une équipe"
|
msgstr "Créer une équipe"
|
||||||
|
|
||||||
|
@ -2665,7 +2665,7 @@ 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:103 tfjm/templates/base.html:79
|
#: participation/views.py:103 tfjm/templates/base.html:79
|
||||||
#: tfjm/templates/navbar.html:48
|
#: tfjm/templates/navbar.html:46
|
||||||
msgid "Join team"
|
msgid "Join team"
|
||||||
msgstr "Rejoindre une équipe"
|
msgstr "Rejoindre une équipe"
|
||||||
|
|
||||||
|
@ -2898,27 +2898,50 @@ msgstr "Marquer comme en attente"
|
||||||
msgid "Mark as invalid"
|
msgid "Mark as invalid"
|
||||||
msgstr "Marquer comme invalide"
|
msgstr "Marquer comme invalide"
|
||||||
|
|
||||||
#: registration/forms.py:23
|
#: registration/forms.py:25
|
||||||
msgid "role"
|
msgid "role"
|
||||||
msgstr "rôle"
|
msgstr "rôle"
|
||||||
|
|
||||||
#: registration/forms.py:25
|
#: registration/forms.py:27
|
||||||
msgid "participant"
|
msgid "participant"
|
||||||
msgstr "participant⋅e"
|
msgstr "participant⋅e"
|
||||||
|
|
||||||
#: registration/forms.py:26 registration/models.py:516
|
#: registration/forms.py:28 registration/models.py:516
|
||||||
msgid "coach"
|
msgid "coach"
|
||||||
msgstr "encadrant⋅e"
|
msgstr "encadrant⋅e"
|
||||||
|
|
||||||
#: registration/forms.py:36 registration/forms.py:61 registration/forms.py:92
|
#: registration/forms.py:38 registration/forms.py:76 registration/forms.py:107
|
||||||
msgid "This email address is already used."
|
msgid "This email address is already used."
|
||||||
msgstr "Cette adresse e-mail est déjà utilisée."
|
msgstr "Cette adresse e-mail est déjà utilisée."
|
||||||
|
|
||||||
#: registration/forms.py:286
|
#: registration/forms.py:45
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid ""
|
||||||
|
#| "Registrations for the tournament of {tournament} are ending on the {date:"
|
||||||
|
#| "%Y-%m-%d %H:%M}."
|
||||||
|
msgid ""
|
||||||
|
"Registrations are not opened yet. They will open on the {opening_date:%Y-%m-"
|
||||||
|
"%d %H:%M}."
|
||||||
|
msgstr ""
|
||||||
|
"Les inscriptions pour le tournoi de {tournament} se terminent le {date:%d/%m/"
|
||||||
|
"%Y %H:%M}."
|
||||||
|
|
||||||
|
#: registration/forms.py:49
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid ""
|
||||||
|
#| "Registrations for the tournament of {tournament} are ending on the {date:"
|
||||||
|
#| "%Y-%m-%d %H:%M}."
|
||||||
|
msgid ""
|
||||||
|
"Registrations for this year are closed since {opening_date:%Y-%m-%d %H:%M}."
|
||||||
|
msgstr ""
|
||||||
|
"Les inscriptions pour le tournoi de {tournament} se terminent le {date:%d/%m/"
|
||||||
|
"%Y %H:%M}."
|
||||||
|
|
||||||
|
#: registration/forms.py:301
|
||||||
msgid "Pending"
|
msgid "Pending"
|
||||||
msgstr "En attente"
|
msgstr "En attente"
|
||||||
|
|
||||||
#: registration/forms.py:305 registration/forms.py:338
|
#: registration/forms.py:320 registration/forms.py:353
|
||||||
msgid "You must upload your receipt."
|
msgid "You must upload your receipt."
|
||||||
msgstr "Vous devez envoyer votre justificatif."
|
msgstr "Vous devez envoyer votre justificatif."
|
||||||
|
|
||||||
|
@ -3909,15 +3932,37 @@ msgstr ""
|
||||||
|
|
||||||
#: registration/templates/registration/signup.html:5
|
#: registration/templates/registration/signup.html:5
|
||||||
#: registration/templates/registration/signup.html:12
|
#: registration/templates/registration/signup.html:12
|
||||||
#: registration/templates/registration/signup.html:26 registration/views.py:48
|
#: registration/templates/registration/signup.html:39 registration/views.py:48
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Inscription"
|
msgstr "Inscription"
|
||||||
|
|
||||||
#: registration/templates/registration/signup.html:21
|
#: registration/templates/registration/signup.html:17
|
||||||
|
msgid ""
|
||||||
|
"Thank you for your great interest, but registrations are not opened yet!"
|
||||||
|
msgstr ""
|
||||||
|
"Merci pour votre grand intérêt, mais les inscriptions ne sont pas encore ouvertes !"
|
||||||
|
|
||||||
|
#: registration/templates/registration/signup.html:18
|
||||||
|
msgid "They will open on:"
|
||||||
|
msgstr "Elles ouvriront le :"
|
||||||
|
|
||||||
|
#: registration/templates/registration/signup.html:19
|
||||||
|
msgid "Please come back at this time to register!"
|
||||||
|
msgstr "Merci de revenir à ce moment-là pour vous inscrire !"
|
||||||
|
|
||||||
|
#: registration/templates/registration/signup.html:23
|
||||||
|
msgid "Registrations are closed for this year. We hope to see you next year!"
|
||||||
|
msgstr "Les inscriptions sont closes pour cette année. Nous espérons vous revoir l'année prochaine !"
|
||||||
|
|
||||||
|
#: registration/templates/registration/signup.html:24
|
||||||
|
msgid "If needed, you can contact us by mail."
|
||||||
|
msgstr "Si nécessaire, vous pouvez nous contacter par mail."
|
||||||
|
|
||||||
|
#: registration/templates/registration/signup.html:34
|
||||||
msgid "By registering, you certify that you have read and accepted our"
|
msgid "By registering, you certify that you have read and accepted our"
|
||||||
msgstr "En vous inscrivant, vous certifiez avoir lu et accepté notre"
|
msgstr "En vous inscrivant, vous certifiez avoir lu et accepté notre"
|
||||||
|
|
||||||
#: registration/templates/registration/signup.html:22
|
#: registration/templates/registration/signup.html:35
|
||||||
msgid "privacy policy"
|
msgid "privacy policy"
|
||||||
msgstr "politique de confidentialité"
|
msgstr "politique de confidentialité"
|
||||||
|
|
||||||
|
@ -4274,11 +4319,11 @@ msgstr "Privé, réservé aux utilisateur⋅rices explicitement autorisé⋅es"
|
||||||
msgid "Admin users"
|
msgid "Admin users"
|
||||||
msgstr "Administrateur⋅rices"
|
msgstr "Administrateur⋅rices"
|
||||||
|
|
||||||
#: tfjm/settings.py:173
|
#: tfjm/settings.py:174
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr "Anglais"
|
msgstr "Anglais"
|
||||||
|
|
||||||
#: tfjm/settings.py:174
|
#: tfjm/settings.py:175
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Français"
|
msgstr "Français"
|
||||||
|
|
||||||
|
@ -4521,39 +4566,39 @@ msgstr ""
|
||||||
"Si vous ne finalisez pas votre inscription avant la date limite indiquée, "
|
"Si vous ne finalisez pas votre inscription avant la date limite indiquée, "
|
||||||
"vous ne pourrez malheureusement pas participer au 𝕋𝔽𝕁𝕄²."
|
"vous ne pourrez malheureusement pas participer au 𝕋𝔽𝕁𝕄²."
|
||||||
|
|
||||||
#: tfjm/templates/navbar.html:19 tfjm/urls.py:34
|
#: tfjm/templates/navbar.html:17 tfjm/urls.py:33
|
||||||
msgid "Home"
|
msgid "Home"
|
||||||
msgstr "Accueil"
|
msgstr "Accueil"
|
||||||
|
|
||||||
#: tfjm/templates/navbar.html:24
|
#: tfjm/templates/navbar.html:22
|
||||||
msgid "Tournament"
|
msgid "Tournament"
|
||||||
msgstr "Tournoi"
|
msgstr "Tournoi"
|
||||||
|
|
||||||
#: tfjm/templates/navbar.html:28
|
#: tfjm/templates/navbar.html:26
|
||||||
msgid "Tournaments"
|
msgid "Tournaments"
|
||||||
msgstr "Tournois"
|
msgstr "Tournois"
|
||||||
|
|
||||||
#: tfjm/templates/navbar.html:34
|
#: tfjm/templates/navbar.html:32
|
||||||
msgid "Users"
|
msgid "Users"
|
||||||
msgstr "Utilisateur⋅rices"
|
msgstr "Utilisateur⋅rices"
|
||||||
|
|
||||||
#: tfjm/templates/navbar.html:54
|
#: tfjm/templates/navbar.html:52
|
||||||
msgid "My team"
|
msgid "My team"
|
||||||
msgstr "Mon équipe"
|
msgstr "Mon équipe"
|
||||||
|
|
||||||
#: tfjm/templates/navbar.html:59
|
#: tfjm/templates/navbar.html:57
|
||||||
msgid "My participation"
|
msgid "My participation"
|
||||||
msgstr "Ma participation"
|
msgstr "Ma participation"
|
||||||
|
|
||||||
#: tfjm/templates/navbar.html:80
|
#: tfjm/templates/navbar.html:78
|
||||||
msgid "Administration"
|
msgid "Administration"
|
||||||
msgstr "Administration"
|
msgstr "Administration"
|
||||||
|
|
||||||
#: tfjm/templates/navbar.html:88
|
#: tfjm/templates/navbar.html:86
|
||||||
msgid "Search…"
|
msgid "Search…"
|
||||||
msgstr "Chercher…"
|
msgstr "Chercher…"
|
||||||
|
|
||||||
#: tfjm/templates/navbar.html:97
|
#: tfjm/templates/navbar.html:95
|
||||||
msgid "Return to admin view"
|
msgid "Return to admin view"
|
||||||
msgstr "Retourner à l'interface administrateur⋅rice"
|
msgstr "Retourner à l'interface administrateur⋅rice"
|
||||||
|
|
||||||
|
@ -4561,7 +4606,7 @@ msgstr "Retourner à l'interface administrateur⋅rice"
|
||||||
msgid "Register"
|
msgid "Register"
|
||||||
msgstr "S'inscrire"
|
msgstr "S'inscrire"
|
||||||
|
|
||||||
#: tfjm/templates/navbar.html:118
|
#: tfjm/templates/navbar.html:119
|
||||||
msgid "My account"
|
msgid "My account"
|
||||||
msgstr "Mon compte"
|
msgstr "Mon compte"
|
||||||
|
|
||||||
|
|
|
@ -5,16 +5,14 @@ from pathlib import Path
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.management import BaseCommand
|
from django.core.management import BaseCommand
|
||||||
from django.utils.translation import activate
|
|
||||||
from participation.models import Solution, Tournament
|
from participation.models import Solution, Tournament
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
def handle(self, *args, **kwargs):
|
def handle(self, *args, **kwargs):
|
||||||
activate(settings.PROBLEMS)
|
|
||||||
|
|
||||||
base_dir = Path(__file__).parent.parent.parent.parent
|
base_dir = Path(__file__).parent.parent.parent.parent
|
||||||
base_dir /= "output"
|
base_dir /= "output"
|
||||||
|
base_dir /= "solutions"
|
||||||
if not base_dir.is_dir():
|
if not base_dir.is_dir():
|
||||||
base_dir.mkdir()
|
base_dir.mkdir()
|
||||||
base_dir /= "Par équipe"
|
base_dir /= "Par équipe"
|
||||||
|
|
|
@ -7,6 +7,8 @@ from django.contrib.auth.forms import UserCreationForm
|
||||||
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
|
||||||
from django.forms import FileInput
|
from django.forms import FileInput
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.utils.text import format_lazy
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from .models import CoachRegistration, ParticipantRegistration, Payment, \
|
from .models import CoachRegistration, ParticipantRegistration, Payment, \
|
||||||
|
@ -36,6 +38,19 @@ class SignupForm(UserCreationForm):
|
||||||
self.add_error("email", _("This email address is already used."))
|
self.add_error("email", _("This email address is already used."))
|
||||||
return email
|
return email
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
# Check that registrations are opened
|
||||||
|
now = timezone.now()
|
||||||
|
if now < settings.REGISTRATION_DATES['open']:
|
||||||
|
self.add_error(None, format_lazy(_("Registrations are not opened yet. "
|
||||||
|
"They will open on the {opening_date:%Y-%m-%d %H:%M}."),
|
||||||
|
opening_date=settings.REGISTRATION_DATES['open']))
|
||||||
|
elif now > settings.REGISTRATION_DATES['close']:
|
||||||
|
self.add_error(None, format_lazy(_("Registrations for this year are closed since "
|
||||||
|
"{closing_date:%Y-%m-%d %H:%M}."),
|
||||||
|
closing_date=settings.REGISTRATION_DATES['close']))
|
||||||
|
return super().clean()
|
||||||
|
|
||||||
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["first_name"].required = True
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Copyright (C) 2024 by Animath
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from django.core.management import BaseCommand
|
||||||
|
from participation.models import Team
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = """Cette commande permet d'exporter dans le dossier output/photo_authorizations l'ensemble des
|
||||||
|
autorisations de droit à l'image des participant⋅es, triées par équipe, incluant aussi celles de la finale."""
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
base_dir = Path(__file__).parent.parent.parent.parent
|
||||||
|
base_dir /= "output"
|
||||||
|
base_dir / "photo_authorizations"
|
||||||
|
if not base_dir.is_dir():
|
||||||
|
base_dir.mkdir()
|
||||||
|
|
||||||
|
for team in Team.objects.filter(participation__valid=True).all():
|
||||||
|
team_dir = base_dir / f"{team.trigram} - {team.name}"
|
||||||
|
if not team_dir.is_dir():
|
||||||
|
team_dir.mkdir()
|
||||||
|
|
||||||
|
for participant in team.participants.all():
|
||||||
|
if participant.photo_authorization:
|
||||||
|
with participant.photo_authorization.file as file_input:
|
||||||
|
with open(team_dir / f"{participant}.pdf", 'wb') as file_output:
|
||||||
|
file_output.write(file_input.read())
|
||||||
|
|
||||||
|
if participant.photo_authorization_final:
|
||||||
|
with participant.photo_authorization.file as file_input:
|
||||||
|
with open(team_dir / f"{participant} (finale).pdf", 'wb') as file_output:
|
||||||
|
file_output.write(file_input.read())
|
|
@ -1,7 +1,7 @@
|
||||||
# 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 datetime import date, datetime
|
from datetime import date
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
|
@ -774,7 +774,7 @@ class Payment(models.Model):
|
||||||
return checkout_intent
|
return checkout_intent
|
||||||
|
|
||||||
tournament = self.tournament
|
tournament = self.tournament
|
||||||
year = datetime.now().year
|
year = timezone.now().year
|
||||||
base_site = "https://" + Site.objects.first().domain
|
base_site = "https://" + Site.objects.first().domain
|
||||||
checkout_intent = helloasso.create_checkout_intent(
|
checkout_intent = helloasso.create_checkout_intent(
|
||||||
amount=100 * self.amount,
|
amount=100 * self.amount,
|
||||||
|
|
|
@ -9,30 +9,42 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>{% trans "Sign up" %}</h2>
|
{% now "c" as now %}
|
||||||
|
{% if now < TFJM.REGISTRATION_DATES.open.isoformat %}
|
||||||
<form method="post">
|
<div class="alert alert-warning">
|
||||||
{% csrf_token %}
|
{% trans "Thank you for your great interest, but registrations are not opened yet!" %}
|
||||||
{{ form|crispy }}
|
{% trans "They will open on:" %} {{ TFJM.REGISTRATION_DATES.open|date:'DATETIME_FORMAT' }}.
|
||||||
<div id="registration_form"></div>
|
{% trans "Please come back at this time to register!" %}
|
||||||
|
|
||||||
<div class="py-2 text-muted">
|
|
||||||
<i class="fas fa-info-circle"></i>
|
|
||||||
{% trans "By registering, you certify that you have read and accepted our" %}
|
|
||||||
<a href="{% url 'about' %}#politique-confidentialite">{% trans "privacy policy" %}</a>.
|
|
||||||
</div>
|
</div>
|
||||||
|
{% elif now > TFJM.REGISTRATION_DATES.close.isoformat %}
|
||||||
<button class="btn btn-success" type="submit">
|
<div class="alert alert-danger">
|
||||||
{% trans "Sign up" %}
|
{% trans "Registrations are closed for this year. We hope to see you next year!" %}
|
||||||
</button>
|
{% trans "If needed, you can contact us by mail." %}
|
||||||
</form>
|
</div>
|
||||||
|
{% else %}
|
||||||
<div id="student_registration_form" class="d-none">
|
<form method="post">
|
||||||
{{ student_registration_form|crispy }}
|
{% csrf_token %}
|
||||||
</div>
|
{{ form|crispy }}
|
||||||
<div id="coach_registration_form" class="d-none">
|
<div id="registration_form"></div>
|
||||||
{{ coach_registration_form|crispy }}
|
|
||||||
</div>
|
<div class="py-2 text-muted">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
{% trans "By registering, you certify that you have read and accepted our" %}
|
||||||
|
<a href="{% url 'about' %}#politique-confidentialite">{% trans "privacy policy" %}</a>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn btn-success" type="submit">
|
||||||
|
{% trans "Sign up" %}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div id="student_registration_form" class="d-none">
|
||||||
|
{{ student_registration_form|crispy }}
|
||||||
|
</div>
|
||||||
|
<div id="coach_registration_form" class="d-none">
|
||||||
|
{{ coach_registration_form|crispy }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extrajavascript %}
|
{% block extrajavascript %}
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
# 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 datetime import timedelta
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
from django.test import TestCase
|
from django.test import override_settings, TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils import timezone
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.http import urlsafe_base64_encode
|
from django.utils.http import urlsafe_base64_encode
|
||||||
from participation.models import Team
|
from participation.models import Team
|
||||||
|
@ -114,6 +117,9 @@ class TestRegistration(TestCase):
|
||||||
self.assertRedirects(response, "http://" + Site.objects.get().domain +
|
self.assertRedirects(response, "http://" + Site.objects.get().domain +
|
||||||
str(self.coach.registration.get_absolute_url()), 302, 200)
|
str(self.coach.registration.get_absolute_url()), 302, 200)
|
||||||
|
|
||||||
|
# Ensure that we are between registration dates
|
||||||
|
@override_settings(REGISTRATION_DATES={'open': timezone.now() - timedelta(days=1),
|
||||||
|
'close': timezone.now() + timedelta(days=1)})
|
||||||
def test_registration(self):
|
def test_registration(self):
|
||||||
"""
|
"""
|
||||||
Ensure that the signup form is working successfully.
|
Ensure that the signup form is working successfully.
|
||||||
|
@ -223,6 +229,52 @@ class TestRegistration(TestCase):
|
||||||
response = self.client.get(reverse("registration:email_validation_resend", args=(user.pk,)))
|
response = self.client.get(reverse("registration:email_validation_resend", args=(user.pk,)))
|
||||||
self.assertRedirects(response, reverse("registration:email_validation_sent"), 302, 200)
|
self.assertRedirects(response, reverse("registration:email_validation_sent"), 302, 200)
|
||||||
|
|
||||||
|
def test_registration_dates(self):
|
||||||
|
"""
|
||||||
|
Test that registrations are working only between registration dates.
|
||||||
|
"""
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
# Test that registration between open and close dates are working
|
||||||
|
with override_settings(REGISTRATION_DATES={'open': timezone.now() - timedelta(days=2),
|
||||||
|
'close': timezone.now() + timedelta(days=2)}):
|
||||||
|
response = self.client.get(reverse("registration:signup"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertIn("<i class=\"fas fa-user-plus\"></i> Register", response.content.decode())
|
||||||
|
self.assertNotIn("registrations are not opened", response.content.decode())
|
||||||
|
self.assertNotIn("Registrations are closed", response.content.decode())
|
||||||
|
|
||||||
|
response = self.client.post(reverse("registration:signup"))
|
||||||
|
self.assertFormError(response.context['form'], None, [])
|
||||||
|
|
||||||
|
# Test that registration before open date is not working
|
||||||
|
with override_settings(REGISTRATION_DATES={'open': timezone.now() + timedelta(days=1),
|
||||||
|
'close': timezone.now() + timedelta(days=2)}):
|
||||||
|
response = self.client.get(reverse("registration:signup"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertNotIn("<i class=\"fas fa-user-plus\"></i> Register", response.content.decode())
|
||||||
|
self.assertIn("registrations are not opened", response.content.decode())
|
||||||
|
|
||||||
|
response = self.client.post(reverse("registration:signup"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertFormError(response.context['form'], None,
|
||||||
|
"Registrations are not opened yet. They will open on the "
|
||||||
|
f"{settings.REGISTRATION_DATES['open']:%Y-%m-%d %H:%M}.")
|
||||||
|
|
||||||
|
# Test that registration after close date is not working
|
||||||
|
with override_settings(REGISTRATION_DATES={'open': timezone.now() - timedelta(days=2),
|
||||||
|
'close': timezone.now() - timedelta(days=1)}):
|
||||||
|
response = self.client.get(reverse("registration:signup"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertNotIn("<i class=\"fas fa-user-plus\"></i> Register", response.content.decode())
|
||||||
|
self.assertIn("Registrations are closed", response.content.decode())
|
||||||
|
|
||||||
|
response = self.client.post(reverse("registration:signup"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertFormError(response.context['form'], None,
|
||||||
|
"Registrations for this year are closed since "
|
||||||
|
f"{settings.REGISTRATION_DATES['close']:%Y-%m-%d %H:%M}.")
|
||||||
|
|
||||||
def test_login(self):
|
def test_login(self):
|
||||||
"""
|
"""
|
||||||
With a registered user, try to log in
|
With a registered user, try to log in
|
||||||
|
|
|
@ -18,6 +18,7 @@ def tfjm_context(request):
|
||||||
'ML_MANAGEMENT': settings.ML_MANAGEMENT,
|
'ML_MANAGEMENT': settings.ML_MANAGEMENT,
|
||||||
'PAYMENT_MANAGEMENT': settings.PAYMENT_MANAGEMENT,
|
'PAYMENT_MANAGEMENT': settings.PAYMENT_MANAGEMENT,
|
||||||
'RECOMMENDED_SOLUTIONS_COUNT': settings.RECOMMENDED_SOLUTIONS_COUNT,
|
'RECOMMENDED_SOLUTIONS_COUNT': settings.RECOMMENDED_SOLUTIONS_COUNT,
|
||||||
|
'REGISTRATION_DATES': settings.REGISTRATION_DATES,
|
||||||
'SINGLE_TOURNAMENT': settings.SINGLE_TOURNAMENT,
|
'SINGLE_TOURNAMENT': settings.SINGLE_TOURNAMENT,
|
||||||
'HEALTH_SHEET_REQUIRED': settings.HEALTH_SHEET_REQUIRED,
|
'HEALTH_SHEET_REQUIRED': settings.HEALTH_SHEET_REQUIRED,
|
||||||
'VACCINE_SHEET_REQUIRED': settings.VACCINE_SHEET_REQUIRED,
|
'VACCINE_SHEET_REQUIRED': settings.VACCINE_SHEET_REQUIRED,
|
||||||
|
|
|
@ -13,6 +13,7 @@ For the full list of settings and their values, see
|
||||||
https://docs.djangoproject.com/en/5.0/ref/settings/
|
https://docs.djangoproject.com/en/5.0/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -365,6 +366,11 @@ if TFJM_APP == "TFJM":
|
||||||
LOGO_FILE = "tfjm.svg"
|
LOGO_FILE = "tfjm.svg"
|
||||||
RULES_LINK = "https://tfjm.org/reglement"
|
RULES_LINK = "https://tfjm.org/reglement"
|
||||||
|
|
||||||
|
REGISTRATION_DATES = dict(
|
||||||
|
open=datetime.fromisoformat("2025-01-08T12:00:00+0100"),
|
||||||
|
close=datetime.fromisoformat("2025-03-02T22:00:00+0100"),
|
||||||
|
)
|
||||||
|
|
||||||
PROBLEMS = [
|
PROBLEMS = [
|
||||||
"Triominos",
|
"Triominos",
|
||||||
"Rassemblements mathématiques",
|
"Rassemblements mathématiques",
|
||||||
|
@ -395,6 +401,11 @@ elif TFJM_APP == "ETEAM":
|
||||||
LOGO_FILE = "eteam.png"
|
LOGO_FILE = "eteam.png"
|
||||||
RULES_LINK = "https://eteam.tfjm.org/rules/"
|
RULES_LINK = "https://eteam.tfjm.org/rules/"
|
||||||
|
|
||||||
|
REGISTRATION_DATES = dict(
|
||||||
|
open=datetime.fromisoformat("2024-06-01T12:00:00+0200"),
|
||||||
|
close=datetime.fromisoformat("2024-07-04T20:00:00+0200"),
|
||||||
|
)
|
||||||
|
|
||||||
PROBLEMS = [
|
PROBLEMS = [
|
||||||
"Exploring Flatland",
|
"Exploring Flatland",
|
||||||
"A Mazing Hive",
|
"A Mazing Hive",
|
||||||
|
|
|
@ -96,9 +96,12 @@
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not user.is_authenticated %}
|
{% if not user.is_authenticated %}
|
||||||
<li class="nav-item active">
|
{% now "c" as now %}
|
||||||
<a class="nav-link" href="{% url "registration:signup" %}"><i class="fas fa-user-plus"></i> {% trans "Register" %}</a>
|
{% if TFJM.REGISTRATION_DATES.open.isoformat <= now and now <= TFJM.REGISTRATION_DATES.close.isoformat %}
|
||||||
</li>
|
<li class="nav-item active">
|
||||||
|
<a class="nav-link" href="{% url "registration:signup" %}"><i class="fas fa-user-plus"></i> {% trans "Register" %}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
<li class="nav-item active">
|
<li class="nav-item active">
|
||||||
<a class="nav-link" href="#" data-bs-toggle="modal" data-bs-target="#loginModal">
|
<a class="nav-link" href="#" data-bs-toggle="modal" data-bs-target="#loginModal">
|
||||||
<i class="fas fa-sign-in-alt"></i> {% trans "Log in" %}
|
<i class="fas fa-sign-in-alt"></i> {% trans "Log in" %}
|
||||||
|
|
Loading…
Reference in New Issue