|
|
|
@ -1,58 +1,53 @@ |
|
|
|
# Standard library imports |
|
|
|
# Standard library imports |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from django.contrib import messages |
|
|
|
|
|
|
|
from django.contrib.auth.mixins import LoginRequiredMixin |
|
|
|
|
|
|
|
from django.contrib.auth import login, get_user_model, logout, update_session_auth_hash |
|
|
|
|
|
|
|
from django.contrib.auth.views import PasswordResetCompleteView, PasswordResetConfirmView |
|
|
|
|
|
|
|
from django.contrib.sites.shortcuts import get_current_site |
|
|
|
|
|
|
|
from django.contrib.auth.decorators import login_required |
|
|
|
|
|
|
|
from django.contrib.admin.views.decorators import staff_member_required |
|
|
|
|
|
|
|
from django.shortcuts import redirect, render, get_object_or_404 |
|
|
|
|
|
|
|
from django.utils import timezone, formats |
|
|
|
|
|
|
|
from django.utils.encoding import force_str, force_bytes |
|
|
|
|
|
|
|
from django.utils.http import urlsafe_base64_decode |
|
|
|
|
|
|
|
from django.http import JsonResponse, HttpResponse, Http404 |
|
|
|
|
|
|
|
from django.urls import reverse, reverse_lazy |
|
|
|
|
|
|
|
from django.conf import settings |
|
|
|
|
|
|
|
from django.db.models import Q |
|
|
|
|
|
|
|
from django.views.generic import View |
|
|
|
|
|
|
|
from django.views.generic.edit import UpdateView |
|
|
|
|
|
|
|
from django.views.decorators.csrf import csrf_protect, csrf_exempt |
|
|
|
|
|
|
|
from django.template.loader import render_to_string |
|
|
|
|
|
|
|
from django.core.mail import EmailMessage |
|
|
|
|
|
|
|
from django.core.exceptions import ValidationError |
|
|
|
|
|
|
|
from django.core.files.storage import default_storage |
|
|
|
|
|
|
|
from django.core.files.base import ContentFile |
|
|
|
|
|
|
|
|
|
|
|
import os |
|
|
|
import os |
|
|
|
import csv |
|
|
|
import csv |
|
|
|
|
|
|
|
import locale |
|
|
|
|
|
|
|
import calendar |
|
|
|
|
|
|
|
|
|
|
|
from api.serializers import GroupStageSerializer, MatchSerializer, PlayerRegistrationSerializer, TeamRegistrationSerializer, TeamScoreSerializer |
|
|
|
from api.serializers import GroupStageSerializer, MatchSerializer, PlayerRegistrationSerializer, TeamRegistrationSerializer, TeamScoreSerializer |
|
|
|
from django.contrib.auth.mixins import LoginRequiredMixin |
|
|
|
|
|
|
|
from django.contrib.auth import logout |
|
|
|
|
|
|
|
from .utils.extensions import is_not_sqlite_backend |
|
|
|
from .utils.extensions import is_not_sqlite_backend |
|
|
|
import stripe |
|
|
|
import stripe |
|
|
|
|
|
|
|
|
|
|
|
from django.contrib.auth import update_session_auth_hash |
|
|
|
from .models import Club, Tournament, CustomUser, Event, Round, Match, TeamScore, TeamRegistration, PlayerRegistration, UserOrigin |
|
|
|
from django.contrib.auth.views import PasswordResetCompleteView |
|
|
|
|
|
|
|
from django.shortcuts import redirect |
|
|
|
|
|
|
|
from django.contrib.auth import login |
|
|
|
|
|
|
|
from django.contrib.auth import get_user_model |
|
|
|
|
|
|
|
from django.shortcuts import render, get_object_or_404 |
|
|
|
|
|
|
|
from django.http import JsonResponse, HttpResponse |
|
|
|
|
|
|
|
from django.utils.encoding import force_str |
|
|
|
|
|
|
|
from django.utils.http import urlsafe_base64_decode |
|
|
|
|
|
|
|
from django.urls import reverse |
|
|
|
|
|
|
|
from django.conf import settings |
|
|
|
|
|
|
|
from django.contrib.admin.views.decorators import staff_member_required |
|
|
|
|
|
|
|
from django.views.generic import View |
|
|
|
|
|
|
|
from django.db.models import Q |
|
|
|
|
|
|
|
from .models import Club, Tournament, CustomUser, Event, Round, Match, TeamScore, TeamRegistration, PlayerRegistration, UserOrigin, Purchase |
|
|
|
|
|
|
|
from datetime import datetime, timedelta |
|
|
|
from datetime import datetime, timedelta |
|
|
|
import time |
|
|
|
import time |
|
|
|
import json |
|
|
|
import json |
|
|
|
import asyncio |
|
|
|
import asyncio |
|
|
|
import zipfile |
|
|
|
import zipfile |
|
|
|
import pandas as pd |
|
|
|
import pandas as pd |
|
|
|
from tournaments.utils.extensions import create_random_filename |
|
|
|
|
|
|
|
from django.core.files.storage import default_storage |
|
|
|
|
|
|
|
from django.core.files.base import ContentFile |
|
|
|
|
|
|
|
from django.utils import formats |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from tournaments.utils.extensions import create_random_filename |
|
|
|
from api.tokens import account_activation_token |
|
|
|
from api.tokens import account_activation_token |
|
|
|
|
|
|
|
|
|
|
|
# Third-party imports |
|
|
|
|
|
|
|
from qr_code.qrcode.utils import QRCodeOptions |
|
|
|
from qr_code.qrcode.utils import QRCodeOptions |
|
|
|
|
|
|
|
|
|
|
|
# Django imports |
|
|
|
|
|
|
|
from django.http import Http404 |
|
|
|
|
|
|
|
from django.urls import reverse_lazy |
|
|
|
|
|
|
|
from django.utils import timezone |
|
|
|
|
|
|
|
from django.utils.encoding import force_bytes |
|
|
|
|
|
|
|
from django.utils.http import urlsafe_base64_encode |
|
|
|
|
|
|
|
from django.template.loader import render_to_string |
|
|
|
|
|
|
|
from django.contrib import messages |
|
|
|
|
|
|
|
from django.contrib.sites.shortcuts import get_current_site |
|
|
|
|
|
|
|
from django.contrib.auth.decorators import login_required |
|
|
|
|
|
|
|
from django.contrib.auth.views import PasswordResetConfirmView |
|
|
|
|
|
|
|
from django.core.mail import EmailMessage |
|
|
|
|
|
|
|
from django.views.decorators.csrf import csrf_protect |
|
|
|
|
|
|
|
from .services.tournament_unregistration import TournamentUnregistrationService |
|
|
|
from .services.tournament_unregistration import TournamentUnregistrationService |
|
|
|
from django.core.exceptions import ValidationError |
|
|
|
|
|
|
|
from .forms import ( |
|
|
|
from .forms import ( |
|
|
|
ProfileUpdateForm, |
|
|
|
ProfileUpdateForm, |
|
|
|
SimpleCustomUserCreationForm, |
|
|
|
SimpleCustomUserCreationForm, |
|
|
|
@ -62,12 +57,11 @@ from .forms import ( |
|
|
|
) |
|
|
|
) |
|
|
|
from .utils.apns import send_push_notification |
|
|
|
from .utils.apns import send_push_notification |
|
|
|
from .utils.licence_validator import LicenseValidator |
|
|
|
from .utils.licence_validator import LicenseValidator |
|
|
|
from django.views.generic.edit import UpdateView |
|
|
|
|
|
|
|
from .forms import CustomPasswordChangeForm |
|
|
|
from .forms import CustomPasswordChangeForm |
|
|
|
from .services.email_service import TournamentEmailService |
|
|
|
from .services.email_service import TournamentEmailService |
|
|
|
from .services.tournament_registration import RegistrationCartManager |
|
|
|
from .services.tournament_registration import RegistrationCartManager |
|
|
|
from .services.payment_service import PaymentService |
|
|
|
from .services.payment_service import PaymentService |
|
|
|
from django.views.decorators.csrf import csrf_exempt |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import logging |
|
|
|
import logging |
|
|
|
|
|
|
|
|
|
|
|
@ -171,6 +165,60 @@ def future_tournaments(club_id, limit=None): |
|
|
|
tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True, limit) |
|
|
|
tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True, limit) |
|
|
|
return [t for t in tournaments if t.display_tournament() and t.starts_in_the_future()] |
|
|
|
return [t for t in tournaments if t.display_tournament() and t.starts_in_the_future()] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def future_tournaments_by_month(club_id, year, month): |
|
|
|
|
|
|
|
"""Get future tournaments filtered by year and month""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f'filter {year} {month}') |
|
|
|
|
|
|
|
tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True) |
|
|
|
|
|
|
|
filtered_tournaments = [] |
|
|
|
|
|
|
|
for t in tournaments: |
|
|
|
|
|
|
|
if (t.display_tournament() and t.starts_in_the_future() and |
|
|
|
|
|
|
|
t.start_date.year == year and t.start_date.month == month + 1): |
|
|
|
|
|
|
|
filtered_tournaments.append(t) |
|
|
|
|
|
|
|
return filtered_tournaments |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def finished_tournaments_by_month(club_id, year, month): |
|
|
|
|
|
|
|
"""Get finished tournaments filtered by year and month""" |
|
|
|
|
|
|
|
clean_ended_tournaments = tournaments_query(Q(end_date__isnull=False), club_id, False) |
|
|
|
|
|
|
|
clean_ended_tournaments = [t for t in clean_ended_tournaments if t.display_tournament()] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
one_day_ago = timezone.now() - timedelta(days=1) |
|
|
|
|
|
|
|
ended_tournaments = tournaments_query( |
|
|
|
|
|
|
|
Q(end_date__isnull=True, start_date__lt=one_day_ago), |
|
|
|
|
|
|
|
club_id, |
|
|
|
|
|
|
|
False |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
ended_tournaments = [t for t in ended_tournaments if t.display_tournament() and t.should_be_over()] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Combine both lists |
|
|
|
|
|
|
|
all_tournaments = clean_ended_tournaments + ended_tournaments |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Filter by year and month |
|
|
|
|
|
|
|
filtered_tournaments = [] |
|
|
|
|
|
|
|
for t in all_tournaments: |
|
|
|
|
|
|
|
if t.start_date.year == year and t.start_date.month == month: |
|
|
|
|
|
|
|
filtered_tournaments.append(t) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Sort by start_date descending |
|
|
|
|
|
|
|
filtered_tournaments.sort(key=lambda t: t.start_date, reverse=True) |
|
|
|
|
|
|
|
return filtered_tournaments |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_available_years_for_tournaments(club_id, filter_type): |
|
|
|
|
|
|
|
"""Get available years for tournaments based on filter type""" |
|
|
|
|
|
|
|
if filter_type == 0: # Future tournaments |
|
|
|
|
|
|
|
tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True) |
|
|
|
|
|
|
|
tournaments = [t for t in tournaments if t.display_tournament() and t.starts_in_the_future()] |
|
|
|
|
|
|
|
elif filter_type == 2: # Finished tournaments |
|
|
|
|
|
|
|
tournaments = finished_tournaments(club_id) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
return [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
years = set() |
|
|
|
|
|
|
|
for t in tournaments: |
|
|
|
|
|
|
|
years.add(t.start_date.year) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return sorted(years, reverse=(filter_type == 2)) |
|
|
|
|
|
|
|
|
|
|
|
def tournament_info(request, tournament_id): |
|
|
|
def tournament_info(request, tournament_id): |
|
|
|
tournament = get_object_or_404(Tournament, pk=tournament_id) |
|
|
|
tournament = get_object_or_404(Tournament, pk=tournament_id) |
|
|
|
registered_user = None |
|
|
|
registered_user = None |
|
|
|
@ -217,18 +265,45 @@ def tournaments(request): |
|
|
|
return redirect('/') |
|
|
|
return redirect('/') |
|
|
|
|
|
|
|
|
|
|
|
club_id = request.GET.get('club') |
|
|
|
club_id = request.GET.get('club') |
|
|
|
|
|
|
|
year_param = request.GET.get('year') |
|
|
|
|
|
|
|
month_param = request.GET.get('month') |
|
|
|
|
|
|
|
|
|
|
|
title = '' |
|
|
|
title = '' |
|
|
|
tournaments = [] |
|
|
|
tournaments = [] |
|
|
|
if filter==0: |
|
|
|
available_years = [] |
|
|
|
|
|
|
|
selected_year = None |
|
|
|
|
|
|
|
if month_param: |
|
|
|
|
|
|
|
selected_month = int(month_param) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
selected_month = timezone.now().month - 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if filter == 0: |
|
|
|
title = 'À venir' |
|
|
|
title = 'À venir' |
|
|
|
|
|
|
|
available_years, selected_year = handle_year_month_filtering(year_param, club_id, filter, is_future=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if selected_year and selected_month: |
|
|
|
|
|
|
|
tournaments = future_tournaments_by_month(club_id, selected_year, selected_month) |
|
|
|
|
|
|
|
elif selected_year: |
|
|
|
tournaments = future_tournaments(club_id) |
|
|
|
tournaments = future_tournaments(club_id) |
|
|
|
elif filter==1: |
|
|
|
else: |
|
|
|
|
|
|
|
tournaments = future_tournaments(club_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
elif filter == 1: |
|
|
|
title = 'En cours' |
|
|
|
title = 'En cours' |
|
|
|
tournaments = live_tournaments(club_id) |
|
|
|
tournaments = live_tournaments(club_id) |
|
|
|
elif filter==2: |
|
|
|
|
|
|
|
|
|
|
|
elif filter == 2: |
|
|
|
title = 'Terminés' |
|
|
|
title = 'Terminés' |
|
|
|
|
|
|
|
available_years, selected_year = handle_year_month_filtering(year_param, club_id, filter, is_future=False) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if selected_year and selected_month: |
|
|
|
|
|
|
|
tournaments = finished_tournaments_by_month(club_id, selected_year, selected_month) |
|
|
|
|
|
|
|
elif selected_year: |
|
|
|
tournaments = finished_tournaments(club_id) |
|
|
|
tournaments = finished_tournaments(club_id) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
tournaments = finished_tournaments(club_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
locale.setlocale(locale.LC_TIME, 'fr_FR.UTF-8') # Define month names in french |
|
|
|
|
|
|
|
|
|
|
|
return render( |
|
|
|
return render( |
|
|
|
request, |
|
|
|
request, |
|
|
|
@ -239,9 +314,39 @@ def tournaments(request): |
|
|
|
'second_title': title, |
|
|
|
'second_title': title, |
|
|
|
'head_title': title, |
|
|
|
'head_title': title, |
|
|
|
'club': club_id, |
|
|
|
'club': club_id, |
|
|
|
|
|
|
|
'filter': filter, |
|
|
|
|
|
|
|
'available_years': available_years, |
|
|
|
|
|
|
|
'available_months': range(0, 12), |
|
|
|
|
|
|
|
'selected_year': selected_year, |
|
|
|
|
|
|
|
'selected_month': selected_month, |
|
|
|
|
|
|
|
'month_names': list(calendar.month_name)[1:], |
|
|
|
|
|
|
|
'year': year_param, |
|
|
|
|
|
|
|
'month': month_param, |
|
|
|
} |
|
|
|
} |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def handle_year_month_filtering(year_param, club_id, filter_type, is_future=True): |
|
|
|
|
|
|
|
"""Helper function to handle year/month filtering for future and finished tournaments""" |
|
|
|
|
|
|
|
available_years = get_available_years_for_tournaments(club_id, filter_type) |
|
|
|
|
|
|
|
selected_year = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Handle year selection |
|
|
|
|
|
|
|
current_year = timezone.now().year |
|
|
|
|
|
|
|
if not year_param and available_years: |
|
|
|
|
|
|
|
if is_future: |
|
|
|
|
|
|
|
selected_year = current_year if current_year in available_years else available_years[0] |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
selected_year = available_years[0] # Most recent year for finished tournaments |
|
|
|
|
|
|
|
elif year_param: |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
selected_year = int(year_param) |
|
|
|
|
|
|
|
if selected_year not in available_years: |
|
|
|
|
|
|
|
selected_year = available_years[0] if available_years else None |
|
|
|
|
|
|
|
except: |
|
|
|
|
|
|
|
selected_year = available_years[0] if available_years else None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return available_years, selected_year |
|
|
|
|
|
|
|
|
|
|
|
def clubs(request): |
|
|
|
def clubs(request): |
|
|
|
all_clubs = Club.objects.all().order_by('name') |
|
|
|
all_clubs = Club.objects.all().order_by('name') |
|
|
|
clubs = [] |
|
|
|
clubs = [] |
|
|
|
|