From 73df8059a5e14ed2bd628fe7ee8e4a26a3d631cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Valenta?= <git@imaniti.org>
Date: Wed, 22 Mar 2023 12:05:12 +0100
Subject: [PATCH] serve media files through app

---
 .../0009_alter_contractfile_file.py           | 18 ++++++++++++
 contracts/models.py                           |  2 +-
 media_server/__init__.py                      |  0
 media_server/admin.py                         |  3 ++
 media_server/apps.py                          |  6 ++++
 media_server/migrations/__init__.py           |  0
 media_server/models.py                        |  3 ++
 media_server/tests.py                         |  3 ++
 media_server/urls.py                          | 12 ++++++++
 media_server/views.py                         | 28 +++++++++++++++++++
 nginx.conf                                    |  9 ------
 registry/settings/base.py                     |  1 +
 registry/urls.py                              |  1 +
 13 files changed, 76 insertions(+), 10 deletions(-)
 create mode 100644 contracts/migrations/0009_alter_contractfile_file.py
 create mode 100644 media_server/__init__.py
 create mode 100644 media_server/admin.py
 create mode 100644 media_server/apps.py
 create mode 100644 media_server/migrations/__init__.py
 create mode 100644 media_server/models.py
 create mode 100644 media_server/tests.py
 create mode 100644 media_server/urls.py
 create mode 100644 media_server/views.py

diff --git a/contracts/migrations/0009_alter_contractfile_file.py b/contracts/migrations/0009_alter_contractfile_file.py
new file mode 100644
index 0000000..798582d
--- /dev/null
+++ b/contracts/migrations/0009_alter_contractfile_file.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.1.4 on 2023-03-22 10:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contracts', '0008_alter_contracteesignaturerepresentative_options_and_more'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='contractfile',
+            name='file',
+            field=models.FileField(upload_to='_private/', verbose_name='Soubor'),
+        ),
+    ]
diff --git a/contracts/models.py b/contracts/models.py
index 811b5a5..9fe9d08 100644
--- a/contracts/models.py
+++ b/contracts/models.py
@@ -532,7 +532,7 @@ class ContractFile(NameStrMixin, models.Model):
 
     file = models.FileField(
         verbose_name="Soubor",
-        upload_to="private/",
+        upload_to="_private/",
     )
 
     contract = models.ForeignKey(
diff --git a/media_server/__init__.py b/media_server/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/media_server/admin.py b/media_server/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/media_server/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/media_server/apps.py b/media_server/apps.py
new file mode 100644
index 0000000..6a7dc44
--- /dev/null
+++ b/media_server/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class MediaServerConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'media_server'
diff --git a/media_server/migrations/__init__.py b/media_server/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/media_server/models.py b/media_server/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/media_server/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/media_server/tests.py b/media_server/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/media_server/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/media_server/urls.py b/media_server/urls.py
new file mode 100644
index 0000000..23bb64a
--- /dev/null
+++ b/media_server/urls.py
@@ -0,0 +1,12 @@
+from django.urls import path
+
+from . import views
+
+app_name = "media_server"
+urlpatterns = [
+    path(
+        "<path:path>",
+        views.view_media,
+        name="view_media",
+    ),
+]
diff --git a/media_server/views.py b/media_server/views.py
new file mode 100644
index 0000000..e803d56
--- /dev/null
+++ b/media_server/views.py
@@ -0,0 +1,28 @@
+import os
+
+from django.core.files.storage import FileSystemStorage
+from django_downloadview import StorageDownloadView
+from django_http_exceptions import HTTPExceptions
+
+
+# Create your views here.
+
+storage = FileSystemStorage()
+
+
+class MediaView(StorageDownloadView):
+    attachment = False
+
+    def get_path(self, *args, **kwargs) -> str:
+        path = super().get_path(*args, **kwargs)
+
+        # Make sure path is clean
+        path = os.path.normpath(path)
+
+        if path.startswith("_"):  # Private path
+            raise HTTPExceptions.NOT_FOUND
+
+        return path
+
+
+view_media = MediaView.as_view(storage=storage)
diff --git a/nginx.conf b/nginx.conf
index dd8e8f0..4725c76 100644
--- a/nginx.conf
+++ b/nginx.conf
@@ -20,13 +20,4 @@ server {
         proxy_set_header X-Forwarded-Proto https;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     }
-
-    location /media/ {
-        alias /var/opt/contract_registry/media/
-    }
-
-    location ~ /media/private/ {
-        deny all;
-        return 404;
-    }
 }
diff --git a/registry/settings/base.py b/registry/settings/base.py
index 576b301..7c54586 100644
--- a/registry/settings/base.py
+++ b/registry/settings/base.py
@@ -64,6 +64,7 @@ INSTALLED_APPS = [
     "markdownx",
     "pirates",
     "webpack_loader",
+    "media_server",
     "shared",
     "contracts",
     "oidc",
diff --git a/registry/urls.py b/registry/urls.py
index ed9a38a..c12fecc 100644
--- a/registry/urls.py
+++ b/registry/urls.py
@@ -28,5 +28,6 @@ urlpatterns = [
     path("", include("users.urls")),
     path("markdownx/", include("markdownx.urls")),
     path("oidc/", include("oidc.urls")),
+    path("media/", include("media_server.urls")),
     path("admin/", admin.site.urls),
 ] + pirates_urlpatterns
-- 
GitLab