diff --git a/backend/backend/urls.py b/backend/backend/urls.py index 24ee4d9..1cea34e 100644 --- a/backend/backend/urls.py +++ b/backend/backend/urls.py @@ -36,5 +36,6 @@ urlpatterns = [ path('api/', include('toolshed.api.inventory')), path('api/', include('toolshed.api.info')), path('api/', include('toolshed.api.files')), + path('media/', include('files.media_urls')), path('docs/', schema_view.with_ui('swagger', cache_timeout=0), name='api-docs'), ] diff --git a/backend/files/media_urls.py b/backend/files/media_urls.py new file mode 100644 index 0000000..4fe8cac --- /dev/null +++ b/backend/files/media_urls.py @@ -0,0 +1,22 @@ +from django.urls import path +from rest_framework import status +from rest_framework.decorators import api_view +from rest_framework.response import Response + +from files.models import File + + +@api_view(['GET']) +def media_urls(request, id, format=None): + try: + file = File.objects.get(file=id) + return Response(status=status.HTTP_200_OK, + headers={'X-Accel-Redirect': f'/redirect_media/{id}'}) # TODO Expires and Cache-Control + + except File.DoesNotExist: + return Response(status=status.HTTP_404_NOT_FOUND) + + +urlpatterns = [ + path('', media_urls), +] diff --git a/backend/files/tests.py b/backend/files/tests.py index 10d7a2d..beac217 100644 --- a/backend/files/tests.py +++ b/backend/files/tests.py @@ -2,7 +2,7 @@ from django.core.files.base import ContentFile from django.core.files.storage import DefaultStorage from django.db import IntegrityError, transaction from django.test import Client -from authentication.tests import SignatureAuthClient, ToolshedTestCase +from authentication.tests import SignatureAuthClient, ToolshedTestCase, UserTestMixin from nacl.hash import sha256 from nacl.encoding import HexEncoder import base64 @@ -95,7 +95,7 @@ class FilesTestCase(FilesTestMixin, ToolshedTestCase): self.assertTrue(created) self.assertEqual(file.file.read(), self.f['test_content4']) self.assertEqual(file.file.name, - f"{self.f['hash4'][:2]}/{self.f['hash4'][2:4]}/{self.f['hash4'][4:6]}/{self.f['hash4'][6:]}") + f"{self.f['hash4'][:2]}/{self.f['hash4'][2:4]}/{self.f['hash4'][4:6]}/{self.f['hash4'][6:]}") def test_file_upload_get_or_create_fail(self): with transaction.atomic(): @@ -103,3 +103,31 @@ class FilesTestCase(FilesTestMixin, ToolshedTestCase): File.objects.get_or_create(hash=self.f['hash3']) self.assertEqual(File.objects.count(), 3) self.assertEqual(countdir(DefaultStorage(), ''), 3) + + +class MediaUrlTestCase(FilesTestMixin, UserTestMixin, ToolshedTestCase): + def setUp(self): + super().setUp() + self.prepare_files() + self.prepare_users() + + def test_file_url(self): + reply = client.get( + f"/media/{self.f['hash1'][:2]}/{self.f['hash1'][2:4]}/{self.f['hash1'][4:6]}/{self.f['hash1'][6:]}", + self.f['local_user1']) + self.assertEqual(reply.status_code, 200) + self.assertEqual(reply.headers['X-Accel-Redirect'], + f"/redirect_media/{self.f['hash1'][:2]}/{self.f['hash1'][2:4]}/{self.f['hash1'][4:6]}/{self.f['hash1'][6:]}") + reply = client.get( + f"/media/{self.f['hash2'][:2]}/{self.f['hash2'][2:4]}/{self.f['hash2'][4:6]}/{self.f['hash2'][6:]}", + self.f['local_user1']) + self.assertEqual(reply.status_code, 200) + self.assertEqual(reply.headers['X-Accel-Redirect'], + f"/redirect_media/{self.f['hash2'][:2]}/{self.f['hash2'][2:4]}/{self.f['hash2'][4:6]}/{self.f['hash2'][6:]}") + + def test_file_url_fail(self): + reply = client.get('/media/{}/'.format('nonexistent'), self.f['local_user1']) + self.assertEqual(reply.status_code, 404) + self.assertTrue('X-Accel-Redirect' not in reply.headers) + +