Skip to content
Snippets Groups Projects
Commit 06dcf15d authored by florimondmanca's avatar florimondmanca
Browse files

add endpoint to download edition documents zip

parent 7178c5f3
No related branches found
No related tags found
No related merge requests found
......@@ -7,6 +7,7 @@ import zipfile
import csv
from io import BytesIO, StringIO
from .models import Form
from django.db.models.fields.files import FieldFile
def _get_rows(form: Form) -> List[List[str]]:
......@@ -70,3 +71,18 @@ def write_zip(forms, stream=None, folder='forms'):
value = csv_file.getvalue()
zip.writestr(csv_filename, value.encode())
return stream
def files_zip(files: List[FieldFile], folder: str='') -> BytesIO:
"""Write form's files into a ZIP."""
stream = BytesIO()
with zipfile.ZipFile(stream, 'w') as zip:
for file in files:
dest = os.path.join(folder, os.path.basename(file.name))
contents = file.read()
zip.writestr(dest, contents)
# fix for Linux zip files read in Windows
for file in zip.filelist:
file.create_system = 0
stream.seek(0)
return stream
"""Dynamic forms views and API endpoints."""
from typing import Union
from django.http import HttpResponse
from rest_framework import mixins, viewsets
from .exports import write_zip
from .exports import write_zip, files_zip
from .models import Form, FormEntry
from .serializers import (FormDetailSerializer, FormEntrySerializer,
FormSerializer)
......@@ -41,6 +42,24 @@ def download_multiple_forms_entries(request, forms):
response = HttpResponse(contents,
content_type='application/x-zip-compressed')
response['Content-Disposition'] = f'attachment; filename="{filename}"'
response['Content-Disposition'] = f'attachment; filename={filename}'
return response
def download_files_zip(request, form: Union[Form, None], folder: str):
"""Download form files in a ZIP archive."""
if form:
files_qs = form.files.all()
files = (f.file for f in files_qs)
else:
files = ()
filename = f'{folder}_files.zip'
stream = files_zip(files, folder=folder)
response = HttpResponse(content_type='application/zip')
response['Content-Disposition'] = f'attachment; filename={filename}'
response.write(stream.read())
return response
......@@ -2,19 +2,20 @@
from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import redirect
from django.utils.text import slugify
from django.utils.timezone import now
from django_filters import rest_framework as filters
from django_filters.rest_framework.backends import DjangoFilterBackend
from rest_framework import mixins, permissions, status, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from dynamicforms.serializers import FormEntrySerializer
from dynamicforms.views import download_files_zip
from .models import Edition, Participation, Project
from .serializers import (EditionDetailSerializer, EditionListSerializer,
ParticipationSerializer, ProjectDetailSerializer,
ProjectSerializer, EditionDocumentsSerializer)
from .serializers import (EditionDetailSerializer, EditionDocumentsSerializer,
EditionListSerializer, ParticipationSerializer,
ProjectDetailSerializer, ProjectSerializer)
class ProjectViewSet(viewsets.ReadOnlyModelViewSet):
......@@ -225,7 +226,7 @@ class EditionViewSet(viewsets.ReadOnlyModelViewSet):
'participations', 'organizers'
)
permission_classes = (permissions.IsAuthenticated,)
filter_backends = (filters.DjangoFilterBackend,)
filter_backends = (filters.backends.DjangoFilterBackend,)
filter_fields = ('project', 'year',)
def get_serializer_class(self):
......@@ -340,6 +341,22 @@ class EditionViewSet(viewsets.ReadOnlyModelViewSet):
data = serializer.data
return Response(data)
@action(methods=['get'], detail=True)
def documents_zip(self, request, pk=None):
"""Download an edition form's documents as a ZIP archive.
If the edition does not have a form, an empty ZIP file is sent.
"""
edition: Edition = self.get_object()
folder = slugify(edition.project.name)
try:
form = edition.edition_form.form
except ObjectDoesNotExist:
form = None
return download_files_zip(request, form=form, folder=folder)
class ParticipationViewSet(mixins.CreateModelMixin,
viewsets.ReadOnlyModelViewSet):
......@@ -401,7 +418,7 @@ class ParticipationViewSet(mixins.CreateModelMixin,
queryset = Participation.objects.prefetch_related('edition').all()
serializer_class = ParticipationSerializer
permission_classes = (permissions.IsAuthenticated,)
filter_backends = (DjangoFilterBackend,)
filter_backends = (filters.backends.DjangoFilterBackend,)
filter_fields = ('user', 'state',)
@action(methods=['get'], detail=True)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment