diff --git a/tournaments/templates/tournaments/admin/tournament_cleaner.html b/tournaments/templates/tournaments/admin/tournament_cleaner.html new file mode 100644 index 0000000..ed3aa68 --- /dev/null +++ b/tournaments/templates/tournaments/admin/tournament_cleaner.html @@ -0,0 +1,16 @@ + + + + + Tournament Import + + +
+ {% csrf_token %} +
+ +
+ +
+ + diff --git a/tournaments/urls.py b/tournaments/urls.py index e4b316b..5670262 100644 --- a/tournaments/urls.py +++ b/tournaments/urls.py @@ -38,4 +38,5 @@ urlpatterns = [ path('terms-of-use/', views.terms_of_use, name='terms-of-use'), path('utils/xls-to-csv/', views.xls_to_csv, name='xls-to-csv'), path('mail-test/', views.simple_form_view, name='mail-test'), + path('admin/tournament-import/', views.tournament_import_view, name='tournament_import'), ] diff --git a/tournaments/views.py b/tournaments/views.py index e30e420..b088cdd 100644 --- a/tournaments/views.py +++ b/tournaments/views.py @@ -5,6 +5,7 @@ from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from django.urls import reverse 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.base import ContentFile @@ -22,6 +23,7 @@ from django.db.models import Q import json import asyncio import csv +import zipfile from api.tokens import account_activation_token @@ -483,3 +485,94 @@ def send_email(mail, name): email = EmailMessage(subject, body, to=[mail]) 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}")