Skip to content
Snippets Groups Projects
Commit b47e4c28 authored by Jean-Philippe Laverdure's avatar Jean-Philippe Laverdure
Browse files

Merge branch '79-add-annotation-to-downloaded-files' into 'master'

Resolve "Add annotation to downloaded files + file upload regression fix"

Closes #79

See merge request !35
parents 5b9b4b25 3bb77e96
No related branches found
No related tags found
1 merge request!35Resolve "Add annotation to downloaded files + file upload regression fix"
......@@ -21,7 +21,8 @@ from .views.secure.datafile import (AdminDataFileAnnotateView,
ajax_batch_datafile_annotations_JSON,
DataFileBatchRemoveAnnotation,
DataFileBatchAddAnnotation,
DataFileUploadServletView)
DataFileUploadServletView,
DataFileAnnotationDownloadView)
from .views.secure.dataset import (AdminDataSetCreateView,
AdminDataSetDeleteView,
AdminDataSetJSONListView,
......@@ -74,6 +75,7 @@ urlpatterns = [
path('secure/datafiles/annotate', DataFileAnnotateView.as_view(), name='user.datafile-annotate'),
path('secure/datafiles/upload', DataFileUploadView.as_view(), name='user.datafile-upload'),
path('secure/datafiles/download/<int:pk>', DataFileDownloadView.as_view(), name='user.datafile-download'),
path('secure/datafiles/download/annotation/<int:pk>', DataFileAnnotationDownloadView.as_view(), name='user.datafile-annotation-download'),
path('secure/datafiles/delete/<int:pk>', DataFileDeleteView.as_view(), name='user.datafile-delete'),
path('secure/datafiles/update/<int:pk>', DataFileUpdateView.as_view(), name='user.datafile-update'),
path('secure/datafiles/annotations', ajax_batch_datafile_annotations_JSON, name='user.ajax_batch_datafile_annotations_JSON'),
......
import logging
import json
import os
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
......@@ -7,7 +8,7 @@ from django.contrib import messages
from django.contrib.messages import get_messages
from django.db.models import Q, F
from django.http import JsonResponse
from django.http.response import HttpResponseRedirect
from django.http.response import HttpResponseRedirect, HttpResponse
from django.template import defaultfilters as filters
from django.template.loader import render_to_string
from django.urls import reverse, reverse_lazy
......@@ -268,20 +269,9 @@ class DataFileUploadView(LoginRequiredMixin, ActivePageViewMixin, CreateView):
uploaded_by=self.request.user.profile,
file=self.request.FILES['file'])
if form.cleaned_data.get('annotations'):
file.annotations = form.cleaned_data['annotations']
if form.cleaned_data.get('lab'):
file.lab = form.cleaned_data['lab']
file.save()
return JsonResponse({'fid': file.id})
def get_form(self, form_class=None):
if form_class is None:
form_class = self.get_form_class()
return form_class(self.request, **self.get_form_kwargs())
def form_invalid(self, form):
# TODO move this to some form of logging and handle error return
logger.debug(form)
......@@ -306,7 +296,7 @@ class DataFileUploadServletView(LoginRequiredMixin, ActivePageViewMixin, CreateV
if form.cleaned_data.get('lab'):
file.lab = form.cleaned_data['lab']
file.save()
dataset = form.cleaned_data.get('dataset')
......@@ -339,6 +329,16 @@ class DataFileDownloadView(LoginRequiredMixin, PrivateStorageDetailView):
)
class DataFileAnnotationDownloadView(DataFileDownloadView):
model = DataFile
def get(self, request, pk):
df = self.get_object()
resp = HttpResponse(json.dumps(df.annotations), content_type="application/json")
resp['Content-Disposition'] = 'attachment; filename={}.annotation.json'.format(str(df.name)).encode("utf-8")
return resp
class DataFileUpdateView(LoginRequiredMixin, UpdateViewMixin, UpdateView):
model = DataFile
form_class = DataFileForm
......
......@@ -2,6 +2,7 @@ import logging
import os
import zipfile
from io import BytesIO
import json
from django.db.models import Q
from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect
......@@ -88,19 +89,22 @@ class DataSetDownload(LoginRequiredMixin, SuccessMessageMixin, DetailView):
# only allow download if user has access to dataset
if DataSet.objects.accessible_to_profile(self.request.user.profile).filter(id=dataset.id).exists():
fpaths = [f.file.path for f in dataset.files.all()]
datafiles = dataset.files.all()
total_size = sum([os.path.getsize(fpath) for fpath in fpaths])
total_size = sum([df.file.size for df in datafiles])
if total_size > 104857600: # 100MB
messages.error(self.request, _("Cannot zip dataset. The total size of files contained in this dataset is larger than 100MB."))
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
messages.error(self.request, _("Cannot zip dataset. The total size of files contained in this dataset is larger than 100MB."))
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
s = BytesIO()
zf = zipfile.ZipFile(s, "w")
for fpath in fpaths:
fdir, fname = os.path.split(fpath)
zf.write(fpath, fname)
for df in datafiles:
fdir, fname = os.path.split(df.file.path)
zf.write(df.file.path, fname)
if df.annotations:
zf.writestr(fname + ".annotation.json", json.dumps(df.annotations))
zf.close()
resp = HttpResponse(s.getvalue(), content_type="application/x-zip-compressed")
......@@ -267,11 +271,11 @@ class DataSetFileListView(DataSetDetailsView):
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return HttpResponse(
'\n'.join(
['http://{0}{1}'.format(request.get_host(), reverse('user.datafile-download', args=[file.id])) for file in self.object.files.all()]),
content_type="text/plain"
)
files = ['http://{0}{1}'.format(request.get_host(), reverse('user.datafile-download', args=[file.id]))
for file in self.object.files.all()]
annotations = ['http://{0}{1}'.format(request.get_host(), reverse('user.datafile-annotation-download', args=[file.id]))
for file in self.object.files.filter(annotations__isnull=False).exclude(annotations__exact='').all()]
return HttpResponse('\n'.join(files + annotations), content_type="text/plain")
class AdminDataSetJSONListView(StaffViewMixin, DataSetJSONListView):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment