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 unidecode import unidecode
16 from .forms import UploadForm
19 # Use sorl.thumbnail if available.
21 from sorl.thumbnail import default
23 def thumbnail(relpath):
24 return settings.MEDIA_URL + relpath
26 def thumbnail(relpath):
28 thumb = default.backend.get_thumbnail(relpath, "x50")
29 if not thumb.exists():
30 # That's not an image. No thumb.
34 # That's not an image. No thumb.
38 class JSONResponse(HttpResponse):
39 """JSON response class."""
40 def __init__(self, obj='', mimetype="application/json", *args, **kwargs):
41 content = json.dumps(obj)
42 super(JSONResponse, self).__init__(content, mimetype, *args, **kwargs)
45 class UploadViewMixin(object):
46 def get_safe_path(self, filename=""):
47 """Finds absolute filesystem path of the browsed dir of file.
49 Makes sure it's inside MEDIA_ROOT.
52 path = os.path.abspath(os.path.join(
56 if not path.startswith(os.path.abspath(settings.MEDIA_ROOT)):
59 if not path.startswith(self.get_safe_path()):
64 class UploadView(UploadViewMixin, FormView):
65 template_name = "fileupload/picture_form.html"
66 form_class = UploadForm
68 def get_object(self, request, *args, **kwargs):
69 """Get any data for later use."""
72 def get_directory(self):
73 """Directory relative to MEDIA_ROOT. Must end with a slash."""
74 return self.kwargs['path']
76 def breadcrumbs(self):
77 """List of tuples (name, url) or just (name,) for breadcrumbs.
79 Probably only the last item (representing currently browsed dir)
83 directory = self.get_directory()
84 now_path = os.path.dirname(self.request.get_full_path())
85 directory = os.path.dirname(directory)
88 (os.path.basename(directory),)
90 directory = os.path.dirname(directory)
91 now_path = (os.path.dirname(now_path))
93 crumbs.insert(0, (os.path.basename(directory), now_path + '/'))
94 directory = os.path.dirname(directory)
95 now_path = os.path.dirname(now_path)
96 crumbs.insert(0, ('media', now_path))
101 def get_url(self, filename):
102 """Finds URL of a file in browsed dir."""
103 return settings.MEDIA_URL + self.get_directory() + quote(filename.encode('utf-8'))
105 @method_decorator(vary_on_headers('Accept'))
106 def dispatch(self, request, *args, **kwargs):
107 self.object = self.get_object(request, *args, **kwargs)
108 return super(UploadView, self).dispatch(request, *args, **kwargs)
110 def get(self, request, *args, **kwargs):
111 if request.is_ajax():
113 path = self.get_safe_path()
114 if os.path.isdir(path):
115 for f in sorted(os.listdir(path)):
119 if os.path.isdir(os.path.join(path, f)):
121 "url": "%s%s/" % (request.get_full_path(), f),
125 "url": self.get_url(f),
126 'thumbnail_url': thumbnail(self.get_directory() + f),
127 'delete_url': "%s?file=%s" % (
128 request.get_full_path(),
129 quote(f.encode('utf-8'))),
130 'delete_type': "DELETE"
132 files.append(file_info)
133 return JSONResponse(files)
135 return super(UploadView, self).get(request, *args, **kwargs)
137 def form_valid(self, form):
138 flist = self.request.FILES.getlist('files')
139 path = self.get_safe_path()
140 if not os.path.isdir(path):
144 f.name = unidecode(f.name)
145 with open(self.get_safe_path(f.name), 'w') as destination:
146 for chunk in f.chunks():
147 destination.write(chunk)
150 'url': self.get_url(f.name),
151 'thumbnail_url': thumbnail(self.get_directory() + f.name),
152 'delete_url': "%s?file=%s" % (
153 self.request.get_full_path(),
154 quote(f.name.encode('utf-8'))),
155 'delete_type': "DELETE"
157 response = JSONResponse(data)
158 response['Content-Disposition'] = 'inline; filename=files.json'
161 def delete(self, request, *args, **kwargs):
162 os.unlink(self.get_safe_path(request.GET.get('file')))
163 response = JSONResponse(True)
164 response['Content-Disposition'] = 'inline; filename=files.json'