Refactor and implement download code natively
- Use modified port of Django 2.2 FileResponse. - Remove Django DownloadView library. Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import types
|
||||
|
||||
from django.conf import settings
|
||||
from django.http.response import StreamingHttpResponse
|
||||
from django.utils import six
|
||||
from django.utils.six.moves.urllib.parse import quote
|
||||
|
||||
from mayan.apps.mimetype.api import get_mimetype
|
||||
|
||||
if six.PY3:
|
||||
dict_type = dict
|
||||
@@ -22,3 +28,75 @@ except NameError:
|
||||
FileNotFoundErrorException = IOError
|
||||
else:
|
||||
FileNotFoundErrorException = FileNotFoundError # NOQA
|
||||
|
||||
|
||||
class FileResponse(StreamingHttpResponse):
|
||||
"""
|
||||
Port of Django's 2.2 FileResponse
|
||||
Modified to allows downloading non file like content as attachment
|
||||
A streaming HTTP response class optimized for files.
|
||||
TODO: To be remove when the code moves to Django 2.2
|
||||
"""
|
||||
block_size = 4096
|
||||
|
||||
def __init__(self, as_attachment=False, filename='', *args, **kwargs):
|
||||
self.as_attachment = as_attachment
|
||||
self.filename = filename
|
||||
super(FileResponse, self).__init__(*args, **kwargs)
|
||||
|
||||
def _set_as_attachment(self, filename):
|
||||
if self.as_attachment:
|
||||
filename = self.filename or os.path.basename(filename)
|
||||
if filename:
|
||||
try:
|
||||
filename.encode('ascii')
|
||||
file_expr = 'filename="{}"'.format(filename)
|
||||
except UnicodeEncodeError:
|
||||
file_expr = "filename*=utf-8''{}".format(quote(filename))
|
||||
self['Content-Disposition'] = 'attachment; {}'.format(file_expr)
|
||||
|
||||
def _set_streaming_content(self, value):
|
||||
if not hasattr(value, 'read'):
|
||||
self.file_to_stream = None
|
||||
result = super(FileResponse, self)._set_streaming_content(value)
|
||||
self._set_as_attachment(filename=self.filename)
|
||||
|
||||
return result
|
||||
|
||||
self.file_to_stream = filelike = value
|
||||
if hasattr(filelike, 'close'):
|
||||
self._closable_objects.append(filelike)
|
||||
value = iter(lambda: filelike.read(self.block_size), b'')
|
||||
self.set_headers(filelike)
|
||||
super(FileResponse, self)._set_streaming_content(value)
|
||||
|
||||
def set_headers(self, filelike):
|
||||
"""
|
||||
Set some common response headers (Content-Length, Content-Type, and
|
||||
Content-Disposition) based on the `filelike` response content.
|
||||
"""
|
||||
encoding_map = {
|
||||
'bzip2': 'application/x-bzip',
|
||||
'gzip': 'application/gzip',
|
||||
'xz': 'application/x-xz',
|
||||
}
|
||||
filename = getattr(filelike, 'name', None)
|
||||
filename = filename if (isinstance(filename, str) and filename) else self.filename
|
||||
if os.path.isabs(filename):
|
||||
self['Content-Length'] = os.path.getsize(filelike.name)
|
||||
elif hasattr(filelike, 'getbuffer'):
|
||||
self['Content-Length'] = filelike.getbuffer().nbytes
|
||||
|
||||
if self.get('Content-Type', '').startswith(settings.DEFAULT_CONTENT_TYPE):
|
||||
if self.file_to_stream:
|
||||
content_type, encoding = get_mimetype(
|
||||
file_object=self.file_to_stream, mimetype_only=True
|
||||
)
|
||||
# Encoding isn't set to prevent browsers from automatically
|
||||
# uncompressing files.
|
||||
content_type = encoding_map.get(encoding, content_type)
|
||||
self['Content-Type'] = content_type or 'application/octet-stream'
|
||||
else:
|
||||
self['Content-Type'] = 'application/octet-stream'
|
||||
|
||||
self._set_as_attachment(filename=filename)
|
||||
|
||||
Reference in New Issue
Block a user