From 7352df66c735debe67efbb09726eab1c63bea1ae Mon Sep 17 00:00:00 2001
From: Parbhat Puri <parbhatpuri17@gmail.com>
Date: Tue, 28 May 2019 07:06:34 +0000
Subject: [PATCH] Serve private media in same URL instead of redirect

---
 opentech/apply/funds/urls.py  |  4 ++--
 opentech/apply/funds/views.py | 29 ++++++++++++++++++++++++-----
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/opentech/apply/funds/urls.py b/opentech/apply/funds/urls.py
index dd75bcd4a..386993422 100644
--- a/opentech/apply/funds/urls.py
+++ b/opentech/apply/funds/urls.py
@@ -12,7 +12,7 @@ from .views import (
     SubmissionOverviewView,
     SubmissionSealedView,
     SubmissionDeleteView,
-    SubmissionPrivateMediaRedirectView,
+    SubmissionPrivateMediaView,
 )
 from .api_views import (
     CommentEdit,
@@ -39,7 +39,7 @@ submission_urls = ([
     path('all/', SubmissionListView.as_view(), name="list"),
     path(
         'documents/submission/<int:submission_id>/<uuid:field_id>/<str:file_name>/',
-        SubmissionPrivateMediaRedirectView.as_view(), name='private_media_redirect'
+        SubmissionPrivateMediaView.as_view(), name='serve_private_media'
     ),
     path('<int:pk>/', include([
         path('', SubmissionDetailView.as_view(), name="detail"),
diff --git a/opentech/apply/funds/views.py b/opentech/apply/funds/views.py
index 135988c9c..a5de558a1 100644
--- a/opentech/apply/funds/views.py
+++ b/opentech/apply/funds/views.py
@@ -1,4 +1,6 @@
+import mimetypes
 from copy import copy
+from wsgiref.util import FileWrapper
 
 from django.conf import settings
 from django.contrib.auth.decorators import login_required, permission_required
@@ -8,13 +10,13 @@ from django.contrib import messages
 from django.core.exceptions import PermissionDenied
 from django.core.files.storage import get_storage_class
 from django.db.models import Count, F, Q
-from django.http import HttpResponseRedirect, Http404
+from django.http import HttpResponseRedirect, Http404, StreamingHttpResponse
 from django.shortcuts import get_object_or_404
 from django.urls import reverse_lazy
 from django.utils.decorators import method_decorator
 from django.utils.text import mark_safe
 from django.utils.translation import ugettext_lazy as _
-from django.views.generic import DetailView, FormView, ListView, UpdateView, DeleteView, RedirectView
+from django.views.generic import DetailView, FormView, ListView, UpdateView, DeleteView, View
 
 from django_filters.views import FilterView
 from django_tables2.views import SingleTableMixin
@@ -831,15 +833,32 @@ class SubmissionDeleteView(DeleteView):
         return response
 
 
-class SubmissionPrivateMediaRedirectView(UserPassesTestMixin, RedirectView):
+class SubmissionPrivateMediaView(UserPassesTestMixin, View):
 
-    def get_redirect_url(self, *args, **kwargs):
+    def get(self, *args, **kwargs):
         submission_id = kwargs['submission_id']
         field_id = kwargs['field_id']
         file_name = kwargs['file_name']
         file_name_with_path = f'submission/{submission_id}/{field_id}/{file_name}'
 
-        return submission_storage.url(file_name_with_path)
+        submission_file = submission_storage.open(file_name_with_path)
+        wrapper = FileWrapper(submission_file)
+        encoding_map = {
+            'bzip2': 'application/x-bzip',
+            'gzip': 'application/gzip',
+            'xz': 'application/x-xz',
+        }
+        content_type, encoding = mimetypes.guess_type(file_name)
+        # Encoding isn't set to prevent browsers from automatically uncompressing files.
+        content_type = encoding_map.get(encoding, content_type)
+        content_type = content_type or 'application/octet-stream'
+        # From Django 2.1, we can use FileResponse instead of StreamingHttpResponse
+        response = StreamingHttpResponse(wrapper, content_type=content_type)
+
+        response['Content-Disposition'] = f'filename={file_name}'
+        response['Content-Length'] = submission_file.size
+
+        return response
 
     def test_func(self):
         submission_id = self.kwargs['submission_id']
-- 
GitLab