diff --git a/src/pretix/base/views/tasks.py b/src/pretix/base/views/tasks.py
index 4e4f28389..f7c78098a 100644
--- a/src/pretix/base/views/tasks.py
+++ b/src/pretix/base/views/tasks.py
@@ -20,6 +20,8 @@
# .
#
import logging
+from collections import defaultdict
+from datetime import timedelta
from importlib import import_module
from zoneinfo import ZoneInfo
@@ -29,18 +31,20 @@ from celery.result import AsyncResult
from django.conf import settings
from django.contrib import messages
from django.core.exceptions import PermissionDenied, ValidationError
+from django.core.files.uploadedfile import UploadedFile
from django.db import transaction
from django.http import HttpResponse, JsonResponse, QueryDict
from django.shortcuts import redirect, render
from django.test import RequestFactory
from django.utils import timezone, translation
-from django.utils.timezone import get_current_timezone
+from django.utils.datastructures import MultiValueDict
+from django.utils.timezone import get_current_timezone, now
from django.utils.translation import get_language, gettext as _
from django.views import View
from django.views.generic import FormView
from redis import ResponseError
-from pretix.base.models import User
+from pretix.base.models import CachedFile, User
from pretix.base.services.tasks import ProfiledEventTask
from pretix.celery_app import app
@@ -228,15 +232,39 @@ class AsyncFormView(AsyncMixin, FormView):
)
def __init_subclass__(cls):
+ class StoredUploadedFile(UploadedFile):
+ pass
+
def async_execute(self, *, request_path, query_string, form_kwargs, locale, tz, url_kwargs=None, url_args=None,
organizer=None, event=None, user=None, session_key=None):
view_instance = cls()
form_kwargs['data'] = QueryDict(form_kwargs['data'])
+
+ if form_kwargs['files']:
+ for k, l in form_kwargs['files'].items():
+ uploadedfiles = []
+ for cfid in l:
+ cf = CachedFile.objects.get(pk=cfid)
+ uploadedfiles.append(StoredUploadedFile(
+ file=cf.file,
+ name=cf.filename,
+ content_type=cf.type,
+ size=cf.file.size,
+ charset=None,
+ content_type_extra=None,
+ ))
+
+ form_kwargs['files'][k] = uploadedfiles
+ form_kwargs['files'] = MultiValueDict(form_kwargs['files'])
+
req = RequestFactory().post(
request_path + '?' + query_string,
data=form_kwargs['data'].urlencode(),
content_type='application/x-www-form-urlencoded'
)
+ if form_kwargs['files']:
+ req._load_post_and_files()
+ req._files = form_kwargs['files']
view_instance.request = req
view_instance.kwargs = url_kwargs
view_instance.args = url_args
@@ -287,8 +315,19 @@ class AsyncFormView(AsyncMixin, FormView):
return super().get(request, *args, **kwargs)
def form_valid(self, form):
- if form.files:
- raise TypeError('File upload currently not supported in AsyncFormView')
+ files = defaultdict(list)
+ if self.request.FILES:
+ for k, v in self.request.FILES.items():
+ cf = CachedFile.objects.create(
+ expires=now() + timedelta(hours=2),
+ date=now(),
+ web_download=False,
+ filename=v.name,
+ type=v.content_type,
+ )
+ cf.file.save('uploaded_file.dat', v)
+ files[k].append(str(cf.pk))
+
form_kwargs = {
k: v for k, v in self.get_form_kwargs().items()
}
@@ -299,6 +338,7 @@ class AsyncFormView(AsyncMixin, FormView):
form_kwargs['instance'] = None
form_kwargs.setdefault('data', QueryDict())
form_kwargs['data'] = form_kwargs['data'].urlencode()
+ form_kwargs['files'] = files
form_kwargs['initial'] = {}
form_kwargs.pop('event', None)
kwargs = {
diff --git a/src/pretix/control/templates/pretixcontrol/subevents/bulk.html b/src/pretix/control/templates/pretixcontrol/subevents/bulk.html
index 9430373c5..21f392f50 100644
--- a/src/pretix/control/templates/pretixcontrol/subevents/bulk.html
+++ b/src/pretix/control/templates/pretixcontrol/subevents/bulk.html
@@ -8,7 +8,7 @@
{% block title %}{% trans "Date" context "subevent" %}{% endblock %}
{% block content %}
{% trans "Create multiple dates" context "subevent" %}
-