1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2025-11-17 16:17:48 +01:00

Compare commits

..

7 Commits

Author SHA1 Message Date
Maxime JUST
07e13ea6ee Add date Strasbourg 2025-11-16 10:42:04 +01:00
Maxime JUST
27a4bdf98e Add responsabilities of accompanying coaches + translate message about pending dates 2025-11-11 19:34:42 +01:00
Maxime JUST
af60d27402 Add messages for missing date tournaments 2025-11-11 18:50:31 +01:00
Maxime JUST
49729485b7 Fix linters + Fix translations 2025-11-11 18:50:01 +01:00
Maxime JUST
c8eefb0991 Add distinction between scientific coach and accompanying coach 2025-11-11 11:21:03 +00:00
Maxime JUST
1bea4d0188 Add migrations not in the repository 2025-11-07 09:54:38 +01:00
Maxime JUST
b0be8f5525 Add 2026 informations 2025-11-06 10:04:27 +01:00
10 changed files with 509 additions and 352 deletions

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.2.8 on 2025-11-06 18:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('draw', '0006_alter_round_current_pool'),
]
operations = [
migrations.AlterField(
model_name='teamdraw',
name='accepted',
field=models.PositiveSmallIntegerField(choices=[(1, 'Problem #1'), (2, 'Problem #2'), (3, 'Problem #3'), (4, 'Problem #4'), (5, 'Problem #5'), (6, 'Problem #6'), (7, 'Problem #7'), (8, 'Problem #8')], default=None, null=True, verbose_name='accepted problem'),
),
migrations.AlterField(
model_name='teamdraw',
name='purposed',
field=models.PositiveSmallIntegerField(choices=[(1, 'Problem #1'), (2, 'Problem #2'), (3, 'Problem #3'), (4, 'Problem #4'), (5, 'Problem #5'), (6, 'Problem #6'), (7, 'Problem #7'), (8, 'Problem #8')], default=None, null=True, verbose_name='purposed problem'),
),
]

File diff suppressed because it is too large Load Diff

View File

@@ -80,13 +80,17 @@ class ParticipationForm(forms.ModelForm):
if settings.SINGLE_TOURNAMENT: if settings.SINGLE_TOURNAMENT:
del self.fields['tournament'] del self.fields['tournament']
self.helper = FormHelper() self.helper = FormHelper()
idf_text = _(
'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.'
)
idf_warning_banner = f""" idf_warning_banner = f"""
<div class=\"alert alert-warning\"> <div class=\"alert alert-warning\">
<h5 class=\"alert-heading\">{_("IMPORTANT")}</h4> <h5 class=\"alert-heading\">{_("IMPORTANT")}</h4>
{_("""For the tournaments in the region "Île-de-France": registration is {idf_text}
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> </div>
""" """
unified_registration_tournament_ids = ",".join( unified_registration_tournament_ids = ",".join(

View File

@@ -0,0 +1,34 @@
# Generated by Django 5.2.8 on 2025-11-06 18:53
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('participation', '0023_tournament_unified_registration'),
]
operations = [
migrations.AlterField(
model_name='passage',
name='solution_number',
field=models.PositiveSmallIntegerField(choices=[(1, 'Problem #1'), (2, 'Problem #2'), (3, 'Problem #3'), (4, 'Problem #4'), (5, 'Problem #5'), (6, 'Problem #6'), (7, 'Problem #7'), (8, 'Problem #8')], verbose_name='reported solution'),
),
migrations.AlterField(
model_name='pool',
name='round',
field=models.PositiveSmallIntegerField(choices=[(1, 'Round 1'), (2, 'Round 2')], verbose_name='round'),
),
migrations.AlterField(
model_name='solution',
name='problem',
field=models.PositiveSmallIntegerField(choices=[(1, 'Problem #1'), (2, 'Problem #2'), (3, 'Problem #3'), (4, 'Problem #4'), (5, 'Problem #5'), (6, 'Problem #6'), (7, 'Problem #7'), (8, 'Problem #8')], verbose_name='problem'),
),
migrations.AlterField(
model_name='team',
name='trigram',
field=models.CharField(help_text='The code must be composed of 3 uppercase letters.', max_length=4, unique=True, validators=[django.core.validators.RegexValidator('^[A-Z]{3}[A-Z]*$'), django.core.validators.RegexValidator('^(?!BIT$|CNO$|CRO$|CUL$|FTG$|FCK$|FUC$|FUK$|FYS$|HIV$|IST$|MST$|KKK$|KYS$|SEX$)', message='This team code is forbidden.')], verbose_name='code'),
),
]

View File

@@ -220,7 +220,6 @@ class Team(models.Model):
""" """
return f"equipe-{slugify(self.trigram)}@{settings.SYMPA_HOST}" return f"equipe-{slugify(self.trigram)}@{settings.SYMPA_HOST}"
def create_mailing_list(self): def create_mailing_list(self):
""" """
Create a new Sympa mailing list to contact the team. Create a new Sympa mailing list to contact the team.

View File

@@ -251,8 +251,19 @@ class CoachRegistrationForm(forms.ModelForm):
""" """
A coach can tell its professional activity. A coach can tell its professional activity.
""" """
ACCOMPANYING_CONFIRM_CHOICES = [
("presence", _("I undertake to be present throughout the entire tournament weekend alongside the team (including overnight stays).")),
("rules", _("I undertake to respond to the team's (non-mathematical) problems and not to hesitate to discuss them with the tournament "
"organisers, who will be able to help.")),
("cancelling", _("In case of absence, I undertake to notify the organisers as soon as possible, providing a replacement if possible.")),
]
confirm_accompanying = forms.MultipleChoiceField(
required=False,
widget=forms.CheckboxSelectMultiple,
choices=ACCOMPANYING_CONFIRM_CHOICES,
label=_("Responsabilities of accompanying coaches")
)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@@ -261,9 +272,21 @@ class CoachRegistrationForm(forms.ModelForm):
class Meta: class Meta:
model = CoachRegistration model = CoachRegistration
fields = ('team', 'is_scientific_coach', 'is_accompanying_coach', 'gender', 'address', 'zip_code', 'city', 'country', 'phone_number', fields = ('team', 'is_scientific_coach', 'is_accompanying_coach', 'confirm_accompanying', 'gender', 'address',
'last_degree', 'professional_activity', 'health_issues', 'housing_constraints', 'zip_code', 'city', 'country', 'phone_number', 'last_degree', 'professional_activity', 'health_issues',
'give_contact_to_animath', 'email_confirmed') 'housing_constraints', 'give_contact_to_animath', 'email_confirmed')
def clean(self):
cleaned = super().clean()
if cleaned.get("is_accompanying_coach"):
selected = set(cleaned.get("confirm_accompanying") or [])
required = {key for key, _ in self.ACCOMPANYING_CONFIRM_CHOICES}
if selected != required:
self.add_error(
"confirm_accompanying",
_("Please tick all the required confirmations."),
)
return cleaned
class VolunteerRegistrationForm(forms.ModelForm): class VolunteerRegistrationForm(forms.ModelForm):

View File

@@ -14,6 +14,8 @@ from django.urls import reverse, reverse_lazy
from django.utils import timezone, translation from django.utils import timezone, translation
from django.utils.crypto import get_random_string from django.utils.crypto import get_random_string
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
from django.utils.functional import lazy
from django.utils.html import format_html
from django.utils.http import urlsafe_base64_encode from django.utils.http import urlsafe_base64_encode
from django.utils.text import format_lazy from django.utils.text import format_lazy
from django.utils.timezone import localtime from django.utils.timezone import localtime
@@ -22,7 +24,8 @@ from phonenumber_field.modelfields import PhoneNumberField
from polymorphic.models import PolymorphicModel from polymorphic.models import PolymorphicModel
from tfjm import helloasso from tfjm import helloasso
from tfjm.tokens import email_validation_token from tfjm.tokens import email_validation_token
from django.utils.html import format_html
format_html_lazy = lazy(format_html, str)
class Registration(PolymorphicModel): class Registration(PolymorphicModel):
@@ -531,7 +534,7 @@ class CoachRegistration(ParticipantRegistration):
is_scientific_coach = models.BooleanField( is_scientific_coach = models.BooleanField(
default=False, default=False,
verbose_name=_("Scientific coach"), verbose_name=_("Scientific coach"),
help_text=format_html( help_text=format_html_lazy(
'{} <a href="{}" target="_blank" rel="noopener">{}</a>.', '{} <a href="{}" target="_blank" rel="noopener">{}</a>.',
_("Provides scientific guidance: methodology, content review, and project mentoring during the preparation phase."), _("Provides scientific guidance: methodology, content review, and project mentoring during the preparation phase."),
"https://tfjm.org/wp-content/uploads/2024/01/note____l_intention_des_encadrants.pdf", "https://tfjm.org/wp-content/uploads/2024/01/note____l_intention_des_encadrants.pdf",
@@ -542,7 +545,12 @@ class CoachRegistration(ParticipantRegistration):
is_accompanying_coach = models.BooleanField( is_accompanying_coach = models.BooleanField(
default=False, default=False,
verbose_name=_("Accompanying coach"), verbose_name=_("Accompanying coach"),
help_text=_("Accompanies the team during the weekend and stays for the entire tournament."), help_text=format_html_lazy(
'{} <a href="{}" target="_blank" rel="noopener">{}</a>.',
_("Accompanies the team during the weekend and stays for the entire tournament."),
"https://tfjm.org/wp-content/uploads/2025/11/Fiches_pratiques_TFJM2.pdf",
_("see practical sheet"),
)
) )
@property @property

View File

@@ -51,15 +51,33 @@
<script> <script>
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
let role_elem = document.getElementById("id_role") let role_elem = document.getElementById("id_role")
function setup_requirements() {
const main = document.getElementById('id_is_accompanying_coach');
const group = document.getElementById('div_id_confirm_accompanying');
function toggle(){
if(main.checked) {
group.style.display = "block";
} else {
group.style.display = "none";
}
}
main.addEventListener('change', toggle);
toggle();
}
function updateView () { function updateView () {
let selected_role = role_elem.options[role_elem.selectedIndex].value let selected_role = role_elem.options[role_elem.selectedIndex].value
if (selected_role === "participant") if (selected_role === "participant")
document.getElementById("registration_form").innerHTML = document.getElementById("student_registration_form").innerHTML document.getElementById("registration_form").innerHTML = document.getElementById("student_registration_form").innerHTML
else else
document.getElementById("registration_form").innerHTML = document.getElementById("coach_registration_form").innerHTML document.getElementById("registration_form").innerHTML = document.getElementById("coach_registration_form").innerHTML
setup_requirements();
} }
role_elem.addEventListener('change', updateView) role_elem.addEventListener('change', updateView)
updateView() updateView()
}) })
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -385,19 +385,19 @@ if TFJM_APP == "TFJM":
RULES_LINK = "https://tfjm.org/reglement" RULES_LINK = "https://tfjm.org/reglement"
REGISTRATION_DATES = dict( REGISTRATION_DATES = dict(
open=datetime.fromisoformat("2025-01-15T12:00:00+0100"), open=datetime.fromisoformat("2025-11-12T00:00:00+0100"),
close=datetime.fromisoformat("2025-03-02T22:00:00+0100"), close=datetime.fromisoformat("2026-01-08T22:00:00+0100"),
) )
PROBLEMS = [ PROBLEMS = [
"Une bonne humeur contagieuse", "Guerre à l'apéro",
"Drôles de toboggans", "Jeu du moulin",
"Plats à tarte gradués", "Poison dans les boissons",
"Transformation de papillons", "Colliers de perles",
"Gerrymandering", "Parcours d'escalade",
"Le cauchemar de la ligne 20-25", "Malaise dans la salle d'attente",
"Taxes routières", "Double et chiffres",
"Points colorés sur un cercle", "Tri trop rapide",
] ]
elif TFJM_APP == "ETEAM": elif TFJM_APP == "ETEAM":
PREFERRED_LANGUAGE_CODE = 'en' PREFERRED_LANGUAGE_CODE = 'en'

View File

@@ -1,4 +1,12 @@
<div id="messages"> <div id="messages">
<div class="alert alert-info fade show" role="alert">
{% load i18n %}
<h2>{% trans "Dates pending" %}</h2>
<p>{% blocktrans %}Since the dates for the tournaments in Bordeaux, Rennes, Metz and Occitanie have not yet been set, we kindly invite the teams concerned to wait a little longer. If you wish, you may register for another tournament and send us an email to let us know of your interest; we will keep you informed as soon as the final dates are confirmed.
{% endblocktrans %}
</p>
</div>
{% for message in messages %} {% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert"> <div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>