mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-11-04 16:02:26 +01:00 
			
		
		
		
	Add ZIP archive for tournament authorizations
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
		@@ -116,7 +116,7 @@
 | 
			
		||||
        {% if user.registration.is_volunteer %}
 | 
			
		||||
            {% if user.registration in self.team.participation.tournament.organizers or user.registration.is_admin %}
 | 
			
		||||
                <div class="text-center">
 | 
			
		||||
                    <a class="btn btn-info" href="{% url "participation:team_authorizations" pk=team.pk %}">
 | 
			
		||||
                    <a class="btn btn-info" href="{% url "participation:team_authorizations" team_id=team.id %}">
 | 
			
		||||
                        <i class="fas fa-file-archive"></i> {% trans "Download all submitted authorizations" %}
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -62,7 +62,6 @@
 | 
			
		||||
        {% 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>
 | 
			
		||||
@@ -91,12 +90,6 @@
 | 
			
		||||
        </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    {% if user.registration.is_admin %}
 | 
			
		||||
        <div class="d-grid">
 | 
			
		||||
            <button class="btn gap-0 btn-success" data-bs-toggle="modal" data-bs-target="#addPoolModal">{% trans "Add new pool" %}</button>
 | 
			
		||||
        </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    {% if notes %}
 | 
			
		||||
        <hr>
 | 
			
		||||
 | 
			
		||||
@@ -134,20 +127,81 @@
 | 
			
		||||
        </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    {% if user.registration.is_admin %}
 | 
			
		||||
        {% trans "Add pool" as modal_title %}
 | 
			
		||||
        {% trans "Add" as modal_button %}
 | 
			
		||||
        {% url "participation:pool_create" as modal_action %}
 | 
			
		||||
        {% include "base_modal.html" with modal_id="addPool" %}
 | 
			
		||||
    {% endif %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
    {% if user.registration.is_admin or user.registration in tournament.organizers.all %}
 | 
			
		||||
        <hr>
 | 
			
		||||
 | 
			
		||||
        <h3>{% trans "Files available for download" %}</h3>
 | 
			
		||||
 | 
			
		||||
        <div class="alert alert-warning fade show files-to-download-collapse" id="files-to-download-popup">
 | 
			
		||||
            <h4>IMPORTANT</h4>
 | 
			
		||||
 | 
			
		||||
            <p>
 | 
			
		||||
                Les fichiers accessibles ci-dessous peuvent contenir des informations personnelles.
 | 
			
		||||
                Par conformité avec le droit européen et par respect de la confidentialité des données
 | 
			
		||||
                des participant⋅es, vous ne devez utiliser ces données que dans un cadre strictement
 | 
			
		||||
                nécessaire en lien avec l'organisation du tournoi.
 | 
			
		||||
            </p>
 | 
			
		||||
 | 
			
		||||
            <p>
 | 
			
		||||
                De plus, il est de votre responsabilité de supprimer ces fichiers une fois que vous
 | 
			
		||||
                n'en avez plus besoin, notamment à la fin du tournoi.
 | 
			
		||||
            </p>
 | 
			
		||||
 | 
			
		||||
            <p class="text-center">
 | 
			
		||||
                <button class="btn btn-warning" data-bs-toggle="collapse" href=".files-to-download-collapse"
 | 
			
		||||
                        role="button" aria-expanded="false" aria-controls="files-to-download files-to-download-popup">
 | 
			
		||||
                    Je m'engage à ne pas divulguer les données des participant⋅es
 | 
			
		||||
                    et de les supprimer à l'issue du tournoi
 | 
			
		||||
                </button>
 | 
			
		||||
            </p>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="card bg-body shadow fade collapse files-to-download-collapse" id="files-to-download">
 | 
			
		||||
            <div class="card-body">
 | 
			
		||||
                <ul>
 | 
			
		||||
                    <li>
 | 
			
		||||
                        <a href="{% url "participation:tournament_csv" pk=tournament.pk %}">
 | 
			
		||||
                            Tableur de données des participant⋅es des équipes validées
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li>
 | 
			
		||||
                        <a href="{% url "participation:tournament_csv" pk=tournament.pk %}?all">
 | 
			
		||||
                            Tableur de données des participant⋅es de toutes les équipes
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li>
 | 
			
		||||
                        <a href="{% url "participation:tournament_authorizations" tournament_id=tournament.id %}">
 | 
			
		||||
                            Archive de toutes les autorisations triées par équipe et par personne
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li>
 | 
			
		||||
                        <a>
 | 
			
		||||
                            Archive de toutes les solutions envoyées triées par équipe
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li>
 | 
			
		||||
                        <a>
 | 
			
		||||
                            Archive de toutes les solutions envoyées triées par problème
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li>
 | 
			
		||||
                        <a>
 | 
			
		||||
                            Archive de toutes les notes de synthèse triées par poule et par passage
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li>
 | 
			
		||||
                        <a>
 | 
			
		||||
                            Archive de tous les barèmes de notes à imprimer triés par poule
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li>
 | 
			
		||||
                        <a>
 | 
			
		||||
                            Archive de tous les tableurs de notes à saisir triés par poule
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
{% block extrajavascript %}
 | 
			
		||||
    <script>
 | 
			
		||||
        document.addEventListener('DOMContentLoaded', () => {
 | 
			
		||||
            {% if user.registration.is_admin %}
 | 
			
		||||
                initModal("addPool", "{% url "participation:pool_create" %}")
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        });
 | 
			
		||||
    </script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ urlpatterns = [
 | 
			
		||||
    path("team/<int:pk>/update/", TeamUpdateView.as_view(), name="update_team"),
 | 
			
		||||
    path("team/<int:pk>/upload-motivation-letter/", TeamUploadMotivationLetterView.as_view(),
 | 
			
		||||
         name="upload_team_motivation_letter"),
 | 
			
		||||
    path("team/<int:pk>/authorizations/", TeamAuthorizationsView.as_view(), name="team_authorizations"),
 | 
			
		||||
    path("team/<int:team_id>/authorizations/", TeamAuthorizationsView.as_view(), name="team_authorizations"),
 | 
			
		||||
    path("team/leave/", TeamLeaveView.as_view(), name="team_leave"),
 | 
			
		||||
    path("detail/", MyParticipationDetailView.as_view(), name="my_participation_detail"),
 | 
			
		||||
    path("detail/<int:pk>/", ParticipationDetailView.as_view(), name="participation_detail"),
 | 
			
		||||
@@ -36,6 +36,8 @@ urlpatterns = [
 | 
			
		||||
    path("tournament/<int:pk>/update/", TournamentUpdateView.as_view(), name="tournament_update"),
 | 
			
		||||
    path("tournament/<int:pk>/payments/", TournamentPaymentsView.as_view(), name="tournament_payments"),
 | 
			
		||||
    path("tournament/<int:pk>/csv/", TournamentExportCSVView.as_view(), name="tournament_csv"),
 | 
			
		||||
    path("tournament/<int:tournament_id>/authorizations/", TeamAuthorizationsView.as_view(),
 | 
			
		||||
         name="tournament_authorizations"),
 | 
			
		||||
    path("tournament/<int:pk>/publish-notes/<int:round>/", TournamentPublishNotesView.as_view(),
 | 
			
		||||
         name="tournament_publish_notes"),
 | 
			
		||||
    path("pools/create/", PoolCreateView.as_view(), name="pool_create"),
 | 
			
		||||
 
 | 
			
		||||
@@ -366,63 +366,91 @@ class MotivationLetterView(LoginRequiredMixin, View):
 | 
			
		||||
        return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TeamAuthorizationsView(LoginRequiredMixin, DetailView):
 | 
			
		||||
class TeamAuthorizationsView(LoginRequiredMixin, View):
 | 
			
		||||
    """
 | 
			
		||||
    Get as a ZIP archive all the authorizations that are sent
 | 
			
		||||
    """
 | 
			
		||||
    model = Team
 | 
			
		||||
 | 
			
		||||
    def dispatch(self, request, *args, **kwargs):
 | 
			
		||||
        user = request.user
 | 
			
		||||
        if not user.is_authenticated:
 | 
			
		||||
            return super().handle_no_permission()
 | 
			
		||||
 | 
			
		||||
        if 'team_id' in kwargs:
 | 
			
		||||
            team = Team.objects.get(pk=kwargs["team_id"])
 | 
			
		||||
            tournament = team.participation.tournament
 | 
			
		||||
        else:
 | 
			
		||||
            team = None
 | 
			
		||||
            tournament = Tournament.objects.get(pk=kwargs["tournament_id"])
 | 
			
		||||
 | 
			
		||||
        if user.registration.is_admin or user.registration.is_volunteer \
 | 
			
		||||
                and (user.registration in self.get_object().participation.tournament.organizers
 | 
			
		||||
                     or self.get_object().participation.final
 | 
			
		||||
                     and user.registration in Tournament.final_tournament().organizers):
 | 
			
		||||
                and (user.registration in tournament.organizers
 | 
			
		||||
                     or (team is not None and team.participation.final
 | 
			
		||||
                         and user.registration in Tournament.final_tournament().organizers)):
 | 
			
		||||
            return super().dispatch(request, *args, **kwargs)
 | 
			
		||||
        raise PermissionDenied
 | 
			
		||||
 | 
			
		||||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
        team = self.get_object()
 | 
			
		||||
        if 'team_id' in kwargs:
 | 
			
		||||
            team = Team.objects.get(pk=kwargs["team_id"])
 | 
			
		||||
            teams = [team]
 | 
			
		||||
            filename = _("Authorizations of team {trigram}.zip").format(trigram=team.trigram)
 | 
			
		||||
        else:
 | 
			
		||||
            tournament = Tournament.objects.get(pk=kwargs["tournament_id"])
 | 
			
		||||
            teams = [p.team for p in tournament.participations.filter(valid=True)]
 | 
			
		||||
            filename = _("Authorizations of {tournament}.zip").format(tournament=tournament.name)
 | 
			
		||||
 | 
			
		||||
        magic = Magic(mime=True)
 | 
			
		||||
        output = BytesIO()
 | 
			
		||||
        zf = ZipFile(output, "w")
 | 
			
		||||
        for participant in team.participants.all():
 | 
			
		||||
            if participant.photo_authorization:
 | 
			
		||||
                mime_type = magic.from_file("media/" + participant.photo_authorization.name)
 | 
			
		||||
                ext = mime_type.split("/")[1].replace("jpeg", "jpg")
 | 
			
		||||
                zf.write("media/" + participant.photo_authorization.name,
 | 
			
		||||
                         _("Photo authorization of {participant}.{ext}").format(participant=str(participant), ext=ext))
 | 
			
		||||
        for team in teams:
 | 
			
		||||
            team_prefix = f"{team.trigram}/" if len(teams) > 1 else ""
 | 
			
		||||
 | 
			
		||||
            if isinstance(participant, StudentRegistration) and participant.parental_authorization:
 | 
			
		||||
                mime_type = magic.from_file("media/" + participant.parental_authorization.name)
 | 
			
		||||
                ext = mime_type.split("/")[1].replace("jpeg", "jpg")
 | 
			
		||||
                zf.write("media/" + participant.parental_authorization.name,
 | 
			
		||||
                         _("Parental authorization of {participant}.{ext}")
 | 
			
		||||
                         .format(participant=str(participant), ext=ext))
 | 
			
		||||
            for participant in team.participants.all():
 | 
			
		||||
                user_prefix = f"{team_prefix}{participant.user.first_name} {participant.user.last_name}/"
 | 
			
		||||
 | 
			
		||||
            if isinstance(participant, StudentRegistration) and participant.health_sheet:
 | 
			
		||||
                mime_type = magic.from_file("media/" + participant.health_sheet.name)
 | 
			
		||||
                ext = mime_type.split("/")[1].replace("jpeg", "jpg")
 | 
			
		||||
                zf.write("media/" + participant.health_sheet.name,
 | 
			
		||||
                         _("Health sheet of {participant}.{ext}").format(participant=str(participant), ext=ext))
 | 
			
		||||
                if participant.photo_authorization \
 | 
			
		||||
                        and participant.photo_authorization.storage.exists(participant.photo_authorization.path):
 | 
			
		||||
                    mime_type = magic.from_file("media/" + participant.photo_authorization.name)
 | 
			
		||||
                    ext = mime_type.split("/")[1].replace("jpeg", "jpg")
 | 
			
		||||
                    zf.write("media/" + participant.photo_authorization.name,
 | 
			
		||||
                             user_prefix + _("Photo authorization of {participant}.{ext}")
 | 
			
		||||
                             .format(participant=str(participant), ext=ext))
 | 
			
		||||
 | 
			
		||||
            if isinstance(participant, StudentRegistration) and participant.vaccine_sheet:
 | 
			
		||||
                mime_type = magic.from_file("media/" + participant.vaccine_sheet.name)
 | 
			
		||||
                ext = mime_type.split("/")[1].replace("jpeg", "jpg")
 | 
			
		||||
                zf.write("media/" + participant.vaccine_sheet.name,
 | 
			
		||||
                         _("Vaccine sheet of {participant}.{ext}").format(participant=str(participant), ext=ext))
 | 
			
		||||
                if participant.is_student and participant.parental_authorization \
 | 
			
		||||
                        and participant.parental_authorization.storage.exists(participant.parental_authorization.path):
 | 
			
		||||
                    mime_type = magic.from_file("media/" + participant.parental_authorization.name)
 | 
			
		||||
                    ext = mime_type.split("/")[1].replace("jpeg", "jpg")
 | 
			
		||||
                    zf.write("media/" + participant.parental_authorization.name,
 | 
			
		||||
                             user_prefix + _("Parental authorization of {participant}.{ext}")
 | 
			
		||||
                             .format(participant=str(participant), ext=ext))
 | 
			
		||||
 | 
			
		||||
                if participant.is_student and participant.health_sheet \
 | 
			
		||||
                        and participant.health_sheet.storage.exists(participant.health_sheet.path):
 | 
			
		||||
                    mime_type = magic.from_file("media/" + participant.health_sheet.name)
 | 
			
		||||
                    ext = mime_type.split("/")[1].replace("jpeg", "jpg")
 | 
			
		||||
                    zf.write("media/" + participant.health_sheet.name,
 | 
			
		||||
                             user_prefix + _("Health sheet of {participant}.{ext}")
 | 
			
		||||
                             .format(participant=str(participant), ext=ext))
 | 
			
		||||
 | 
			
		||||
                if participant.is_student and participant.vaccine_sheet \
 | 
			
		||||
                        and participant.vaccine_sheet.storage.exists(participant.vaccine_sheet.path):
 | 
			
		||||
                    mime_type = magic.from_file("media/" + participant.vaccine_sheet.name)
 | 
			
		||||
                    ext = mime_type.split("/")[1].replace("jpeg", "jpg")
 | 
			
		||||
                    zf.write("media/" + participant.vaccine_sheet.name,
 | 
			
		||||
                             user_prefix + _("Vaccine sheet of {participant}.{ext}")
 | 
			
		||||
                             .format(participant=str(participant), ext=ext))
 | 
			
		||||
 | 
			
		||||
            if team.motivation_letter and team.motivation_letter.storage.exists(team.motivation_letter.path):
 | 
			
		||||
                mime_type = magic.from_file("media/" + team.motivation_letter.name)
 | 
			
		||||
                ext = mime_type.split("/")[1].replace("jpeg", "jpg")
 | 
			
		||||
                zf.write("media/" + team.motivation_letter.name,
 | 
			
		||||
                         team_prefix + _("Motivation letter of {team}.{ext}")
 | 
			
		||||
                         .format(team=str(team), ext=ext))
 | 
			
		||||
 | 
			
		||||
        if team.motivation_letter:
 | 
			
		||||
            mime_type = magic.from_file("media/" + team.motivation_letter.name)
 | 
			
		||||
            ext = mime_type.split("/")[1].replace("jpeg", "jpg")
 | 
			
		||||
            zf.write("media/" + team.motivation_letter.name,
 | 
			
		||||
                     _("Motivation letter of {team}.{ext}").format(team=str(team), ext=ext))
 | 
			
		||||
        zf.close()
 | 
			
		||||
        response = HttpResponse(content_type="application/zip")
 | 
			
		||||
        response["Content-Disposition"] = "attachment; filename=\"{filename}\"" \
 | 
			
		||||
            .format(filename=_("Photo authorizations of team {trigram}.zip").format(trigram=team.trigram))
 | 
			
		||||
        response["Content-Disposition"] = f"attachment; filename=\"{filename}\""
 | 
			
		||||
        response.write(output.getvalue())
 | 
			
		||||
        return response
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user