API: File upload infrastructure

This commit is contained in:
Raphael Michel
2021-01-05 12:49:58 +01:00
parent 9d70fd675c
commit 8b08b43e77
6 changed files with 149 additions and 1 deletions

View File

@@ -8,7 +8,7 @@ from pretix.api.views import cart
from .views import (
checkin, device, event, exporters, item, oauth, order, organizer, user,
version, voucher, waitinglist, webhooks,
upload, version, voucher, waitinglist, webhooks,
)
router = routers.DefaultRouter()
@@ -95,6 +95,7 @@ urlpatterns = [
url(r"^device/roll$", device.RollKeyView.as_view(), name="device.roll"),
url(r"^device/revoke$", device.RevokeKeyView.as_view(), name="device.revoke"),
url(r"^device/eventselection$", device.EventSelectionView.as_view(), name="device.eventselection"),
url(r"^upload$", upload.UploadView.as_view(), name="user.me"),
url(r"^me$", user.MeView.as_view(), name="user.me"),
url(r"^version$", version.VersionView.as_view(), name="version"),
]

View File

@@ -0,0 +1,53 @@
import datetime
from django.utils.timezone import now
from oauth2_provider.contrib.rest_framework import OAuth2Authentication
from rest_framework.authentication import SessionAuthentication
from rest_framework.exceptions import ValidationError
from rest_framework.parsers import FileUploadParser
from rest_framework.response import Response
from rest_framework.views import APIView
from pretix.api.auth.device import DeviceTokenAuthentication
from pretix.api.auth.token import TeamTokenAuthentication
from pretix.base.models import CachedFile
ALLOWED_TYPES = {
'image/gif': {'.gif'},
'image/jpeg': {'.jpg', '.jpeg'},
'image/png': {'.png'},
'application/pdf': {'.pdf'},
}
class UploadView(APIView):
authentication_classes = (
SessionAuthentication, OAuth2Authentication, DeviceTokenAuthentication, TeamTokenAuthentication
)
parser_classes = [FileUploadParser]
def post(self, request):
if 'file' not in request.data:
raise ValidationError('No file has been submitted.')
file_obj = request.data['file']
content_type = file_obj.content_type.split(";")[0] # ignore e.g. "; charset=…"
if content_type not in ALLOWED_TYPES:
raise ValidationError('Content type "{type}" is not allowed'.format(type=content_type))
if not any(file_obj.name.endswith(ext) for ext in ALLOWED_TYPES[content_type]):
raise ValidationError('File name "{name}" has an invalid extension for type "{type}"'.format(
name=file_obj.name,
type=content_type
))
cf = CachedFile.objects.create(
expires=now() + datetime.timedelta(days=1),
date=now(),
web_download=False,
filename=file_obj.name,
type=content_type,
session_key=f'api-upload-{str(type(request.user or request.auth))}-{(request.user or request.auth).pk}'
)
cf.file.save(file_obj.name, file_obj)
cf.save()
return Response({
'id': f'file:{cf.pk}'
}, status=201)