|
|
|
@ -5,6 +5,7 @@ from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode |
|
|
|
from django.urls import reverse |
|
|
|
from django.urls import reverse |
|
|
|
|
|
|
|
|
|
|
|
from django.views.decorators.csrf import csrf_exempt |
|
|
|
from django.views.decorators.csrf import csrf_exempt |
|
|
|
|
|
|
|
from django.contrib.admin.views.decorators import staff_member_required |
|
|
|
from django.core.files.storage import default_storage |
|
|
|
from django.core.files.storage import default_storage |
|
|
|
from django.core.files.base import ContentFile |
|
|
|
from django.core.files.base import ContentFile |
|
|
|
|
|
|
|
|
|
|
|
@ -22,6 +23,7 @@ from django.db.models import Q |
|
|
|
import json |
|
|
|
import json |
|
|
|
import asyncio |
|
|
|
import asyncio |
|
|
|
import csv |
|
|
|
import csv |
|
|
|
|
|
|
|
import zipfile |
|
|
|
|
|
|
|
|
|
|
|
from api.tokens import account_activation_token |
|
|
|
from api.tokens import account_activation_token |
|
|
|
|
|
|
|
|
|
|
|
@ -483,3 +485,94 @@ def send_email(mail, name): |
|
|
|
|
|
|
|
|
|
|
|
email = EmailMessage(subject, body, to=[mail]) |
|
|
|
email = EmailMessage(subject, body, to=[mail]) |
|
|
|
email.send() |
|
|
|
email.send() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from api.serializers import GroupStageSerializer, MatchSerializer, PlayerRegistrationSerializer, RoundSerializer, TeamRegistrationSerializer, TeamScoreSerializer |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@staff_member_required |
|
|
|
|
|
|
|
def tournament_import_view(request): |
|
|
|
|
|
|
|
if request.method == 'POST': |
|
|
|
|
|
|
|
zip_file = request.FILES.get('tournament_zip') |
|
|
|
|
|
|
|
if zip_file: |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
tournament_id = os.path.splitext(zip_file.name)[0] |
|
|
|
|
|
|
|
tournament = Tournament.objects.get(id=tournament_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Delete existing relationships |
|
|
|
|
|
|
|
tournament.round_set.all().delete() |
|
|
|
|
|
|
|
tournament.groupstage_set.all().delete() |
|
|
|
|
|
|
|
tournament.teamregistration_set.all().delete() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with zipfile.ZipFile(zip_file) as z: |
|
|
|
|
|
|
|
# First, process rounds |
|
|
|
|
|
|
|
rounds_data = get_file_data(z, f"{tournament_id}/rounds.json") |
|
|
|
|
|
|
|
if rounds_data: |
|
|
|
|
|
|
|
# First pass: Create rounds without parent relationships |
|
|
|
|
|
|
|
rounds_without_parent = [] |
|
|
|
|
|
|
|
for item in rounds_data: |
|
|
|
|
|
|
|
item['tournament'] = tournament.id |
|
|
|
|
|
|
|
# Temporarily remove parent field |
|
|
|
|
|
|
|
parent = item.pop('parent', None) |
|
|
|
|
|
|
|
rounds_without_parent.append({'data': item, 'parent': parent}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
serializer = RoundSerializer(data=[item['data'] for item in rounds_without_parent], many=True) |
|
|
|
|
|
|
|
serializer.is_valid(raise_exception=True) |
|
|
|
|
|
|
|
created_rounds = serializer.save() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Create a mapping of round IDs |
|
|
|
|
|
|
|
round_mapping = {round_obj.id: round_obj for round_obj in created_rounds} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Second pass: Update parent relationships |
|
|
|
|
|
|
|
for round_obj, original_data in zip(created_rounds, rounds_without_parent): |
|
|
|
|
|
|
|
if original_data['parent']: |
|
|
|
|
|
|
|
round_obj.parent = round_mapping.get(original_data['parent']) |
|
|
|
|
|
|
|
round_obj.save() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Then process all other files |
|
|
|
|
|
|
|
serializer_mapping = { |
|
|
|
|
|
|
|
'group-stages.json': GroupStageSerializer, |
|
|
|
|
|
|
|
'team-registrations.json': TeamRegistrationSerializer, |
|
|
|
|
|
|
|
'matches.json': MatchSerializer, |
|
|
|
|
|
|
|
'player-registrations.json': PlayerRegistrationSerializer, |
|
|
|
|
|
|
|
'team-scores.json': TeamScoreSerializer |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Process each remaining file |
|
|
|
|
|
|
|
for filename, serializer_class in serializer_mapping.items(): |
|
|
|
|
|
|
|
process_file(z, filename, tournament_id, tournament, serializer_class) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return JsonResponse({'status': 'success'}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
|
|
return JsonResponse({'status': 'error', 'message': str(e)}) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
return render(request, 'tournaments/admin/tournament_cleaner.html') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_file(zip_file, filename, tournament_id, tournament, serializer_class): |
|
|
|
|
|
|
|
"""Helper function to process individual files""" |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
file_path = f"{tournament_id}/{filename}" |
|
|
|
|
|
|
|
json_data = get_file_data(zip_file, file_path) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if json_data: |
|
|
|
|
|
|
|
# Add tournament to each item |
|
|
|
|
|
|
|
for item in json_data: |
|
|
|
|
|
|
|
item['tournament'] = tournament.id |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
serializer = serializer_class(data=json_data, many=True) |
|
|
|
|
|
|
|
serializer.is_valid(raise_exception=True) |
|
|
|
|
|
|
|
serializer.save() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
|
|
print(f"Error processing {filename}: {str(e)}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_file_data(zip_file, file_path): |
|
|
|
|
|
|
|
"""Helper function to read and parse JSON data from zip file""" |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
file_content = zip_file.read(file_path) |
|
|
|
|
|
|
|
return json.loads(file_content) |
|
|
|
|
|
|
|
except KeyError: |
|
|
|
|
|
|
|
print(f"File not found: {file_path}") |
|
|
|
|
|
|
|
return None |
|
|
|
|
|
|
|
except json.JSONDecodeError as e: |
|
|
|
|
|
|
|
print(f"JSON Error for {file_path}: {str(e)}") |
|
|
|
|
|
|
|
raise Exception(f"Invalid JSON in file {file_path}") |
|
|
|
|