From 07fed0acce922bd44e76fb8549e4bec6e9422c7d Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Tue, 11 Apr 2017 12:12:40 +0200 Subject: [PATCH] Use async actions for order export --- src/pretix/base/services/export.py | 1 + src/pretix/base/views/async.py | 4 ++ .../pretixcontrol/orders/export.html | 4 +- src/pretix/control/urls.py | 1 + src/pretix/control/views/orders.py | 42 ++++++++++++----- src/pretix/static/pretixbase/js/asynctask.js | 46 ++++++++++++++++--- 6 files changed, 80 insertions(+), 18 deletions(-) diff --git a/src/pretix/base/services/export.py b/src/pretix/base/services/export.py index 490d0cf11..2b70624ca 100644 --- a/src/pretix/base/services/export.py +++ b/src/pretix/base/services/export.py @@ -21,3 +21,4 @@ def export(event: str, fileid: str, provider: str, form_data: Dict[str, Any]) -> file.filename, file.type, data = ex.render(form_data) file.file.save(cachedfile_name(file, file.filename), ContentFile(data)) file.save() + return file.pk diff --git a/src/pretix/base/views/async.py b/src/pretix/base/views/async.py index 4b76db552..6e9c702b1 100644 --- a/src/pretix/base/views/async.py +++ b/src/pretix/base/views/async.py @@ -72,6 +72,7 @@ class AsyncAction: # but handle the mssage itself data.update({ 'redirect': self.get_success_url(res.info), + 'success': True, 'message': str(self.get_success_message(res.info)) }) else: @@ -80,6 +81,7 @@ class AsyncAction: # but handle the mssage itself data.update({ 'redirect': self.get_error_url(), + 'success': False, 'message': str(self.get_error_message(res.info)) }) return data @@ -103,6 +105,7 @@ class AsyncAction: if "ajax" in self.request.POST or "ajax" in self.request.GET: return JsonResponse({ 'ready': True, + 'success': True, 'redirect': self.get_success_url(value), 'message': str(self.get_success_message(value)) }) @@ -113,6 +116,7 @@ class AsyncAction: if "ajax" in self.request.POST or "ajax" in self.request.GET: return JsonResponse({ 'ready': True, + 'success': False, 'redirect': self.get_error_url(), 'message': str(self.get_error_message(exception)) }) diff --git a/src/pretix/control/templates/pretixcontrol/orders/export.html b/src/pretix/control/templates/pretixcontrol/orders/export.html index 685e9c22d..00f8acf4b 100644 --- a/src/pretix/control/templates/pretixcontrol/orders/export.html +++ b/src/pretix/control/templates/pretixcontrol/orders/export.html @@ -11,7 +11,9 @@

{{ e.verbose_name }}

-
+ {% csrf_token %} {% bootstrap_form e.form layout='horizontal' %} diff --git a/src/pretix/control/urls.py b/src/pretix/control/urls.py index 0d5e15fb2..e6a3e2f01 100644 --- a/src/pretix/control/urls.py +++ b/src/pretix/control/urls.py @@ -122,6 +122,7 @@ urlpatterns = [ name='event.invoice.download'), url(r'^orders/overview/$', orders.OverView.as_view(), name='event.orders.overview'), url(r'^orders/export/$', orders.ExportView.as_view(), name='event.orders.export'), + url(r'^orders/export/do$', orders.ExportDoView.as_view(), name='event.orders.export.do'), url(r'^orders/go$', orders.OrderGo.as_view(), name='event.orders.go'), url(r'^orders/$', orders.OrderList.as_view(), name='event.orders'), url(r'^waitinglist/$', waitinglist.WaitingListView.as_view(), name='event.orders.waitinglist'), diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py index e2cfb59e1..dfed6258f 100644 --- a/src/pretix/control/views/orders.py +++ b/src/pretix/control/views/orders.py @@ -30,6 +30,7 @@ from pretix.base.services.stats import order_overview from pretix.base.signals import ( register_data_exporters, register_payment_providers, ) +from pretix.base.views.async import AsyncAction from pretix.control.forms.orders import ( CommentForm, ExporterForm, ExtendForm, OrderContactForm, OrderLocaleForm, OrderPositionChangeForm, @@ -622,9 +623,7 @@ class OrderGo(EventPermissionRequiredMixin, View): return redirect('control:event.orders', event=request.event.slug, organizer=request.event.organizer.slug) -class ExportView(EventPermissionRequiredMixin, TemplateView): - permission = 'can_view_orders' - template_name = 'pretixcontrol/orders/export.html' +class ExportMixin: @cached_property def exporters(self): @@ -640,10 +639,22 @@ class ExportView(EventPermissionRequiredMixin, TemplateView): exporters.append(ex) return exporters - def get_context_data(self, **kwargs): - ctx = super().get_context_data(**kwargs) - ctx['exporters'] = self.exporters - return ctx + +class ExportDoView(EventPermissionRequiredMixin, ExportMixin, AsyncAction, View): + permission = 'can_view_orders' + task = export + + def get_success_message(self, value): + return None + + def get_success_url(self, value): + return reverse('cachedfile.download', kwargs={'id': str(value)}) + + def get_error_url(self): + return reverse('control:event.orders.export', kwargs={ + 'event': self.request.event.slug, + 'organizer': self.request.event.organizer.slug + }) @cached_property def exporter(self): @@ -651,13 +662,14 @@ class ExportView(EventPermissionRequiredMixin, TemplateView): if ex.identifier == self.request.POST.get("exporter"): return ex - def post(self, *args, **kwargs): + def post(self, request, *args, **kwargs): if not self.exporter: messages.error(self.request, _('The selected exporter was not found.')) return redirect('control:event.orders.export', kwargs={ 'event': self.request.event.slug, 'organizer': self.request.event.organizer.slug }) + if not self.exporter.form.is_valid(): messages.error(self.request, _('There was a problem processing your input. See below for error details.')) return self.get(*args, **kwargs) @@ -666,6 +678,14 @@ class ExportView(EventPermissionRequiredMixin, TemplateView): cf.date = now() cf.expires = now() + timedelta(days=3) cf.save() - export.apply_async(args=(self.request.event.id, str(cf.id), self.exporter.identifier, - self.exporter.form.cleaned_data)) - return redirect(reverse('cachedfile.download', kwargs={'id': str(cf.id)})) + return self.do(self.request.event.id, str(cf.id), self.exporter.identifier, self.exporter.form.cleaned_data) + + +class ExportView(EventPermissionRequiredMixin, ExportMixin, TemplateView): + permission = 'can_view_orders' + template_name = 'pretixcontrol/orders/export.html' + + def get_context_data(self, **kwargs): + ctx = super().get_context_data(**kwargs) + ctx['exporters'] = self.exporters + return ctx diff --git a/src/pretix/static/pretixbase/js/asynctask.js b/src/pretix/static/pretixbase/js/asynctask.js index b8ec0d9d7..c34d056c0 100644 --- a/src/pretix/static/pretixbase/js/asynctask.js +++ b/src/pretix/static/pretixbase/js/asynctask.js @@ -2,6 +2,9 @@ var async_task_id = null; var async_task_timeout = null; var async_task_check_url = null; +var async_task_old_url = null; +var async_task_is_download = false; +var async_task_is_long = false; function async_task_check() { "use strict"; @@ -20,13 +23,26 @@ function async_task_check() { function async_task_check_callback(data, jqXHR, status) { "use strict"; if (data.ready && data.redirect) { + if (async_task_is_download && data.success) { + waitingDialog.hide(); + if (location.href.indexOf("async_id") !== -1) { + history.replaceState({}, "pretix", async_task_old_url); + } + } location.href = data.redirect; return; } async_task_timeout = window.setTimeout(async_task_check, 250); - $("#loadingmodal p").text(gettext('Your request has been queued on the server and will now be ' + - 'processed. If this takes longer than two minutes, please contact us or go ' + - 'back in your browser and try again.')); + + if (async_task_is_long) { + $("#loadingmodal p").text(gettext('Your request has been queued on the server and will now be ' + + 'processed. Depending on the size of your event, this might take up to a ' + + 'few minutes.')); + } else { + $("#loadingmodal p").text(gettext('Your request has been queued on the server and will now be ' + + 'processed. If this takes longer than two minutes, please contact us or go ' + + 'back in your browser and try again.')); + } } function async_task_check_error(jqXHR, textStatus, errorThrown) { @@ -35,6 +51,9 @@ function async_task_check_error(jqXHR, textStatus, errorThrown) { if (c.length > 0) { $("body").data('ajaxing', false); waitingDialog.hide(); + if (location.href.indexOf("async_id") !== -1) { + history.replaceState({}, "pretix", async_task_old_url); + } ajaxErrDialog.show(c.first().html()); } else { if (jqXHR.status >= 400 && jqXHR.status < 500) { @@ -54,6 +73,12 @@ function async_task_callback(data, jqXHR, status) { "use strict"; $("body").data('ajaxing', false); if (data.redirect) { + if (async_task_is_download && data.success) { + waitingDialog.hide(); + if (location.href.indexOf("async_id") !== -1) { + history.replaceState({}, "pretix", async_task_old_url); + } + } location.href = data.redirect; return; } @@ -61,9 +86,15 @@ function async_task_callback(data, jqXHR, status) { async_task_check_url = data.check_url; async_task_timeout = window.setTimeout(async_task_check, 100); - $("#loadingmodal p").text(gettext('Your request has been queued on the server and will now be ' + - 'processed. If this takes longer than two minutes, please contact us or go ' + - 'back in your browser and try again.')); + if (async_task_is_long) { + $("#loadingmodal p").text(gettext('Your request has been queued on the server and will now be ' + + 'processed. Depending on the size of your event, this might take up to a ' + + 'few minutes.')); + } else { + $("#loadingmodal p").text(gettext('Your request has been queued on the server and will now be ' + + 'processed. If this takes longer than two minutes, please contact us or go ' + + 'back in your browser and try again.')); + } if (location.href.indexOf("async_id") === -1) { history.pushState({}, "Waiting", async_task_check_url.replace(/ajax=1/, '')); } @@ -99,6 +130,9 @@ $(function () { return; } async_task_id = null; + async_task_is_download = $(this).is("[data-asynctask-download]"); + async_task_is_long = $(this).is("[data-asynctask-long]"); + async_task_old_url = location.href; $("body").data('ajaxing', true); waitingDialog.show(gettext('We are processing your request …')); $("#loadingmodal p").text(gettext('We are currently sending your request to the server. If this takes longer ' +