X-Git-Url: https://git.mdrn.pl/redakcja.git/blobdiff_plain/43116c58e5c56f94ef358a5a17fb13a252e02531..a802a933f53625f732e9d3807b4162e770c8aaf1:/apps/fileupload/views.py?ds=inline diff --git a/apps/fileupload/views.py b/apps/fileupload/views.py index 217a78b5..cfaedc80 100644 --- a/apps/fileupload/views.py +++ b/apps/fileupload/views.py @@ -1,36 +1,100 @@ +# -*- coding: utf-8 -*- import json import os -from .forms import UploadForm -from django.views.generic import FormView, View -from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404 +from zipfile import ZipFile +from urllib import quote from django.conf import settings +from django.http import HttpResponse, Http404 +from django.utils.decorators import method_decorator +from django.utils.encoding import force_unicode +from django.views.decorators.vary import vary_on_headers +from django.views.generic import FormView, RedirectView +from unidecode import unidecode + +from .forms import UploadForm + + +# Use sorl.thumbnail if available. +try: + from sorl.thumbnail import default +except ImportError: + def thumbnail(relpath): + return settings.MEDIA_URL + relpath + default = None +else: + def thumbnail(relpath): + try: + return default.backend.get_thumbnail(relpath, "x50").url + except IOError: + # That's not an image. No thumb. + return None class JSONResponse(HttpResponse): """JSON response class.""" - def __init__(self, obj='', mimetype="application/json", *args, **kwargs): + def __init__(self, obj=None, mimetype="application/json", *args, **kwargs): content = json.dumps(obj) super(JSONResponse, self).__init__(content, mimetype, *args, **kwargs) -class UploadView(FormView): - template_name = "fileupload/picture_form.html" - form_class = UploadForm +class UploadViewMixin(object): def get_safe_path(self, filename=""): - path = os.path.abspath(os.path.join( - settings.MEDIA_ROOT, - self.get_directory(), - filename)) - if not path.startswith(settings.MEDIA_ROOT): + """Finds absolute filesystem path of the browsed dir of file. + + Makes sure it's inside MEDIA_ROOT. + + """ + path = os.path.abspath(os.path.join(settings.MEDIA_ROOT, self.get_directory(), filename)) + if not path.startswith(os.path.abspath(settings.MEDIA_ROOT)): raise Http404 if filename: if not path.startswith(self.get_safe_path()): raise Http404 - return path + return force_unicode(path) + + +class UploadView(UploadViewMixin, FormView): + template_name = "fileupload/picture_form.html" + form_class = UploadForm - def get_url(self, filename=""): - return settings.MEDIA_URL + self.get_directory() + filename + def get_object(self, request, *args, **kwargs): + """Get any data for later use.""" + return None + def get_directory(self): + """Directory relative to MEDIA_ROOT. Must end with a slash.""" + return self.kwargs['path'] + + def breadcrumbs(self): + """List of tuples (name, url) or just (name,) for breadcrumbs. + + Probably only the last item (representing currently browsed dir) + should lack url. + + """ + directory = self.get_directory() + now_path = os.path.dirname(self.request.get_full_path()) + directory = os.path.dirname(directory) + if directory: + crumbs = [ + (os.path.basename(directory),) + ] + directory = os.path.dirname(directory) + now_path = (os.path.dirname(now_path)) + while directory: + crumbs.insert(0, (os.path.basename(directory), now_path+'/')) + directory = os.path.dirname(directory) + now_path = os.path.dirname(now_path) + crumbs.insert(0, ('media', now_path)) + else: + crumbs = [('media',)] + return crumbs + + def get_url(self, filename): + """Finds URL of a file in browsed dir.""" + return settings.MEDIA_URL + self.get_directory() + quote(filename.encode('utf-8')) + + @method_decorator(vary_on_headers('Accept')) def dispatch(self, request, *args, **kwargs): self.object = self.get_object(request, *args, **kwargs) return super(UploadView, self).dispatch(request, *args, **kwargs) @@ -38,37 +102,51 @@ class UploadView(FormView): def get(self, request, *args, **kwargs): if request.is_ajax(): files = [] - path = self.get_safe_path() if os.path.isdir(path): - for f in os.listdir(path): - files.append({ + for f in sorted(os.listdir(path)): + file_info = { "name": f, - "url": self.get_url(f), - 'thumbnail_url': self.get_url(f), # FIXME: thumb! - 'delete_url': "%s?file=%s" % (request.get_full_path(), f), # FIXME: encode - 'delete_type': "DELETE" - }) + } + if os.path.isdir(os.path.join(path, f)): + file_info.update({ + "url": "%s%s/" % (request.get_full_path(), f), + }) + else: + thumbnail_url = thumbnail(self.get_directory() + f) + file_info.update({ + "url": self.get_url(f), + 'thumbnail_url': thumbnail_url, + 'delete_url': "%s?file=%s" % ( + request.get_full_path(), + quote(f.encode('utf-8'))), + 'delete_type': "DELETE" + }) + files.append(file_info) return JSONResponse(files) else: return super(UploadView, self).get(request, *args, **kwargs) def form_valid(self, form): - f = self.request.FILES.get('file') + flist = self.request.FILES.getlist('files') path = self.get_safe_path() - if not os.path.isdir(path): os.makedirs(path) - with open(self.get_safe_path(f.name), 'w') as destination: - for chunk in f.chunks(): - destination.write(chunk) - data = [{ - 'name': f.name, - 'url': self.get_url(f.name), - 'thumbnail_url': self.get_url(f.name), # FIXME: thumb! - 'delete_url': "%s?file=%s" % (self.request.get_full_path(), f.name), # FIXME: encode - 'delete_type': "DELETE" - }] + data = [] + for f in flist: + f.name = unidecode(f.name) + with open(self.get_safe_path(f.name), 'w') as destination: + for chunk in f.chunks(): + destination.write(chunk) + data.append({ + 'name': f.name, + 'url': self.get_url(f.name), + 'thumbnail_url': thumbnail(self.get_directory() + f.name), + 'delete_url': "%s?file=%s" % ( + self.request.get_full_path(), + quote(f.name.encode('utf-8'))), + 'delete_type': "DELETE", + }) response = JSONResponse(data) response['Content-Disposition'] = 'inline; filename=files.json' return response @@ -78,3 +156,18 @@ class UploadView(FormView): response = JSONResponse(True) response['Content-Disposition'] = 'inline; filename=files.json' return response + + +class PackageView(UploadViewMixin, RedirectView): + # usage of RedirectView here is really really ugly + permanent = False + + def dispatch(self, request, *args, **kwargs): + self.object = self.get_object(request, *args, **kwargs) + path = self.get_safe_path() + with ZipFile(os.path.join(path, 'package.zip'), 'w') as zip_file: + for f in os.listdir(path): + if f == 'package.zip': + continue + zip_file.write(os.path.join(path, f), arcname=f) + return super(PackageView, self).dispatch(request, *args, **kwargs)