online_registration
Raz 11 months ago
parent c70deac834
commit e6526cbb8f
  1. 2
      tournaments/forms.py
  2. 12
      tournaments/models/enums.py
  3. 3
      tournaments/models/team_registration.py
  4. 52
      tournaments/models/tournament.py
  5. 56
      tournaments/static/tournaments/css/style.css
  6. 8
      tournaments/templates/profile.html
  7. 18
      tournaments/templates/register_tournament.html
  8. 8
      tournaments/templates/tournaments/navigation_base.html
  9. 26
      tournaments/templates/tournaments/navigation_tournament.html
  10. 19
      tournaments/templates/tournaments/tournament_info.html
  11. 2
      tournaments/templates/tournaments/tournament_row.html
  12. 5
      tournaments/templates/tournaments/tournaments.html
  13. 39
      tournaments/views.py

@ -47,7 +47,7 @@ class SimpleForm(forms.Form):
class TournamentRegistrationForm(forms.Form): class TournamentRegistrationForm(forms.Form):
#first_name = forms.CharField(label='Prénom', max_length=50) #first_name = forms.CharField(label='Prénom', max_length=50)
#last_name = forms.CharField(label='Nom', max_length=50) #last_name = forms.CharField(label='Nom', max_length=50)
email = forms.EmailField(label='E-mail') email = forms.EmailField(label='E-mail', widget=forms.EmailInput(attrs={'readonly': 'readonly'}))
mobile_number = forms.CharField( mobile_number = forms.CharField(
label='Téléphone (facultatif)', label='Téléphone (facultatif)',
max_length=15, max_length=15,

@ -92,11 +92,10 @@ class OnlineRegistrationStatus(models.IntegerChoices):
NOT_ENABLED = 2, 'Not Enabled' NOT_ENABLED = 2, 'Not Enabled'
NOT_STARTED = 3, 'Not Started' NOT_STARTED = 3, 'Not Started'
ENDED = 4, 'Ended' ENDED = 4, 'Ended'
REGISTRATION_FULL = 5, 'Registration Full' WAITING_LIST_POSSIBLE = 5, 'Waiting List Possible'
WAITING_LIST_POSSIBLE = 6, 'Waiting List Possible' WAITING_LIST_FULL = 6, 'Waiting List Full'
WAITING_LIST_FULL = 7, 'Waiting List Full' IN_PROGRESS = 7, 'In Progress'
IN_PROGRESS = 8, 'In Progress' ENDED_WITH_RESULTS = 8, 'Ended with Results'
ENDED_WITH_RESULTS = 9, 'Ended with Results'
def status_localized(self) -> str: def status_localized(self) -> str:
status_map = { status_map = {
@ -104,8 +103,7 @@ class OnlineRegistrationStatus(models.IntegerChoices):
OnlineRegistrationStatus.NOT_ENABLED: "Inscription désactivée", OnlineRegistrationStatus.NOT_ENABLED: "Inscription désactivée",
OnlineRegistrationStatus.NOT_STARTED: "Inscription pas encore ouverte", OnlineRegistrationStatus.NOT_STARTED: "Inscription pas encore ouverte",
OnlineRegistrationStatus.ENDED: "Inscription terminée", OnlineRegistrationStatus.ENDED: "Inscription terminée",
OnlineRegistrationStatus.REGISTRATION_FULL: "Inscription complète", OnlineRegistrationStatus.WAITING_LIST_POSSIBLE: "Liste d'attente ouverte",
OnlineRegistrationStatus.WAITING_LIST_POSSIBLE: "Liste d'attente disponible",
OnlineRegistrationStatus.WAITING_LIST_FULL: "Liste d'attente complète", OnlineRegistrationStatus.WAITING_LIST_FULL: "Liste d'attente complète",
OnlineRegistrationStatus.IN_PROGRESS: "Tournoi en cours", OnlineRegistrationStatus.IN_PROGRESS: "Tournoi en cours",
OnlineRegistrationStatus.ENDED_WITH_RESULTS: "Tournoi terminé" OnlineRegistrationStatus.ENDED_WITH_RESULTS: "Tournoi terminé"

@ -125,3 +125,6 @@ class TeamRegistration(models.Model):
if p != player: if p != player:
return p return p
return None return None
def is_in_waiting_list(self):
return self.tournament.get_team_waiting_list_position(self)

@ -200,7 +200,9 @@ class Tournament(models.Model):
def registration_count_display(self): def registration_count_display(self):
teams = self.teams(True) teams = self.teams(True)
if teams is not None and len(teams) > 0: if teams is not None and len(teams) == 1:
return f"{len(teams)} équipe inscrite"
elif teams is not None and len(teams) > 1:
return f"{len(teams)} équipes inscrites" return f"{len(teams)} équipes inscrites"
else: else:
return None return None
@ -295,6 +297,18 @@ class Tournament(models.Model):
rankings.sort(key=lambda r: r.ranking) rankings.sort(key=lambda r: r.ranking)
return rankings return rankings
def get_team_waiting_list_position(self, team_registration):
# Use the teams method to get sorted list of teams
all_teams = self.teams(True)
waiting_teams = [t for t in all_teams if t.stage == "Attente"]
# Find matching team in waiting list and return its index
for i, team in enumerate(waiting_teams):
if team.team_registration.id == team_registration.id:
return i
return -1 # Team not found in waiting list
def teams(self, includeWaitingList): def teams(self, includeWaitingList):
# print("Starting teams method") # print("Starting teams method")
bracket_teams = [] bracket_teams = []
@ -989,16 +1003,6 @@ class Tournament(models.Model):
if waiting_list_count >= self.waiting_list_limit: if waiting_list_count >= self.waiting_list_limit:
return OnlineRegistrationStatus.WAITING_LIST_FULL return OnlineRegistrationStatus.WAITING_LIST_FULL
return OnlineRegistrationStatus.WAITING_LIST_POSSIBLE return OnlineRegistrationStatus.WAITING_LIST_POSSIBLE
return OnlineRegistrationStatus.REGISTRATION_FULL
current_team_count = self.teamregistration_set.filter(walk_out=False).count()
if current_team_count >= self.target_team_count:
if self.waiting_list_limit is not None:
waiting_list_count = current_team_count - self.target_team_count
if waiting_list_count >= self.waiting_list_limit:
return OnlineRegistrationStatus.WAITING_LIST_FULL
return OnlineRegistrationStatus.WAITING_LIST_POSSIBLE
return OnlineRegistrationStatus.REGISTRATION_FULL
return OnlineRegistrationStatus.OPEN return OnlineRegistrationStatus.OPEN
def is_unregistration_possible(self): def is_unregistration_possible(self):
@ -1021,8 +1025,34 @@ class Tournament(models.Model):
# Otherwise unregistration is allowed # Otherwise unregistration is allowed
return True return True
def get_waiting_list_position(self):
# If no target team count exists, no one goes to waiting list
if self.target_team_count is None:
return -1
# Get count of active teams (not walked out)
current_team_count = len([tr for tr in self.teamregistration_set.all() if tr.out_of_tournament() is False])
# If current count is less than target count, next team is not in waiting list
if current_team_count < self.target_team_count:
return -1
# If we have a waiting list limit
if self.waiting_list_limit is not None:
waiting_list_count = current_team_count - self.target_team_count
# If waiting list is full
if waiting_list_count >= self.waiting_list_limit:
return -1
# Return waiting list position
return waiting_list_count
# In waiting list with no limit
return current_team_count - self.target_team_count
def build_tournament_details_str(self): def build_tournament_details_str(self):
tournament_details = [] tournament_details = []
if self.federal_level_category > 0:
tournament_details.append(self.level()) tournament_details.append(self.level())
if self.category(): if self.category():
tournament_details.append(self.category()) tournament_details.append(self.category())

@ -82,6 +82,26 @@ nav a {
font-weight: 600; font-weight: 600;
} }
nav a.orange {
color: white;
background-color: #f39200;
}
nav a.orange:hover {
color: #1b223a; /* Same text color on hover */
text-decoration: none; /* Prevent underline on <a> hover */
}
nav a.red {
color: white;
background-color: #e84038;
}
nav a.red:hover {
color: white; /* Same text color on hover */
background-color: #1b223a;
}
hr { hr {
margin: 2px 0px; margin: 2px 0px;
} }
@ -323,7 +343,7 @@ tr {
} }
.red { .red {
background-color: red; background-color: #e84038;
} }
svg { svg {
@ -712,7 +732,7 @@ h-margin {
} }
.alert { .alert {
color: red; /* Make the text red */ color: #e84038; /* Make the text red */
font-weight: bold; /* Optional: Make the text bold */ font-weight: bold; /* Optional: Make the text bold */
} }
@ -725,35 +745,3 @@ h-margin {
background-color: #cc0000; /* Darker red on hover */ background-color: #cc0000; /* Darker red on hover */
color: white; /* White text on hover */ color: white; /* White text on hover */
} }
.top-link {
display: block;
text-align: center;
margin-top: 10px;
font-style: italic;
text-decoration: underline;
}
.login-buttons {
position: relative;
display: flex;
margin-left: 10px;
gap: 10px;
padding: 0px;
}
.login-buttons .button {
display: block;
padding: 8px 8px;
border: none;
background: none;
border-radius: 4px;
text-align: center;
text-decoration: underline;
color: #333;
transition: background 0.2s;
}
.login-buttons .button:hover {
background: #f39200;
}

@ -6,12 +6,12 @@
{% block content %} {% block content %}
<nav class="margin10"> <nav class="margin10">
<a href="{% url 'index' %}">Accueil</a> <a href="{% url 'index' %}" class="orange">Accueil</a>
<a href="{% url 'clubs' %}">Clubs</a> <a href="{% url 'clubs' %}" class="orange">Clubs</a>
{% if user.is_authenticated %} {% if user.is_authenticated %}
<a href="{% url 'my-tournaments' %}">Mes tournois</a> <a href="{% url 'my-tournaments' %}" class="orange">Mes tournois</a>
<a href="{% url 'profile' %}">Mon compte</a> <a href="{% url 'profile' %}">Mon compte</a>
<a href="{% url 'logout' %}">Se déconnecter</a> <a href="{% url 'logout' %}" class="red">Se déconnecter</a>
{% else %} {% else %}
<a href="{% url 'login' %}">Se connecter</a> <a href="{% url 'login' %}">Se connecter</a>
{% endif %} {% endif %}

@ -110,8 +110,24 @@
{% if current_players|length >= tournament.minimum_player_per_team %} {% if current_players|length >= tournament.minimum_player_per_team %}
<div class="margin10"> <div class="margin10">
</div> </div>
<div class="semibold margin10">
{% if tournament.get_waiting_list_position == 1 %}
{{ tournament.get_waiting_list_position }} équipe en liste d'attente devant vous
{% elif tournament.get_waiting_list_position > 1 %}
{{ tournament.get_waiting_list_position }} équipes en liste d'attente devant vous
{% elif tournament.get_waiting_list_position == 0 %}
Aucune équipe en liste d'attente devant vous
{% endif %}
</div>
<div> <div>
<button type="submit" name="register_team" class="rounded-button">Confirmer l'inscription</button> <button type="submit" name="register_team" class="rounded-button">
{% if tournament.get_waiting_list_position < 0 %}
Confirmer l'inscription
{% else %}
Se mettre en liste d'attente
{% endif %}
</button>
</div> </div>
{% endif %} {% endif %}
</form> </form>

@ -1,11 +1,13 @@
<nav class="margin10"> <nav class="margin10">
<a href="{% url 'index' %}">Accueil</a> <a href="{% url 'index' %}" class="orange">Accueil</a>
<a href="{% url 'clubs' %}">Clubs</a> <a href="{% url 'clubs' %}" class="orange">Clubs</a>
{% if user.is_authenticated %} {% if user.is_authenticated %}
<a href="{% url 'my-tournaments' %}">Mes tournois</a> <a href="{% url 'my-tournaments' %}" class="orange">Mes tournois</a>
<a href="{% url 'profile' %}">Mon compte</a> <a href="{% url 'profile' %}">Mon compte</a>
{% else %} {% else %}
<a href="{% url 'login' %}">Se connecter</a> <a href="{% url 'login' %}">Se connecter</a>
{% endif %} {% endif %}
<a href="{% url 'download' %}">Ajouter vos tournois</a>
</nav> </nav>

@ -1,32 +1,30 @@
<nav class="margin10">
{% if user.is_authenticated %}
<a href="{% url 'profile' %}">Mon compte</a>
{% else %}
<a href="{% url 'login' %}">Se connecter</a>
{% endif %}
</nav>
<nav class="margin10"> <nav class="margin10">
<a href="{% url 'tournament-info' tournament.id %}" class="topmargin5">Informations</a> <a href="{% url 'tournament-info' tournament.id %}" class="topmargin5 orange">Informations</a>
{% if tournament.display_matches or tournament.display_group_stages %} {% if tournament.display_matches or tournament.display_group_stages %}
<a href="{% url 'tournament' tournament.id %}" class="topmargin5">Matches</a> <a href="{% url 'tournament' tournament.id %}" class="topmargin5 orange">Matches</a>
{% endif %} {% endif %}
{% if tournament.display_group_stages %} {% if tournament.display_group_stages %}
<a href="{% url 'group-stages' tournament.id %}" class="topmargin5">Poules</a> <a href="{% url 'group-stages' tournament.id %}" class="topmargin5 orange">Poules</a>
{% endif %} {% endif %}
{% if tournament.display_summons %} {% if tournament.display_summons %}
<a href="{% url 'tournament-summons' tournament.id %}" class="topmargin5">Convocations</a> <a href="{% url 'tournament-summons' tournament.id %}" class="topmargin5 orange">Convocations</a>
{% endif %} {% endif %}
{% if tournament.display_teams %} {% if tournament.display_teams %}
<a href="{% url 'tournament-teams' tournament.id %}" class="topmargin5">Équipes</a> <a href="{% url 'tournament-teams' tournament.id %}" class="topmargin5 orange">Équipes</a>
{% endif %} {% endif %}
{% if tournament.display_rankings %} {% if tournament.display_rankings %}
<a href="{% url 'tournament-rankings' tournament.id %}" class="topmargin5">Classement</a> <a href="{% url 'tournament-rankings' tournament.id %}" class="topmargin5 orange">Classement</a>
{% endif %}
{% if user.is_authenticated %}
<a href="{% url 'profile' %}" class="topmargin5">Mon compte</a>
{% else %}
<a href="{% url 'login' %}" class="topmargin5">Se connecter</a>
{% endif %} {% endif %}
</nav> </nav>

@ -117,6 +117,19 @@
<h1 class="club my-block topmargin20">Votre équipe</h1 > <h1 class="club my-block topmargin20">Votre équipe</h1 >
<div class="bubble"> <div class="bubble">
<div class="semibold">
{% if team.is_in_waiting_list >= 0 %}
Vous êtes en liste d'attente.
{% if team.is_in_waiting_list == 1 %}
{{ tournament.get_waiting_list_position }} équipe en liste d'attente devant vous
{% elif tournament.get_waiting_list_position > 1 %}
{{ tournament.get_waiting_list_position }} équipes en liste d'attente devant vous
{% elif tournament.get_waiting_list_position == 0 %}
Aucune équipe en liste d'attente devant vous
{% endif %}
{% endif %}
</div>
<p> <p>
<div class="semibold"> <div class="semibold">
{% for player in team.players %} {% for player in team.players %}
@ -125,7 +138,7 @@
</div> </div>
</p> </p>
<p> <p>
<div>Inscrit le {{ team.registration_date }}</div> <div>Inscrits le {{ team.registration_date }}</div>
</p> </p>
{% if tournament.is_unregistration_possible %} {% if tournament.is_unregistration_possible %}
@ -140,7 +153,11 @@
<a href="{% url 'unregister_tournament' tournament.id %}" <a href="{% url 'unregister_tournament' tournament.id %}"
class="rounded-button destructive-button" class="rounded-button destructive-button"
onclick="return confirm('Êtes-vous sûr de vouloir vous désinscrire ?');"> onclick="return confirm('Êtes-vous sûr de vouloir vous désinscrire ?');">
{% if team.is_in_waiting_list >= 0 %}
Se retirer de la liste d'attente
{% else %}
Se désinscrire Se désinscrire
{% endif %}
</a> </a>
</p> </p>

@ -26,7 +26,7 @@
</div> </div>
{% if tournament.tournament_status_display %} {% if tournament.tournament_status_display %}
<div class="table-cell-responsive-large center horizontal-padding"> <div class="table-cell-responsive-large right horizontal-padding">
{{ tournament.tournament_status_display|linebreaksbr }} {{ tournament.tournament_status_display|linebreaksbr }}
</div> </div>
{% endif %} {% endif %}

@ -6,11 +6,6 @@
{% block right_header %} {% block right_header %}
<div class="medium-6 large-3 cell topblock my-block flex">
<div class="right-content w300px">
<a href="{% url 'download' %}" class="large_button">Téléchargez l'app pour organiser vos tournois !</a>
</div>
</div>
{% endblock %} {% endblock %}
{% block content %} {% block content %}

@ -133,7 +133,9 @@ def tournament_info(request, tournament_id):
# Check if there is a PlayerRegistration for this user in this tournament # Check if there is a PlayerRegistration for this user in this tournament
registered_user = PlayerRegistration.objects.filter( registered_user = PlayerRegistration.objects.filter(
licence_id__startswith=stripped_license, licence_id__startswith=stripped_license,
team_registration__tournament=tournament team_registration__tournament=tournament,
team_registration__walk_out=False,
team_registration__unregistered=False,
).first() ).first()
# If the user is registered, retrieve their team registration # If the user is registered, retrieve their team registration
@ -716,6 +718,7 @@ def register_tournament(request, tournament_id):
# Check if the team registration form is valid and finalize the registration # Check if the team registration form is valid and finalize the registration
elif 'register_team' in request.POST and team_form.is_valid(): elif 'register_team' in request.POST and team_form.is_valid():
waiting_list_position = tournament.get_waiting_list_position()
registration_date = timezone.now().replace(microsecond=0) registration_date = timezone.now().replace(microsecond=0)
team_registration = TeamRegistration.objects.create( team_registration = TeamRegistration.objects.create(
tournament=tournament, tournament=tournament,
@ -777,17 +780,28 @@ def register_tournament(request, tournament_id):
# Send confirmation email # Send confirmation email
tournament_details_str = tournament.build_tournament_details_str() tournament_details_str = tournament.build_tournament_details_str()
name_str = tournament.build_name_details_str() name_str = tournament.build_name_details_str()
email_subject = f"Confirmation d'inscription au {tournament_details_str}{name_str}"
email_subject = f"Confirmation d'inscription au tournoi {tournament_details_str}{name_str}"
if waiting_list_position >= 0:
email_subject = f"En liste d'attente du tournoi {tournament_details_str}{name_str}"
inscription_date = timezone.now().strftime("%d/%m/%Y à %H:%M") inscription_date = timezone.now().strftime("%d/%m/%Y à %H:%M")
team_members = [player.name() for player in team_registration.playerregistration_set.all()] team_members = [player.name() for player in team_registration.playerregistration_set.all()]
team_members_str = " et ".join(team_members) team_members_str = " et ".join(team_members)
email_body = f"Bonjour,\n\nVotre inscription au tournoi {tournament_details_str}{name_str} est confirmée."
email_body = f"Bonjour,\n\nVotre inscription au tournoi{tournament_details_str}{name_str} est confirmée."
if tournament.get_waiting_list_position() >= 0:
email_body = f"Bonjour,\n\nVotre inscription en liste d'attente du tournoi{tournament_details_str}{name_str} est confirmée."
email_body += f"\n\nDate d'inscription: {inscription_date}" email_body += f"\n\nDate d'inscription: {inscription_date}"
email_body += f"\n\nÉquipe inscrite: {team_members_str}" email_body += f"\n\nÉquipe inscrite: {team_members_str}"
email_body += f"\n\nLe tournoi commencera le {tournament.start_date.strftime('%d/%m/%Y')}" email_body += f"\n\nLe tournoi commencera le {tournament.start_date.strftime('%d/%m/%Y')}"
email_body += f" @ {tournament.event.club.name}" email_body += f" @ {tournament.event.club.name}"
email_body += f"\n\nVoir les informations sur {request.build_absolute_uri(f'/tournament/{tournament.id}/')}" email_body += f"\n\nVoir les informations sur {request.build_absolute_uri(f'/tournament/{tournament.id}/')}"
email_body += "\n\nPour toute question, veuillez contacter votre juge-arbitre. Si vous n'êtes pas à l'origine de cette inscription, merci de le contacter rapidement.\nCeci est un e-mail automatique, veuillez ne pas y répondre." email_body += "\n\nPour toute question, veuillez contacter votre juge-arbitre. Si vous n'êtes pas à l'origine de cette inscription, merci de le contacter rapidement."
email_body += f"\n{tournament.event.creator.full_name()}\n{tournament.event.creator.email}"
email_body += "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre."
email_body += "\n\nCordialement,\n\nPadel Club" email_body += "\n\nCordialement,\n\nPadel Club"
@ -876,7 +890,9 @@ def unregister_tournament(request, tournament_id):
player_registration = PlayerRegistration.objects.filter( player_registration = PlayerRegistration.objects.filter(
licence_id__startswith=user_licence_id, licence_id__startswith=user_licence_id,
team_registration__tournament_id=tournament_id team_registration__tournament_id=tournament_id,
team_registration__walk_out=False,
team_registration__unregistered=False,
).first() # Get the first match, if any ).first() # Get the first match, if any
@ -884,7 +900,9 @@ def unregister_tournament(request, tournament_id):
if player_registration: if player_registration:
team_registration = player_registration.team_registration # Get the related TeamRegistration team_registration = player_registration.team_registration # Get the related TeamRegistration
other_player = team_registration.get_other_player(player_registration) other_player = team_registration.get_other_player(player_registration)
team_registration.delete() # Delete the team registration team_registration.unregistered = True # Delete the team registration
team_registration.unregistration_date = timezone.now()
team_registration.save()
else: else:
messages.error(request, "La désincription a échouée. Veuillez contacter le juge-arbitre.") messages.error(request, "La désincription a échouée. Veuillez contacter le juge-arbitre.")
return redirect('tournament-info', tournament_id=tournament_id) return redirect('tournament-info', tournament_id=tournament_id)
@ -894,17 +912,18 @@ def unregister_tournament(request, tournament_id):
if tournament and request.user.email: # Ensure we have valid tournament and user email if tournament and request.user.email: # Ensure we have valid tournament and user email
tournament_details_str = tournament.build_tournament_details_str() tournament_details_str = tournament.build_tournament_details_str()
name_str = tournament.build_name_details_str() name_str = tournament.build_name_details_str()
email_subject = f"Confirmation de désistement au {tournament_details_str}{name_str}" email_subject = f"Confirmation de désistement du tournoi{tournament_details_str}{name_str}"
email_body = f"Bonjour,\n\nVous venez de vous désinscrire du tournoi {tournament_details_str}{name_str}" email_body = f"Bonjour,\n\nVous venez de vous désinscrire du tournoi{tournament_details_str}{name_str}"
email_body += f" du {tournament.start_date.strftime('%d/%m/%Y')}" email_body += f" du {tournament.start_date.strftime('%d/%m/%Y')}"
email_body += f" au {tournament.event.club.name}" email_body += f" au {tournament.event.club.name}"
if other_player is not None: if other_player is not None:
email_body += f"\n\nVous étiez inscrit avec {other_player.name()}, n'oubliez pas de prévenir votre partenaire." email_body += f"\n\nVous étiez inscrit avec {other_player.name()}, n'oubliez pas de prévenir votre partenaire."
email_body += f"\n\nVoir les informations sur {request.build_absolute_uri(f'/tournament/{tournament.id}/')}" email_body += f"\n\nVoir les informations sur {request.build_absolute_uri(f'/tournament/{tournament.id}/')}"
email_body += "\n\nPour toute question, veuillez contacter votre juge-arbitre. Si vous n'êtes pas à l'origine de ce désistement, merci de le contacter rapidement.\nCeci est un e-mail automatique, veuillez ne pas y répondre." email_body += "\n\nPour toute question, veuillez contacter votre juge-arbitre. Si vous n'êtes pas à l'origine de cette inscription, merci de le contacter rapidement."
email_body += "\n\nCordialement,\n\nPadel Club." email_body += f"\n{tournament.event.creator.full_name()}\n{tournament.event.creator.email}"
email_body += "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre."
email = EmailMessage( email = EmailMessage(
subject=email_subject, subject=email_subject,

Loading…
Cancel
Save