mirror of
https://gitlab.com/animath/si/plateforme.git
synced 2025-07-08 06:10:21 +02:00
Compare commits
21 Commits
d24f8cab16
...
main
Author | SHA1 | Date | |
---|---|---|---|
905b96fbcf
|
|||
be2e258948
|
|||
882570800c
|
|||
df31968a77
|
|||
df6fb3b3f3
|
|||
3807fbcf45
|
|||
8433390e19
|
|||
ec85f62ab6
|
|||
74b2a0c095
|
|||
67958335ab
|
|||
20410cc17f
|
|||
a5aff5ff21
|
|||
196dbc8275
|
|||
0847e5a308
|
|||
e5aa3ef059
|
|||
e1b4e1bb6b
|
|||
ecc59a6c8c
|
|||
b053a47a19
|
|||
ab2e49e8fb
|
|||
fe399c869d
|
|||
9de8a2ed0e
|
@ -2,15 +2,6 @@ stages:
|
|||||||
- test
|
- test
|
||||||
- quality-assurance
|
- quality-assurance
|
||||||
|
|
||||||
py311:
|
|
||||||
stage: test
|
|
||||||
image: python:3.11-alpine
|
|
||||||
before_script:
|
|
||||||
- apk add --no-cache libmagic
|
|
||||||
- apk add --no-cache gettext
|
|
||||||
- pip install tox --no-cache-dir
|
|
||||||
script: tox -e py311
|
|
||||||
|
|
||||||
py312:
|
py312:
|
||||||
stage: test
|
stage: test
|
||||||
image: python:3.12-alpine
|
image: python:3.12-alpine
|
||||||
|
@ -3,7 +3,8 @@ FROM python:3.13-alpine
|
|||||||
ENV PYTHONUNBUFFERED 1
|
ENV PYTHONUNBUFFERED 1
|
||||||
ENV DJANGO_ALLOW_ASYNC_UNSAFE 1
|
ENV DJANGO_ALLOW_ASYNC_UNSAFE 1
|
||||||
|
|
||||||
RUN apk add --no-cache gettext nginx gcc git libc-dev libffi-dev libxml2-dev libxslt-dev npm postgresql-dev libmagic texlive texmf-dist-fontsrecommended texmf-dist-lang texmf-dist-latexextra
|
RUN apk add --no-cache gettext nginx gcc git libc-dev libffi-dev libpq-dev libxml2-dev libxslt-dev \
|
||||||
|
npm libmagic texlive texmf-dist-fontsrecommended texmf-dist-lang texmf-dist-latexextra
|
||||||
|
|
||||||
RUN apk add --no-cache bash
|
RUN apk add --no-cache bash
|
||||||
|
|
||||||
|
211
docs/dev/transition.rst
Normal file
211
docs/dev/transition.rst
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
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-inscription-1:/code/output/photo_authorizations .
|
||||||
|
sudo mv photo_authorizations/* "data/owncloud/data/Emmy/files/Autorisations de droit à l'image/Autorisations de droit à l'image 2024/"
|
||||||
|
sudo chown -R www-data:root "data/owncloud/data/Emmy/files/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_tfjm | sudo tee inscription_tfjm_bkp_2024.sql > /dev/null
|
||||||
|
|
||||||
|
|
||||||
|
Réinitialisation effective
|
||||||
|
""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
Il est désormais possible de réinitialiser la base de données, après avoir éteint le serveur :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
sudo docker compose stop inscription
|
||||||
|
sudo rm -r data/inscription/media/*
|
||||||
|
sudo docker compose exec -u postgres postgres dropdb inscription_tfjm
|
||||||
|
sudo docker compose exec -u postgres postgres createdb -O inscription_tfjm inscription_tfjm
|
||||||
|
|
||||||
|
Redémarrez enfin le serveur (les migrations seront créées automatiquement)
|
||||||
|
et créez un nouveau compte administrateur⋅rice :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
sudo docker compose up -d inscription
|
||||||
|
sudo docker compose exec inscription bash
|
||||||
|
./manage.py createsuperuser
|
||||||
|
|
||||||
|
Vérifiez finalement le bon fonctionnement du site.
|
||||||
|
|
||||||
|
|
||||||
|
Sites Django
|
||||||
|
""""""""""""
|
||||||
|
|
||||||
|
Après avoir réinitialisé les données, il faut mettre à jour le site Django, qui permettra
|
||||||
|
d'avoir notamment des noms de domaine correct dans les mails envoyés.
|
||||||
|
|
||||||
|
Se connecter alors sur le site réouvert, puis dans la partie « Administration », chercher la
|
||||||
|
section « Sites » et modifier l'unique site présent. Vous pouvez ensuite effectuer les modifications
|
||||||
|
à réaliser.
|
||||||
|
|
||||||
|
|
||||||
|
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-15T12: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-inscription-1:/code/output/solutions .
|
||||||
|
sudo mv solutions/* "data/owncloud/data/Emmy/files/Solutions écrites 2024/"
|
||||||
|
sudo chown -R www-data:root "data/owncloud/data/Emmy/files/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
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@ from io import StringIO
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from crispy_forms.helper import FormHelper
|
from crispy_forms.helper import FormHelper
|
||||||
from crispy_forms.layout import Div, Field, Submit
|
from crispy_forms.layout import Div, Field, HTML, Layout, 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
|
||||||
@ -77,9 +77,30 @@ class ParticipationForm(forms.ModelForm):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if settings.TFJM_APP == "ETEAM":
|
if settings.SINGLE_TOURNAMENT:
|
||||||
# One single tournament only
|
|
||||||
del self.fields['tournament']
|
del self.fields['tournament']
|
||||||
|
self.helper = FormHelper()
|
||||||
|
idf_warning_banner = f"""
|
||||||
|
<div class=\"alert alert-warning\">
|
||||||
|
<h5 class=\"alert-heading\">{_("IMPORTANT")}</h4>
|
||||||
|
{_("""For the tournaments in the region "Île-de-France": registration is
|
||||||
|
unified for each tournament. By choosing a tournament "Île-de-France",
|
||||||
|
you're accepting that your team may be selected for one of these tournaments.
|
||||||
|
In case of date conflict, please write them in your motivation letter.""")}
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
unified_registration_tournament_ids = ",".join(
|
||||||
|
str(tournament.id) for tournament in Tournament.objects.filter(
|
||||||
|
unified_registration=True).all())
|
||||||
|
self.helper.layout = Layout(
|
||||||
|
'tournament',
|
||||||
|
Div(
|
||||||
|
HTML(idf_warning_banner),
|
||||||
|
css_id="idf_warning_banner",
|
||||||
|
data_tid_unified=unified_registration_tournament_ids,
|
||||||
|
),
|
||||||
|
'final',
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Participation
|
model = Participation
|
||||||
|
@ -5,16 +5,16 @@ 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"
|
||||||
|
if not base_dir.is_dir():
|
||||||
|
base_dir.mkdir()
|
||||||
|
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"
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 5.1.5 on 2025-01-14 18:06
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("participation", "0022_alter_note_observer_oral"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="tournament",
|
||||||
|
name="unified_registration",
|
||||||
|
field=models.BooleanField(
|
||||||
|
default=False, verbose_name="unified registration"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@ -283,6 +283,11 @@ class Tournament(models.Model):
|
|||||||
default=date.today,
|
default=date.today,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
unified_registration = models.BooleanField(
|
||||||
|
verbose_name=_("unified registration"),
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
|
||||||
place = models.CharField(
|
place = models.CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
verbose_name=_("place"),
|
verbose_name=_("place"),
|
||||||
|
@ -2,28 +2,28 @@
|
|||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Validation request - ETEAM</title>
|
<title>Demande de validation - TFJM²</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<p>
|
||||||
Hi,
|
Bonjour,
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The team "{{ team.name }}" ({{ team.trigram }}) has just asked to validate his team to take part
|
L'équipe « {{ team.name }} » ({{ team.trigram }}) vient de demander à valider son équipe pour participer
|
||||||
in ETEAM.
|
au {{ team.participation.get_problem_display }} du TFJM².
|
||||||
You can decide whether or not to accept the team by going to the team page:
|
Vous pouvez décider d'accepter ou de refuser l'équipe en vous rendant sur la page de l'équipe :
|
||||||
<a href="https://{{ domain }}{% url "participation:team_detail" pk=team.pk %}">
|
<a href="https://{{ domain }}{% url "participation:team_detail" pk=team.pk %}">
|
||||||
https://{{ domain }}{% url "participation:team_detail" pk=team.pk %}
|
https://{{ domain }}{% url "participation:team_detail" pk=team.pk %}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Sincerely yours,
|
Cordialement,
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The ETEAM team
|
L'organisation du TFJM²
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
Hi {{ user }},
|
Bonjour {{ user }},
|
||||||
|
|
||||||
The team "{{ team.name }}" ({{ team.trigram }}) has just asked to validate his team to take part
|
L'équipe « {{ team.name }} » ({{ team.trigram }}) vient de demander à valider son équipe pour participer
|
||||||
in ETEAM.
|
au {{ team.participation.get_problem_display }} du TFJM².
|
||||||
You can decide whether or not to accept the team by going to the team page:
|
Vous pouvez décider d'accepter ou de refuser l'équipe en vous rendant sur la page de l'équipe :
|
||||||
https://{{ domain }}{% url "participation:team_detail" pk=team.pk %}
|
https://{{ domain }}{% url "participation:team_detail" pk=team.pk %}
|
||||||
|
|
||||||
Sincerely yours,
|
Cordialement,
|
||||||
|
|
||||||
The ETEAM team
|
L'organisation du TFJM²
|
||||||
|
@ -2,21 +2,21 @@
|
|||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Team not validated – ETEAM</title>
|
<title>Équipe non validée – TFJM²</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
Hi,<br/>
|
Bonjour,<br/>
|
||||||
<br />
|
<br />
|
||||||
Unfortunately, your team "{{ team.name }}" ({{ team.trigram }}) has not been validated.
|
Maleureusement, votre équipe « {{ team.name }} » ({{ team.trigram }}) n'a pas été validée. Veuillez vérifier que vos autorisations
|
||||||
Please check that your authorisations are correctly filled in.
|
de droit à l'image sont correctes. Les organisateurs vous adressent ce message :<br />
|
||||||
The organisers are sending you this message:<br />
|
|
||||||
<br />
|
<br />
|
||||||
{{ message }}<br />
|
{{ message }}<br />
|
||||||
<br />
|
<br />
|
||||||
Please contact us at <a href="mailto:eteam_moc@proton.me">eteam_moc@proton.me</a> if you need further information.
|
N'hésitez pas à nous contacter à l'adresse <a href="mailto:contact@tfjm.org">contact@tfjm.org</a>
|
||||||
|
pour plus d'informations.
|
||||||
<br/>
|
<br/>
|
||||||
Sincerely yours,<br/>
|
Cordialement,<br/>
|
||||||
<br/>
|
<br/>
|
||||||
The ETEAM team
|
Le comité d'organisation du TFJM²
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
Hi,
|
Bonjour,
|
||||||
|
|
||||||
Unfortunately, your team "{{ team.name }}" ({{ team.trigram }}) has not been validated.
|
Maleureusement, votre équipe « {{ team.name }} » ({{ team.trigram }}) n'a pas été validée. Veuillez vérifier que vos
|
||||||
Please check that your authorisations are correctly filled in.
|
autorisations de droit à l'image sont correctes. Les organisateurs vous adressent ce message :
|
||||||
The organisers are sending you this message:<br />
|
|
||||||
|
|
||||||
{{ message }}
|
{{ message }}
|
||||||
|
|
||||||
Please contact us at eteam_moc@proton.me if you need further information.
|
N'hésitez pas à nous contacter à l'adresse contact@tfjm.org pour plus d'informations.
|
||||||
|
|
||||||
Sincerely yours,
|
Cordialement,
|
||||||
|
|
||||||
The ETEAM team
|
Le comité d'organisation du TFJM²
|
||||||
|
@ -2,36 +2,37 @@
|
|||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Team validated – ETEAM</title>
|
<title>Équipe validée – TFJM²</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<p>
|
||||||
Hello {{ registration }},
|
Bonjour {{ registration }},
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Congratulations! Your team "{{ team.name }}" ({{ team.trigram }}) is now validated! You are now ready to
|
Félicitations ! Votre équipe « {{ team.name }} » ({{ team.trigram }}) est désormais validée ! Vous êtes désormais
|
||||||
to work on your problems. You can then upload your solutions to the platform.
|
apte à travailler sur vos problèmes. Vous pourrez ensuite envoyer vos solutions sur la plateforme.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% if payment %}
|
{% if payment %}
|
||||||
<p>
|
<p>
|
||||||
You must now pay your participation fee of € {{ payment.amount }}.
|
Vous devez désormais vous acquitter de vos frais de participation, de {{ payment.amount }} € par élève.
|
||||||
You can pay by credit card or bank transfer. You'll find information
|
Vous pouvez payer par carte bancaire ou par virement bancaire. Vous trouverez les informations
|
||||||
on the payment page which you can find on
|
sur <a href="https://{{ domain }}{% url 'registration:update_payment' pk=payment.pk %}">la page de paiement</a>.
|
||||||
<a href="https://{{ domain }}{% url 'registration:my_account_detail' %}">your account</a>.
|
Si vous disposez d'une bourse, l'inscription est gratuite, mais vous devez soumettre un justificatif
|
||||||
If you have a scholarship, registration is free, but you must submit a justification on the same page.
|
sur la même page.
|
||||||
</p>
|
</p>
|
||||||
{% elif registration.is_coach and team.participation.tournament.price %}
|
{% elif registration.is_coach and team.participation.tournament.price %}
|
||||||
<p>
|
<p>
|
||||||
Your team must now pay a participation fee of {{ team.participation.tournament.price }} € per student (supervisors are exempt). Students with scholarships are exempt⋅es from these fees.
|
Votre équipe doit désormais s'acquitter des frais de participation de {{ team.participation.tournament.price }} €
|
||||||
You can track the status of payments on
|
par élève (les encadrant⋅es sont exonéré⋅es). Les élèves qui disposent d'une bourse sont exonéré⋅es de ces frais.
|
||||||
<a href="https://{{ domain }}{% url 'participation:team_detail' pk=team.pk %}">your team page</a>.
|
Vous pouvez suivre l'état des paiements sur
|
||||||
|
<a href="https://{{ domain }}{% url 'participation:team_detail' pk=team.pk %}">la page de votre équipe</a>.
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if message %}
|
{% if message %}
|
||||||
<p>
|
<p>
|
||||||
The organisers send you this message:
|
Les organisateur⋅ices vous adressent ce message :
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{{ message }}
|
{{ message }}
|
||||||
@ -39,7 +40,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The ETEAM team
|
Le comité d'organisation du TFJM²
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
Hello {{registration }},
|
Bonjour {{ registration }},
|
||||||
|
|
||||||
Congratulations! Your team "{{ team.name }}" ({{ team.trigram }}) is now validated! You are now ready to
|
Félicitations ! Votre équipe « {{ team.name }} » ({{ team.trigram }}) est désormais validée ! Vous êtes désormais apte
|
||||||
to work on your problems. You can then upload your solutions to the platform.
|
à travailler sur vos problèmes. Vous pourrez ensuite envoyer vos solutions sur la plateforme.
|
||||||
{% if payment %}
|
{% if team.participation.amount %}
|
||||||
You must now pay your participation fee of € {{ payment.amount }}.
|
Vous devez désormais vous acquitter de vos frais de participation, de {{ team.participation.amount }} €.
|
||||||
You can pay by credit card or bank transfer. You'll find information
|
Vous pouvez payer par carte bancaire ou par virement bancaire. Vous trouverez les informations
|
||||||
on the payment page which you can find on your account:
|
sur la page de paiement que vous pouvez retrouver sur votre compte :
|
||||||
https://{{ domain }}{% url 'registration:my_account_detail' %}
|
https://{{ domain }}{% url 'registration:my_account_detail' %}
|
||||||
If you have a scholarship, registration is free, but you must submit a justification on the same page.
|
Si vous disposez d'une bourse, l'inscription est gratuite, mais vous devez soumettre un justificatif
|
||||||
|
sur la même page.
|
||||||
{% elif registration.is_coach and team.participation.tournament.price %}
|
{% elif registration.is_coach and team.participation.tournament.price %}
|
||||||
Your team must now pay a participation fee of {{ team.participation.tournament.price }} € per student (supervisors are exempt). Students with scholarships are exempt⋅es from these fees.
|
Votre équipe doit désormais s'acquitter des frais de participation de {{ team.participation.tournament.price }} €
|
||||||
You can track the status of payments on your team page:
|
par élève (les encadrant⋅es sont exonéré⋅es). Les élèves qui disposent d'une bourse sont exonéré⋅es de ces frais.
|
||||||
|
Vous pouvez suivre l'état des paiements sur la page de votre équipe :
|
||||||
https://{{ domain }}{% url 'participation:team_detail' pk=team.pk %}
|
https://{{ domain }}{% url 'participation:team_detail' pk=team.pk %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if message %}
|
{% if message %}
|
||||||
The organisers send you this message:
|
Les organisateurices vous adressent ce message :
|
||||||
|
|
||||||
{{ message }}
|
{{ message }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
The ETEAM team
|
Le comité d'organisation du TFJM²
|
||||||
|
@ -208,22 +208,26 @@
|
|||||||
<h3>{% trans "Files available for download" %}</h3>
|
<h3>{% trans "Files available for download" %}</h3>
|
||||||
|
|
||||||
<div class="alert alert-warning fade show files-to-download-collapse" id="files-to-download-popup">
|
<div class="alert alert-warning fade show files-to-download-collapse" id="files-to-download-popup">
|
||||||
<h4>IMPORTANT</h4>
|
<h4>{% trans "IMPORTANT" %}</h4>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
{% blocktrans trimmed %}
|
||||||
The files accessible below may contain personal information.
|
The files accessible below may contain personal information.
|
||||||
In compliance with European law and out of respect for the confidentiality of participants' data,
|
In compliance with European law and out of respect for the confidentiality of participants data,
|
||||||
you may only use this data for purposes strictly necessary to the organization of the tournament.
|
you may only use this data for purposes strictly necessary to the organization of the tournament.
|
||||||
|
{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
{% blocktrans trimmed %}
|
||||||
Moreover, it is your responsibility to delete these files once you no longer need them, especially at the end of the tournament.
|
Moreover, it is your responsibility to delete these files once you no longer need them, especially at the end of the tournament.
|
||||||
|
{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<button class="btn btn-warning" data-bs-toggle="collapse" href=".files-to-download-collapse"
|
<button class="btn btn-warning" data-bs-toggle="collapse" href=".files-to-download-collapse"
|
||||||
role="button" aria-expanded="false" aria-controls="files-to-download files-to-download-popup">
|
role="button" aria-expanded="false" aria-controls="files-to-download files-to-download-popup">
|
||||||
I agree not to divulge participants' data and to delete them at the end of the tournament.
|
{% trans "I agree not to divulge participants data and to delete them at the end of the tournament." %}
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,15 +1,37 @@
|
|||||||
{% extends request.content_only|yesno:"empty.html,base.html" %}
|
{% extends request.content_only|yesno:"empty.html,base.html" %}
|
||||||
|
|
||||||
{% load crispy_forms_filters i18n %}
|
{% load crispy_forms_filters crispy_forms_tags i18n %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<div id="form-content">
|
<div id="form-content">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
{{ participation_form|crispy }}
|
{% crispy participation_form %}
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-success" type="submit">{% trans "Update" %}</button>
|
<button class="btn btn-success" type="submit">{% trans "Update" %}</button>
|
||||||
</form>
|
</form>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
|
{% block extrajavascript %}
|
||||||
|
<script>
|
||||||
|
const tournamentSelect = document.getElementById('id_tournament')
|
||||||
|
const idfWarningBanner = document.getElementById('idf_warning_banner')
|
||||||
|
const unifiedRegistrationTournamentIds = idfWarningBanner.getAttribute('data-tid-unified').split(',')
|
||||||
|
if (idfWarningBanner.getAttribute('data-tid-unified') !== "") {
|
||||||
|
function updateIDFWarningBannerVisibility() {
|
||||||
|
const tid = tournamentSelect.value
|
||||||
|
if (unifiedRegistrationTournamentIds.includes(tid))
|
||||||
|
idfWarningBanner.classList.remove('d-none')
|
||||||
|
else
|
||||||
|
idfWarningBanner.classList.add('d-none')
|
||||||
|
}
|
||||||
|
|
||||||
|
tournamentSelect.addEventListener('change', updateIDFWarningBannerVisibility)
|
||||||
|
updateIDFWarningBannerVisibility()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
idfWarningBanner.classList.add('d-none')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
@ -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,37 @@
|
|||||||
|
# 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"
|
||||||
|
if not base_dir.is_dir():
|
||||||
|
base_dir.mkdir()
|
||||||
|
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_final.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,29 +9,29 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Hi {{ user.registration }},
|
Bonjour {{ user.registration }},
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
You have been invited by {{ inviter.registration }} to join the ETEAM platform, available at
|
Vous avez été invités par {{ inviter.registration }} à rejoindre la plateforme du TFJM², accessible à l'adresse
|
||||||
<a href="https://{{ domain }}/">https://{{ domain }}/</a>. You have a volunteer account.
|
<a href="https://{{ domain }}/">https://{{ domain }}/</a>. Vous disposez d'un compte de bénévole.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
A random password has been set: <strong>{{ password }}</strong>.
|
Un mot de passe aléatoire a été défini : <strong>{{ password }}</strong>.
|
||||||
For security reasons, please change it as soon as you log in the first time.
|
Par sécurité, merci de le changer dès votre connexion.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
In the event of a problem, please contact us by e-mail at the following address
|
En cas de problème, merci de nous contacter soit par mail à l'adresse
|
||||||
<a href="mailto:eteam_moc@proton.me">eteam_moc@proton.me</a>.
|
<a href="mailto:contact@tfjm.org">contact@tfjm.org</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Sincerely yours,
|
Bien cordialement,
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
--
|
--
|
||||||
<p>
|
<p>
|
||||||
{% trans "The ETEAM team." %}<br>
|
{% trans "The TFJM² team." %}<br>
|
||||||
</p>
|
</p>
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
Hi {{ user.registration }},
|
Bonjour {{ user.registration }},
|
||||||
|
|
||||||
You have been invited by {{ inviter.registration }} to join the ETEAM platform, available at https://{{ domain }}. You have a volunteer account.
|
Vous avez été invités par {{ inviter.registration }} à rejoindre la plateforme du TFJM², accessible à l'adresse
|
||||||
A random password has been set: {{ password }}.
|
https://{{ domain }}/. Vous disposez d'un compte de bénévole.
|
||||||
For security reasons, please change it as soon as you log in the first time.
|
|
||||||
|
|
||||||
In the event of a problem, please contact us by e-mail at the following address eteam_moc@proton.me.
|
Un mot de passe aléatoire a été défini : {{ password }}.
|
||||||
|
Par sécurité, merci de le changer dès votre connexion.
|
||||||
|
|
||||||
Sincerely yours,
|
En cas de problème, merci de nous contacter soit par mail à l'adresse contact@tfjm.org, soit sur la plateforme
|
||||||
|
de chat accessible sur https://element.tfjm.org/ en vous connectant avec les mêmes identifiants.
|
||||||
|
|
||||||
|
Bien cordialement,
|
||||||
|
|
||||||
--
|
--
|
||||||
{% trans "The ETEAM team." %}
|
{% trans "The TFJM² team." %}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
{% trans "You recently registered on the ETEAM platform. Please click on the link below to confirm your registration." %}
|
{% trans "You recently registered on the TFJM² platform. Please click on the link below to confirm your registration." %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -36,5 +36,5 @@
|
|||||||
|
|
||||||
--
|
--
|
||||||
<p>
|
<p>
|
||||||
{% trans "The ETEAM team." %}<br>
|
{% trans "The TFJM² team." %}<br>
|
||||||
</p>
|
</p>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{% trans "Hi" %} {{ user.registration }},
|
{% trans "Hi" %} {{ user.registration }},
|
||||||
|
|
||||||
{% trans "You recently registered on the ETEAM platform. Please click on the link below to confirm your registration." %}
|
{% trans "You recently registered on the TFJM² platform. Please click on the link below to confirm your registration." %}
|
||||||
|
|
||||||
https://{{ domain }}{% url 'registration:email_validation' uidb64=uid token=token %}
|
https://{{ domain }}{% url 'registration:email_validation' uidb64=uid token=token %}
|
||||||
|
|
||||||
@ -12,4 +12,4 @@ https://{{ domain }}{% url 'registration:email_validation' uidb64=uid token=toke
|
|||||||
|
|
||||||
{% trans "Thanks" %},
|
{% trans "Thanks" %},
|
||||||
|
|
||||||
{% trans "The ETEAM team." %}
|
{% trans "The TFJM² team." %}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
{% blocktrans trimmed with amount=payment.amount team=payment.team.trigram tournament=payment.tournament.name %}
|
{% blocktrans trimmed with amount=payment.amount team=payment.team.trigram tournament=payment.tournament.name %}
|
||||||
We successfully received the payment of {{ amount }} € for your participation for the ETEAM in the team {{ team }}!
|
We successfully received the payment of {{ amount }} € for your participation for the TFJM² in the team {{ team }} for the tournament {{ tournament }}!
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -32,13 +32,17 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{% trans "Please note that these dates may be subject to change. If your local organizers gave you different dates, trust them." %}
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
{% trans "NB: This mail don't represent a payment receipt. The payer should receive a mail from Hello Asso. If it is not the case, please contact us if necessary" %}
|
{% trans "NB: This mail don't represent a payment receipt. The payer should receive a mail from Hello Asso. If it is not the case, please contact us if necessary" %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
--
|
--
|
||||||
<p>
|
<p>
|
||||||
{% trans "The ETEAM team." %}<br>
|
{% trans "The TFJM² team." %}<br>
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{% trans "Hi" %} {{ registration|safe }},
|
{% trans "Hi" %} {{ registration|safe }},
|
||||||
|
|
||||||
{% blocktrans trimmed with amount=payment.amount team=payment.team.trigram tournament=payment.tournament.name %}
|
{% blocktrans trimmed with amount=payment.amount team=payment.team.trigram tournament=payment.tournament.name %}
|
||||||
We successfully received the payment of {{ amount }} € for your participation for the ETEAM in the team {{ team }}!
|
We successfully received the payment of {{ amount }} € for your participation for the TFJM² in the team {{ team }} for the tournament {{ tournament }}!
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
|
|
||||||
{% trans "Your registration is now fully completed, and you can work on your solutions." %}
|
{% trans "Your registration is now fully completed, and you can work on your solutions." %}
|
||||||
@ -13,8 +13,10 @@ We successfully received the payment of {{ amount }} € for your participation
|
|||||||
* {% trans "Problems draw:" %} {{ payment.tournament.solutions_draw|date }}
|
* {% trans "Problems draw:" %} {{ payment.tournament.solutions_draw|date }}
|
||||||
* {% trans "Tournament dates:" %} {% trans "From" %} {{ payment.tournament.date_start|date }} {% trans "to" %} {{ payment.tournament.date_end|date }}
|
* {% trans "Tournament dates:" %} {% trans "From" %} {{ payment.tournament.date_start|date }} {% trans "to" %} {{ payment.tournament.date_end|date }}
|
||||||
|
|
||||||
|
{% trans "Please note that these dates may be subject to change. If your local organizers gave you different dates, trust them." %}
|
||||||
|
|
||||||
{% trans "NB: This mail don't represent a payment receipt. The payer should receive a mail from Hello Asso. If it is not the case, please contact us if necessary" %}
|
{% trans "NB: This mail don't represent a payment receipt. The payer should receive a mail from Hello Asso. If it is not the case, please contact us if necessary" %}
|
||||||
|
|
||||||
--
|
--
|
||||||
{% trans "The ETEAM team" %}
|
{% trans "The TFJM² team" %}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
{% blocktrans trimmed with amount=payment.amount team=payment.team.trigram tournament=payment.tournament %}
|
{% blocktrans trimmed with amount=payment.amount team=payment.team.trigram tournament=payment.tournament %}
|
||||||
You are registered for the ETEAM. Your team {{ team }} has been successfully validated.
|
You are registered for the TFJM² of {{ tournament }}. Your team {{ team }} has been successfully validated.
|
||||||
To end your inscription, you must pay the amount of {{ amount }} €.
|
To end your inscription, you must pay the amount of {{ amount }} €.
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
--
|
--
|
||||||
<p>
|
<p>
|
||||||
{% trans "The ETEAM team." %}<br>
|
{% trans "The TFJM² team." %}<br>
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{% trans "Hi" %} {{ registration|safe }},
|
{% trans "Hi" %} {{ registration|safe }},
|
||||||
|
|
||||||
{% blocktrans trimmed with amount=payment.amount team=payment.team.trigram tournament=payment.tournament %}
|
{% blocktrans trimmed with amount=payment.amount team=payment.team.trigram tournament=payment.tournament %}
|
||||||
You are registered for the ETEAM. Your team {{ team }} has been successfully validated.
|
You are registered for the TFJM² of {{ tournament }}. Your team {{ team }} has been successfully validated.
|
||||||
To end your inscription, you must pay the amount of {{ amount }} €.
|
To end your inscription, you must pay the amount of {{ amount }} €.
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
{% if payment.grouped %}
|
{% if payment.grouped %}
|
||||||
@ -19,4 +19,4 @@ https://{{ domain }}{% url "registration:update_payment" pk=payment.pk %}
|
|||||||
{% trans "If you have any problem, feel free to contact us." %}
|
{% trans "If you have any problem, feel free to contact us." %}
|
||||||
|
|
||||||
--
|
--
|
||||||
The ETEAM team
|
The TFJM² team
|
||||||
|
@ -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 %}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
% Specials
|
% Specials
|
||||||
\newcommand{\writingsep}{\vrule height 4ex width 0pt}
|
\newcommand{\writingsep}{\vrule height 4ex width 0pt}
|
||||||
|
\newcommand{\cdt}{\kern-0.5pt\ensuremath\cdot\kern-0.5pt}
|
||||||
|
|
||||||
% Page formating
|
% Page formating
|
||||||
\hoffset -1in
|
\hoffset -1in
|
||||||
@ -56,19 +57,23 @@ Autorisation d'enregistrement et de diffusion de l'image ({{ tournament.name }})
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Je soussign\'e {{ registration|safe|default:"\dotfill" }}\\
|
Je soussign\'e\cdt{}e {{ registration|safe|default:"\dotfill" }}\\
|
||||||
demeurant au {{ registration.address|safe|default:"\dotfill" }}
|
demeurant au {{ registration.address|safe|default:"\dotfill" }}
|
||||||
|
|
||||||
\medskip
|
\medskip
|
||||||
Cochez la/les cases correspondantes.\\
|
Cochez la/les cases correspondantes.\\
|
||||||
\medskip
|
\medskip
|
||||||
|
|
||||||
\fbox{\textcolor{white}{A}} Autorise l'association Animath, \`a l'occasion du $\mathbb{TFJM}^2$ de {{ tournament.name }}
|
\fbox{\textcolor{white}{A}} Autorise l'association Animath, \`a l'occasion du $\mathbb{TFJM}^2$
|
||||||
du {{ tournament.date_start }} au {{ tournament.date_end }} à : {{ tournament.place }}, \`a me photographier ou \`a me
|
{% if tournament.unified_registration %} dans
|
||||||
filmer et \`a diffuser les photos et/ou les vid\'eos r\'ealis\'ees \`a cette occasion sur son site et sur les sites
|
l'un des tournois d'Île-de-France (selon sélection : du 26 au 27 avril 2025, du 3 au 4 mai 2025, ou du 10 au 11 mai 2025)
|
||||||
partenaires. D\'eclare c\'eder \`a titre gracieux \`a Animath le droit d’utiliser mon image sur tous ses supports
|
{% else %} de
|
||||||
d'information : brochures, sites web, r\'eseaux sociaux. Animath devient, par la pr\'esente, cessionnaire des droits
|
{{ tournament.name }} du {{ tournament.date_start }} au {{ tournament.date_end }} à : {{ tournament.place }},
|
||||||
pendant toute la dur\'ee pour laquelle ont \'et\'e acquis les droits d'auteur de ces photographies.\\
|
{% endif %} \`a
|
||||||
|
me photographier ou \`a me filmer et \`a diffuser les photos et/ou les vid\'eos r\'ealis\'ees \`a cette occasion
|
||||||
|
sur son site et sur les sites partenaires. D\'eclare c\'eder \`a titre gracieux \`a Animath le droit d’utiliser mon
|
||||||
|
image sur tous ses supports d'information : brochures, sites web, r\'eseaux sociaux. Animath devient, par la pr\'esente,
|
||||||
|
cessionnaire des droits pendant toute la dur\'ee pour laquelle ont \'et\'e acquis les droits d'auteur de ces photographies.\\
|
||||||
|
|
||||||
\medskip
|
\medskip
|
||||||
Animath s'engage, conform\'ement aux dispositions l\'egales en vigueur relatives au droit \`a l'image, \`a ce que la
|
Animath s'engage, conform\'ement aux dispositions l\'egales en vigueur relatives au droit \`a l'image, \`a ce que la
|
||||||
@ -98,7 +103,7 @@ Animath, IHP, 11 rue Pierre et Marie Curie, 75231 Paris cedex 05.\\
|
|||||||
|
|
||||||
\bigskip
|
\bigskip
|
||||||
|
|
||||||
Signature pr\'ec\'ed\'ee de la mention \og lu et approuv\'e \fg{}
|
Signature pr\'ec\'ed\'ee de la mention « lu et approuv\'e »
|
||||||
|
|
||||||
\medskip
|
\medskip
|
||||||
|
|
||||||
@ -106,7 +111,7 @@ Signature pr\'ec\'ed\'ee de la mention \og lu et approuv\'e \fg{}
|
|||||||
|
|
||||||
\begin{minipage}[c]{0.5\textwidth}
|
\begin{minipage}[c]{0.5\textwidth}
|
||||||
|
|
||||||
\underline{Le participant :}\\
|
\underline{La/le participant\cdt{}e :}\\
|
||||||
|
|
||||||
Fait \`a :\\
|
Fait \`a :\\
|
||||||
le
|
le
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
% Specials
|
% Specials
|
||||||
\newcommand{\writingsep}{\vrule height 4ex width 0pt}
|
\newcommand{\writingsep}{\vrule height 4ex width 0pt}
|
||||||
|
\newcommand{\cdt}{\kern-0.5pt\ensuremath\cdot\kern-0.5pt}
|
||||||
|
|
||||||
% Page formating
|
% Page formating
|
||||||
\hoffset -1in
|
\hoffset -1in
|
||||||
@ -57,20 +58,25 @@ Autorisation d'enregistrement et de diffusion de l'image
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Je soussign\'e \dotfill (p\`ere, m\`ere, responsable l\'egal) \\
|
Je soussign\'e\cdt{}e \dotfill (p\`ere, m\`ere, responsable l\'egal) \\
|
||||||
agissant en qualit\'e de repr\'esentant de {{ registration|safe|default:"\dotfill" }}\\
|
agissant en qualit\'e de repr\'esentant\cdt{}e de {{ registration|safe|default:"\dotfill" }}\\
|
||||||
demeurant au {{ registration.address|safe|default:"\dotfill" }}
|
demeurant au {{ registration.address|safe|default:"\dotfill" }}
|
||||||
|
|
||||||
\medskip
|
\medskip
|
||||||
Cochez la/les cases correspondantes.\\
|
Cochez la/les cases correspondantes.\\
|
||||||
\medskip
|
\medskip
|
||||||
|
|
||||||
\fbox{\textcolor{white}{A}} Autorise l'association Animath, \`a l'occasion du $\mathbb{TFJM}^2$ de {{ tournament.name }}
|
\fbox{\textcolor{white}{A}} Autorise l'association Animath, \`a l'occasion du $\mathbb{TFJM}^2$
|
||||||
du {{ tournament.date_start }} au {{ tournament.date_end }} à : {{ tournament.place }}, \`a photographier ou \`a filmer
|
{% if tournament.unified_registration %} dans
|
||||||
l'enfant et \`a diffuser les photos et/ou les vid\'eos r\'ealis\'ees \`a cette occasion sur son site et sur les sites
|
l'un des tournois d'Île-de-France (selon sélection : du 26 au 27 avril 2025, du 3 au 4 mai 2025, ou du 10 au 11 mai 2025)
|
||||||
partenaires. D\'eclare c\'eder \`a titre gracieux \`a Animath le droit d’utiliser l'image de l'enfant sur tous ses
|
{% else %} de
|
||||||
supports d'information : brochures, sites web, r\'eseaux sociaux. Animath devient, par la pr\'esente, cessionnaire des
|
{{ tournament.name }} du {{ tournament.date_start }} au {{ tournament.date_end }} à : {{ tournament.place }},
|
||||||
droits pendant toute la dur\'ee pour laquelle ont \'et\'e acquis les droits d'auteur de ces photographies.\\
|
{% endif %} \`a
|
||||||
|
photographier ou \`a filmer l'enfant et \`a diffuser les photos et/ou les vid\'eos r\'ealis\'ees \`a cette occasion
|
||||||
|
sur son site et sur les sites partenaires. D\'eclare c\'eder \`a titre gracieux \`a Animath le droit d’utiliser l'image
|
||||||
|
de l'enfant sur tous ses supports d'information : brochures, sites web, r\'eseaux sociaux. Animath devient, par la
|
||||||
|
pr\'esente, cessionnaire des droits pendant toute la dur\'ee pour laquelle ont \'et\'e acquis les droits d'auteur de
|
||||||
|
ces photographies.\\
|
||||||
|
|
||||||
\medskip
|
\medskip
|
||||||
Animath s'engage, conform\'ement aux dispositions l\'egales en vigueur relatives au droit \`a l'image, \`a ce que la
|
Animath s'engage, conform\'ement aux dispositions l\'egales en vigueur relatives au droit \`a l'image, \`a ce que la
|
||||||
@ -100,14 +106,14 @@ Animath, IHP, 11 rue Pierre et Marie Curie, 75231 Paris cedex 05.\\
|
|||||||
|
|
||||||
\bigskip
|
\bigskip
|
||||||
|
|
||||||
Signatures pr\'ec\'ed\'ees de la mention \og lu et approuv\'e \fg{}
|
Signatures pr\'ec\'ed\'ees de la mention « lu et approuv\'e »
|
||||||
|
|
||||||
\medskip
|
\medskip
|
||||||
|
|
||||||
|
|
||||||
\begin{minipage}[c]{0.5\textwidth}
|
\begin{minipage}[c]{0.5\textwidth}
|
||||||
|
|
||||||
\underline{Le responsable l\'egal :}\\
|
\underline{La/le responsable l\'egal\cdt{}e :}\\
|
||||||
|
|
||||||
Fait \`a :\\
|
Fait \`a :\\
|
||||||
le :
|
le :
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
% Specials
|
% Specials
|
||||||
\newcommand{\writingsep}{\vrule height 4ex width 0pt}
|
\newcommand{\writingsep}{\vrule height 4ex width 0pt}
|
||||||
|
\newcommand{\cdt}{\kern-0.5pt\ensuremath\cdot\kern-0.5pt}
|
||||||
|
|
||||||
% Page formating
|
% Page formating
|
||||||
\hoffset -1in
|
\hoffset -1in
|
||||||
@ -45,16 +46,25 @@
|
|||||||
\Large \bf Autorisation parentale pour les mineurs ({{ tournament.name }})
|
\Large \bf Autorisation parentale pour les mineurs ({{ tournament.name }})
|
||||||
\end{center}
|
\end{center}
|
||||||
|
|
||||||
Je soussigné(e) \hrulefill,\\
|
Je soussigné\cdt{}e \hrulefill,\\
|
||||||
responsable légal, demeurant \writingsep\hrulefill\\
|
responsable légal\cdt{}e, demeurant \writingsep\hrulefill\\
|
||||||
\writingsep\hrulefill,\\
|
\writingsep\hrulefill,\\
|
||||||
\writingsep autorise {{ registration|default:"\hrulefill" }},\\
|
\writingsep autorise {{ registration|default:"\hrulefill" }},\\
|
||||||
né(e) le {{ registration.birth_date }},
|
né\cdt{}e le {{ registration.birth_date|default:"\underline{\phantom{dd/mm/aaaa} }" }},
|
||||||
à participer au Tournoi Français des Jeunes Mathématiciennes et Mathématiciens ($\mathbb{TFJM}^2$) organisé \`a :
|
à participer au Tournoi Français des Jeunes Mathématiciennes et Mathématiciens ($\mathbb{TFJM}^2$)
|
||||||
|
{% if tournament.unified_registration %} dans l'un des tournois d'Île-de-France selon sélection :
|
||||||
|
\begin{itemize}
|
||||||
|
\item Île-de-France 1, du 26 au 27 avril 2025 ;
|
||||||
|
\item Île-de-France 2, du 3 au 4 mai 2025 ;
|
||||||
|
\item Île-de-France 3, du 10 au 11 mai 2025.
|
||||||
|
\end{itemize}
|
||||||
|
{% else %}
|
||||||
|
organisé \`a :
|
||||||
{{ tournament.place }}, du {{ tournament.date_start }} au {{ tournament.date_end }}.
|
{{ tournament.place }}, du {{ tournament.date_start }} au {{ tournament.date_end }}.
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
Iel se rendra au lieu indiqu\'e ci-dessus le samedi matin et quittera les lieux l'après-midi du dimanche par
|
Iel se rendra au lieu indiqu\'e ci-dessus le samedi matin et quittera les lieux l'après-midi du dimanche par
|
||||||
ses propres moyens et sous la responsabilité du représentant légal.
|
ses propres moyens et sous la responsabilité du/de la représentant\cdt{}e légal\cdt{}e.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -19,7 +19,7 @@ gunicorn~=23.0.0
|
|||||||
odfpy~=1.4.1
|
odfpy~=1.4.1
|
||||||
pandas~=2.2.3
|
pandas~=2.2.3
|
||||||
phonenumbers~=8.13.47
|
phonenumbers~=8.13.47
|
||||||
psycopg-binary~=3.2.3
|
psycopg~=3.2.3
|
||||||
pypdf~=5.0.1
|
pypdf~=5.0.1
|
||||||
ipython~=8.28.0
|
ipython~=8.28.0
|
||||||
python-magic~=0.4.27
|
python-magic~=0.4.27
|
||||||
|
@ -13,11 +13,12 @@ def tfjm_context(request):
|
|||||||
'HAS_OBSERVER': settings.HAS_OBSERVER,
|
'HAS_OBSERVER': settings.HAS_OBSERVER,
|
||||||
'HAS_FINAL': settings.HAS_FINAL,
|
'HAS_FINAL': settings.HAS_FINAL,
|
||||||
'HOME_PAGE_LINK': settings.HOME_PAGE_LINK,
|
'HOME_PAGE_LINK': settings.HOME_PAGE_LINK,
|
||||||
'LOGO_PATH': "static/tfjm/img/" + settings.LOGO_FILE,
|
'LOGO_PATH': "tfjm/img/" + settings.LOGO_FILE,
|
||||||
'NB_ROUNDS': settings.NB_ROUNDS,
|
'NB_ROUNDS': settings.NB_ROUNDS,
|
||||||
'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
|
||||||
|
|
||||||
@ -195,7 +196,14 @@ STATICFILES_DIRS = [
|
|||||||
|
|
||||||
STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
||||||
|
|
||||||
STATICFILES_STORAGE = 'pipeline.storage.PipelineStorage'
|
STORAGES = {
|
||||||
|
"default": {
|
||||||
|
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
||||||
|
},
|
||||||
|
'staticfiles': {
|
||||||
|
'BACKEND': 'pipeline.storage.PipelineStorage',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
STATICFILES_FINDERS = (
|
STATICFILES_FINDERS = (
|
||||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||||
@ -365,6 +373,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-15T12:00:00+0100"),
|
||||||
|
close=datetime.fromisoformat("2025-03-02T22:00:00+0100"),
|
||||||
|
)
|
||||||
|
|
||||||
PROBLEMS = [
|
PROBLEMS = [
|
||||||
"Triominos",
|
"Triominos",
|
||||||
"Rassemblements mathématiques",
|
"Rassemblements mathématiques",
|
||||||
@ -395,6 +408,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",
|
||||||
|
@ -30,6 +30,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<h3 class="alert-heading"><i class="fas fa-warning"></i> {% trans "New in 2025" %}</h3>
|
||||||
|
{% blocktrans trimmed %}
|
||||||
|
Registration for Ile-de-France tournaments is now unified.
|
||||||
|
If you live in or near the Ile-de-France region, your registration will be pooled with each of the region's tournaments,
|
||||||
|
and the organizers will take care of team allocation. However, date constraints can be indicated in the motivation letter.
|
||||||
|
{% endblocktrans %}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="jumbotron p-5 border rounded-5">
|
<div class="jumbotron p-5 border rounded-5">
|
||||||
<h5 class="display-4">{% trans "How does it work?" %}</h5>
|
<h5 class="display-4">{% trans "How does it work?" %}</h5>
|
||||||
<p>
|
<p>
|
||||||
|
@ -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" %}
|
||||||
|
Reference in New Issue
Block a user