mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-11-04 08:22:10 +01:00 
			
		
		
		
	Add CSV export for tournaments
This commit is contained in:
		@@ -62,6 +62,7 @@
 | 
			
		||||
        {% if user.registration.is_admin or user.registration in tournament.organizers.all %}
 | 
			
		||||
            <div class="card-footer text-center">
 | 
			
		||||
                <a href="{% url "participation:tournament_update" pk=tournament.pk %}"><button class="btn btn-secondary">{% trans "Edit tournament" %}</button></a>
 | 
			
		||||
                <a href="{% url "participation:tournament_csv" pk=tournament.pk %}"><button class="btn btn-success">{% trans "Export as CSV" %}</button></a>
 | 
			
		||||
            </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ from .views import CreateTeamView, JoinTeamView, MyParticipationDetailView, MyTe
 | 
			
		||||
    ParticipationDetailView, PassageCreateView, PassageDetailView, PassageUpdateView, PoolCreateView, PoolDetailView, \
 | 
			
		||||
    PoolUpdateTeamsView, PoolUpdateView, SolutionUploadView, SynthesisUploadView, TeamAuthorizationsView, \
 | 
			
		||||
    TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, TeamUploadMotivationLetterView, TournamentCreateView, \
 | 
			
		||||
    TournamentDetailView, TournamentListView, TournamentUpdateView
 | 
			
		||||
    TournamentDetailView, TournamentExportCSVView, TournamentListView, TournamentUpdateView
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
app_name = "participation"
 | 
			
		||||
@@ -31,6 +31,7 @@ urlpatterns = [
 | 
			
		||||
    path("tournament/create/", TournamentCreateView.as_view(), name="tournament_create"),
 | 
			
		||||
    path("tournament/<int:pk>/", TournamentDetailView.as_view(), name="tournament_detail"),
 | 
			
		||||
    path("tournament/<int:pk>/update/", TournamentUpdateView.as_view(), name="tournament_update"),
 | 
			
		||||
    path("tournament/<int:pk>/csv/", TournamentExportCSVView.as_view(), name="tournament_csv"),
 | 
			
		||||
    path("pools/create/", PoolCreateView.as_view(), name="pool_create"),
 | 
			
		||||
    path("pools/<int:pk>/", PoolDetailView.as_view(), name="pool_detail"),
 | 
			
		||||
    path("pools/<int:pk>/update/", PoolUpdateView.as_view(), name="pool_update"),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
# Copyright (C) 2020 by Animath
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
import csv
 | 
			
		||||
from io import BytesIO
 | 
			
		||||
import os
 | 
			
		||||
from zipfile import ZipFile
 | 
			
		||||
@@ -180,13 +180,13 @@ class TeamDetailView(LoginRequiredMixin, FormMixin, ProcessFormView, DetailView)
 | 
			
		||||
        # A team is complete when there are at least 4 members plus a coache that have sent their authorizations,
 | 
			
		||||
        # their health sheet, they confirmed their email address and under-18 people sent their parental authorization.
 | 
			
		||||
        context["can_validate"] = team.students.count() >= 4 and team.coaches.exists() and \
 | 
			
		||||
            team.participation.tournament and \
 | 
			
		||||
            all(r.photo_authorization for r in team.participants.all()) and \
 | 
			
		||||
            (team.participation.tournament.remote
 | 
			
		||||
             or all(r.health_sheet for r in team.students.all() if r.under_18)) and \
 | 
			
		||||
            (team.participation.tournament.remote
 | 
			
		||||
             or all(r.parental_authorization for r in team.students.all() if r.under_18)) and \
 | 
			
		||||
            team.motivation_letter
 | 
			
		||||
                                  team.participation.tournament and \
 | 
			
		||||
                                  all(r.photo_authorization for r in team.participants.all()) and \
 | 
			
		||||
                                  (team.participation.tournament.remote
 | 
			
		||||
                                   or all(r.health_sheet for r in team.students.all() if r.under_18)) and \
 | 
			
		||||
                                  (team.participation.tournament.remote
 | 
			
		||||
                                   or all(r.parental_authorization for r in team.students.all() if r.under_18)) and \
 | 
			
		||||
                                  team.motivation_letter
 | 
			
		||||
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
@@ -346,6 +346,7 @@ class MotivationLetterView(LoginRequiredMixin, View):
 | 
			
		||||
    """
 | 
			
		||||
    Display the sent motivation letter.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
        filename = kwargs["filename"]
 | 
			
		||||
        path = f"media/authorization/motivation_letters/{filename}"
 | 
			
		||||
@@ -459,6 +460,7 @@ class MyParticipationDetailView(LoginRequiredMixin, RedirectView):
 | 
			
		||||
    """
 | 
			
		||||
    Redirects to the detail view of the participation of the team.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def get_redirect_url(self, *args, **kwargs):
 | 
			
		||||
        user = self.request.user
 | 
			
		||||
        registration = user.registration
 | 
			
		||||
@@ -557,6 +559,40 @@ class TournamentDetailView(DetailView):
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TournamentExportCSVView(VolunteerMixin, DetailView):
 | 
			
		||||
    """
 | 
			
		||||
    Export team information in a CSV file.
 | 
			
		||||
    """
 | 
			
		||||
    model = Tournament
 | 
			
		||||
 | 
			
		||||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
        tournament = self.get_object()
 | 
			
		||||
 | 
			
		||||
        resp = HttpResponse(
 | 
			
		||||
            content_type='text/csv',
 | 
			
		||||
            headers={'Content-Disposition': f'attachment; filename="Tournoi de {tournament.name}.csv"'},
 | 
			
		||||
        )
 | 
			
		||||
        writer = csv.DictWriter(resp, ('Tournoi', 'Équipe', 'Trigramme', 'Nom', 'Prénom', 'Genre', 'Date de naissance'))
 | 
			
		||||
        writer.writeheader()
 | 
			
		||||
 | 
			
		||||
        for participation in tournament.participations.filter(valid=True).order_by('team__trigram').all():
 | 
			
		||||
            for registration in participation.team.participants\
 | 
			
		||||
                    .order_by('coachregistration', 'user__last_name').all():
 | 
			
		||||
                writer.writerow({
 | 
			
		||||
                    'Tournoi': tournament.name,
 | 
			
		||||
                    'Équipe': participation.team.name,
 | 
			
		||||
                    'Trigramme': participation.team.trigram,
 | 
			
		||||
                    'Nom': registration.user.last_name,
 | 
			
		||||
                    'Prénom': registration.user.first_name,
 | 
			
		||||
                    'Genre': registration.get_gender_display() if isinstance(registration, StudentRegistration)
 | 
			
		||||
                    else 'Encandrant⋅e',
 | 
			
		||||
                    'Date de naissance': registration.birth_date if isinstance(registration, StudentRegistration)
 | 
			
		||||
                    else 'Encandrant⋅e',
 | 
			
		||||
                })
 | 
			
		||||
 | 
			
		||||
        return resp
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SolutionUploadView(LoginRequiredMixin, FormView):
 | 
			
		||||
    template_name = "participation/upload_solution.html"
 | 
			
		||||
    form_class = SolutionForm
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user