add media endpoint for XSendfile
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
j3d1 2023-10-23 23:51:30 +02:00
parent cc0bdc0472
commit d411e6790d
3 changed files with 53 additions and 2 deletions

View file

@ -36,5 +36,6 @@ urlpatterns = [
path('api/', include('toolshed.api.inventory')), path('api/', include('toolshed.api.inventory')),
path('api/', include('toolshed.api.info')), path('api/', include('toolshed.api.info')),
path('api/', include('toolshed.api.files')), 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'), path('docs/', schema_view.with_ui('swagger', cache_timeout=0), name='api-docs'),
] ]

View file

@ -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('<path:id>', media_urls),
]

View file

@ -2,7 +2,7 @@ from django.core.files.base import ContentFile
from django.core.files.storage import DefaultStorage from django.core.files.storage import DefaultStorage
from django.db import IntegrityError, transaction from django.db import IntegrityError, transaction
from django.test import Client 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.hash import sha256
from nacl.encoding import HexEncoder from nacl.encoding import HexEncoder
import base64 import base64
@ -95,7 +95,7 @@ class FilesTestCase(FilesTestMixin, ToolshedTestCase):
self.assertTrue(created) self.assertTrue(created)
self.assertEqual(file.file.read(), self.f['test_content4']) self.assertEqual(file.file.read(), self.f['test_content4'])
self.assertEqual(file.file.name, 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): def test_file_upload_get_or_create_fail(self):
with transaction.atomic(): with transaction.atomic():
@ -103,3 +103,31 @@ class FilesTestCase(FilesTestMixin, ToolshedTestCase):
File.objects.get_or_create(hash=self.f['hash3']) File.objects.get_or_create(hash=self.f['hash3'])
self.assertEqual(File.objects.count(), 3) self.assertEqual(File.objects.count(), 3)
self.assertEqual(countdir(DefaultStorage(), ''), 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)