From 7d8f30311679be91424a786f3536ef7e31276e02 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Mon, 11 Dec 2017 16:07:06 +0100
Subject: [PATCH] possibility to upload files that are served by django

---
 .gitignore                              |  3 +++
 smash/web/models/constants.py           |  4 ++++
 smash/web/urls.py                       |  6 ++++++
 smash/web/views/__init__.py             |  1 +
 smash/web/views/uploaded_files.py       | 25 ++++++++++++++++++++++++
 smash/web/widgets/__init__.py           |  0
 smash/web/widgets/secure_file_widget.py | 26 +++++++++++++++++++++++++
 7 files changed, 65 insertions(+)
 create mode 100644 smash/web/views/uploaded_files.py
 create mode 100644 smash/web/widgets/__init__.py
 create mode 100644 smash/web/widgets/secure_file_widget.py

diff --git a/.gitignore b/.gitignore
index 7230e12f..a988c9e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,9 @@ env/*
 # Folder with db statics (dev mode)
 smash/~/
 
+# files uploaded and hosted by django
+smash/uploads/
+
 # Disable python bytecode
 *.pyc
 #vim swap files
diff --git a/smash/web/models/constants.py b/smash/web/models/constants.py
index 57794ce9..5db58bb9 100644
--- a/smash/web/models/constants.py
+++ b/smash/web/models/constants.py
@@ -1,6 +1,8 @@
 # coding=utf-8
 import locale
 
+from django.core.files.storage import FileSystemStorage
+
 BOOL_CHOICES = ((True, 'Yes'), (False, 'No'))
 SEX_CHOICES_MALE = 'M'
 SEX_CHOICES_FEMALE = 'F'
@@ -90,3 +92,5 @@ VOUCHER_STATUS_CHOICES = (
     (VOUCHER_STATUS_USED, 'Used'),
     (VOUCHER_STATUS_EXPIRED, 'Expired'),
 )
+
+FILE_STORAGE = FileSystemStorage(location='uploads')
diff --git a/smash/web/urls.py b/smash/web/urls.py
index 1ee0abb3..567ef50b 100644
--- a/smash/web/urls.py
+++ b/smash/web/urls.py
@@ -206,6 +206,12 @@ urlpatterns = [
 
     url(r'^configuration$', views.configuration_item.configuration_items, name='web.views.configuration'),
 
+    ####################
+    #       FILES      #
+    ####################
+
+    url(r'^files/', views.uploaded_files.download, name='web.views.uploaded_files'),
+
     ####################
     #       AUTH       #
     ####################
diff --git a/smash/web/views/__init__.py b/smash/web/views/__init__.py
index 6f232ada..296d4e9f 100644
--- a/smash/web/views/__init__.py
+++ b/smash/web/views/__init__.py
@@ -81,3 +81,4 @@ import voucher
 import voucher_type
 import voucher_type_price
 import redcap
+import uploaded_files
diff --git a/smash/web/views/uploaded_files.py b/smash/web/views/uploaded_files.py
new file mode 100644
index 00000000..e20a022a
--- /dev/null
+++ b/smash/web/views/uploaded_files.py
@@ -0,0 +1,25 @@
+# coding=utf-8
+import logging
+import ntpath
+from wsgiref.util import FileWrapper
+
+from django.contrib.auth.decorators import login_required
+from django.http import HttpResponse
+
+from web.models.constants import FILE_STORAGE
+
+logger = logging.getLogger(__name__)
+
+
+def path_to_filename(path):
+    head, tail = ntpath.split(path)
+    return tail or ntpath.basename(head)
+
+
+@login_required
+def download(request):
+    if request.GET and request.GET.get('file'):
+        path = FILE_STORAGE.location + "/" + request.GET.get('file')
+        response = HttpResponse(FileWrapper(open(path, 'r')), content_type='application/force-download')
+        response['Content-Disposition'] = 'attachment; filename=%s' % path_to_filename(path)
+        return response
diff --git a/smash/web/widgets/__init__.py b/smash/web/widgets/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/smash/web/widgets/secure_file_widget.py b/smash/web/widgets/secure_file_widget.py
new file mode 100644
index 00000000..d26d799f
--- /dev/null
+++ b/smash/web/widgets/secure_file_widget.py
@@ -0,0 +1,26 @@
+import logging
+
+from django import forms
+from django.core.urlresolvers import reverse
+from django.utils.safestring import mark_safe
+from django.utils.translation import ugettext_lazy as _
+
+logger = logging.getLogger(__name__)
+
+
+class SecuredFileWidget(forms.FileInput):
+    """A FileField Widget that shows secure file link"""
+
+    def __init__(self, attrs=None):
+        if attrs is None:
+            attrs = {}
+        super(SecuredFileWidget, self).__init__(attrs)
+
+    def render(self, name, value, attrs=None):
+        output = []
+        if value and hasattr(value, "url"):
+            url = reverse('web.views.uploaded_files') + '?file=' + unicode(value)
+            out = u'<a href="{}">{}</a><br />{} '
+            output.append(out.format(url, _(u'Download'), _(u'Change:')))
+        output.append(super(SecuredFileWidget, self).render(name, value, attrs))
+        return mark_safe(u''.join(output))
-- 
GitLab