1 # This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
6 from urllib.parse import quote
7 from django.conf import settings
8 from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
9 from django.utils.decorators import method_decorator
10 from django.views.decorators.vary import vary_on_headers
11 from django.views.generic import FormView, View
12 from .forms import UploadForm
15 # Use sorl.thumbnail if available.
17 from sorl.thumbnail import default
19 def thumbnail(relpath):
20 return settings.MEDIA_URL + relpath
22 def thumbnail(relpath):
24 return default.backend.get_thumbnail(relpath, "x50").url
25 except (IOError, ValueError):
26 # That's not an image. No thumb.
30 class JSONResponse(HttpResponse):
31 """JSON response class."""
32 def __init__(self, obj='', mimetype="application/json", *args, **kwargs):
33 content = json.dumps(obj)
34 super(JSONResponse, self).__init__(content, mimetype, *args, **kwargs)
37 class UploadView(FormView):
38 template_name = "fileupload/picture_form.html"
39 form_class = UploadForm
41 def get_object(self, request, *args, **kwargs):
42 """Get any data for later use."""
45 def get_directory(self):
46 """Directory relative to MEDIA_ROOT. Must end with a slash."""
47 return self.kwargs['path']
49 def breadcrumbs(self):
50 """List of tuples (name, url) or just (name,) for breadcrumbs.
52 Probably only the last item (representing currently browsed dir)
56 directory = self.get_directory()
57 now_path = os.path.dirname(self.request.get_full_path())
58 directory = os.path.dirname(directory)
61 (os.path.basename(directory),)
63 directory = os.path.dirname(directory)
64 now_path = (os.path.dirname(now_path))
66 crumbs.insert(0, (os.path.basename(directory), now_path+'/'))
67 directory = os.path.dirname(directory)
68 now_path = os.path.dirname(now_path)
69 crumbs.insert(0, ('media', now_path))
74 def get_safe_path(self, filename=""):
75 """Finds absolute filesystem path of the browsed dir of file.
77 Makes sure it's inside MEDIA_ROOT.
80 path = os.path.abspath(os.path.join(
84 if not path.startswith(settings.MEDIA_ROOT):
87 if not path.startswith(self.get_safe_path()):
91 def get_url(self, filename):
92 """Finds URL of a file in browsed dir."""
93 return settings.MEDIA_URL + self.get_directory() + quote(filename.encode('utf-8'))
95 @method_decorator(vary_on_headers('Accept'))
96 def dispatch(self, request, *args, **kwargs):
97 self.object = self.get_object(request, *args, **kwargs)
98 return super(UploadView, self).dispatch(request, *args, **kwargs)
100 def get(self, request, *args, **kwargs):
101 if request.is_ajax():
103 path = self.get_safe_path()
104 if os.path.isdir(path):
105 for f in sorted(os.listdir(path)):
109 if os.path.isdir(os.path.join(path, f)):
111 "url": "%s%s/" % (request.get_full_path(), f),
115 "url": self.get_url(f),
116 'thumbnail_url': thumbnail(self.get_directory() + f),
117 'delete_url': "%s?file=%s" % (
118 request.get_full_path(),
119 quote(f.encode('utf-8'))),
120 'delete_type': "DELETE"
122 thumbnail_url = thumbnail(self.get_directory() + f),
123 files.append(file_info)
124 return JSONResponse(files)
126 return super(UploadView, self).get(request, *args, **kwargs)
128 def form_valid(self, form):
129 flist = self.request.FILES.getlist('files')
130 path = self.get_safe_path()
131 if not os.path.isdir(path):
135 with open(self.get_safe_path(f.name), 'wb') as destination:
136 for chunk in f.chunks():
137 destination.write(chunk)
140 'url': self.get_url(f.name),
141 'thumbnail_url': thumbnail(self.get_directory() + f.name),
142 'delete_url': "%s?file=%s" % (
143 self.request.get_full_path(),
144 quote(f.name.encode('utf-8'))),
145 'delete_type': "DELETE"
147 response = JSONResponse(data)
148 response['Content-Disposition'] = 'inline; filename=files.json'
151 def delete(self, request, *args, **kwargs):
152 os.unlink(self.get_safe_path(request.GET.get('file')))
153 response = JSONResponse(True)
154 response['Content-Disposition'] = 'inline; filename=files.json'