1 # -*- coding: utf-8 -*-
3 # This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
4 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
8 from urllib import quote
9 from django.conf import settings
10 from django.http import HttpResponse, Http404
11 from django.utils.decorators import method_decorator
12 from django.views.decorators.vary import vary_on_headers
13 from django.views.generic import FormView
14 from .forms import UploadForm
17 # Use sorl.thumbnail if available.
19 from sorl.thumbnail import default
21 def thumbnail(relpath):
22 return settings.MEDIA_URL + relpath
24 def thumbnail(relpath):
26 thumb = default.backend.get_thumbnail(relpath, "x50")
27 if not thumb.exists():
28 # That's not an image. No thumb.
32 # That's not an image. No thumb.
36 class JSONResponse(HttpResponse):
37 """JSON response class."""
38 def __init__(self, obj='', mimetype="application/json", *args, **kwargs):
39 content = json.dumps(obj)
40 super(JSONResponse, self).__init__(content, mimetype, *args, **kwargs)
43 class UploadViewMixin(object):
44 def get_safe_path(self, filename=""):
45 """Finds absolute filesystem path of the browsed dir of file.
47 Makes sure it's inside MEDIA_ROOT.
50 path = os.path.abspath(os.path.join(
54 if not path.startswith(os.path.abspath(settings.MEDIA_ROOT)):
57 if not path.startswith(self.get_safe_path()):
62 class UploadView(UploadViewMixin, FormView):
63 template_name = "fileupload/picture_form.html"
64 form_class = UploadForm
66 def get_object(self, request, *args, **kwargs):
67 """Get any data for later use."""
70 def get_directory(self):
71 """Directory relative to MEDIA_ROOT. Must end with a slash."""
72 return self.kwargs['path']
74 def breadcrumbs(self):
75 """List of tuples (name, url) or just (name,) for breadcrumbs.
77 Probably only the last item (representing currently browsed dir)
81 directory = self.get_directory()
82 now_path = os.path.dirname(self.request.get_full_path())
83 directory = os.path.dirname(directory)
86 (os.path.basename(directory),)
88 directory = os.path.dirname(directory)
89 now_path = (os.path.dirname(now_path))
91 crumbs.insert(0, (os.path.basename(directory), now_path + '/'))
92 directory = os.path.dirname(directory)
93 now_path = os.path.dirname(now_path)
94 crumbs.insert(0, ('media', now_path))
99 def get_url(self, filename):
100 """Finds URL of a file in browsed dir."""
101 return settings.MEDIA_URL + self.get_directory() + quote(filename.encode('utf-8'))
103 @method_decorator(vary_on_headers('Accept'))
104 def dispatch(self, request, *args, **kwargs):
105 self.object = self.get_object(request, *args, **kwargs)
106 return super(UploadView, self).dispatch(request, *args, **kwargs)
108 def get(self, request, *args, **kwargs):
109 if request.is_ajax():
111 path = self.get_safe_path()
112 if os.path.isdir(path):
113 for f in sorted(os.listdir(path)):
117 if os.path.isdir(os.path.join(path, f)):
119 "url": "%s%s/" % (request.get_full_path(), f),
123 "url": self.get_url(f),
124 'thumbnail_url': thumbnail(self.get_directory() + f),
125 'delete_url': "%s?file=%s" % (
126 request.get_full_path(),
127 quote(f.encode('utf-8'))),
128 'delete_type': "DELETE"
130 files.append(file_info)
131 return JSONResponse(files)
133 return super(UploadView, self).get(request, *args, **kwargs)
135 def form_valid(self, form):
136 flist = self.request.FILES.getlist('files')
137 path = self.get_safe_path()
138 if not os.path.isdir(path):
142 with open(self.get_safe_path(f.name), 'w') as destination:
143 for chunk in f.chunks():
144 destination.write(chunk)
147 'url': self.get_url(f.name),
148 'thumbnail_url': thumbnail(self.get_directory() + f.name),
149 'delete_url': "%s?file=%s" % (
150 self.request.get_full_path(),
151 quote(f.name.encode('utf-8'))),
152 'delete_type': "DELETE"
154 response = JSONResponse(data)
155 response['Content-Disposition'] = 'inline; filename=files.json'
158 def delete(self, request, *args, **kwargs):
159 os.unlink(self.get_safe_path(request.GET.get('file')))
160 response = JSONResponse(True)
161 response['Content-Disposition'] = 'inline; filename=files.json'