diff --git a/src/pretix/presale/views/checkout.py b/src/pretix/presale/views/checkout.py index f2865e9e52..1318d56e2e 100644 --- a/src/pretix/presale/views/checkout.py +++ b/src/pretix/presale/views/checkout.py @@ -21,6 +21,7 @@ # from urllib.parse import quote, urlencode +from django.conf import settings from django.contrib import messages from django.http import Http404 from django.utils.decorators import method_decorator @@ -29,6 +30,7 @@ from django.views.generic import View from pretix.base.services.cart import CartError from pretix.base.signals import validate_cart +from pretix.base.views.tasks import AsyncAction from pretix.helpers.http import redirect_to_url from pretix.multidomain.urlreverse import eventreverse from pretix.presale.checkoutflow import get_checkout_flow @@ -51,7 +53,12 @@ class CheckoutView(View): def dispatch(self, request, *args, **kwargs): self.request = request - if not cart_exists(request) and "async_id" not in request.GET: + is_asyncaction_call = ( + request.method == "GET" and + 'async_id' in request.GET and + settings.HAS_CELERY + ) + if not cart_exists(request) and not is_asyncaction_call: messages.error(request, _("Your cart is empty")) return self.redirect(self.get_index_url(self.request)) @@ -78,7 +85,9 @@ class CheckoutView(View): utm_params = {k: v for k, v in request.GET.items() if k.startswith("utm_")} return self.redirect(step.get_step_url(request) + '?' + urlencode(utm_params)) is_selected = (step.identifier == kwargs.get('step', '')) - if "async_id" not in request.GET and not is_selected and not step.is_completed(request, warn=not is_selected): + + is_valid_asyncaction_call = is_asyncaction_call and isinstance(step, AsyncAction) + if not is_valid_asyncaction_call and not is_selected and not step.is_completed(request, warn=not is_selected): return self.redirect(step.get_step_url(request)) if is_selected: if request.method.lower() in self.http_method_names: diff --git a/src/tests/presale/test_checkout.py b/src/tests/presale/test_checkout.py index 1b2efbd1a6..5a92cd7466 100644 --- a/src/tests/presale/test_checkout.py +++ b/src/tests/presale/test_checkout.py @@ -6102,3 +6102,14 @@ class CustomerCheckoutTestCase(BaseCheckoutTestCase, TestCase): response = self.client.get('/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug), follow=True) assert 'Gift card' in response.content.decode() assert '(1 available)' in response.content.decode() + + def test_validation_bypass_error_async_id_is_fixed(self): + with scopes_disabled(): + CartPosition.objects.create( + event=self.event, cart_id=self.session_key, item=self.ticket, + price=0, listed_price=0, price_after_voucher=0, expires=now() + timedelta(minutes=10) + ) + + response = self.client.post('/%s/%s/checkout/confirm/?async_id=1' % (self.orga.slug, self.event.slug), follow=False) + self.assertRedirects(response, '/%s/%s/checkout/customer/' % (self.orga.slug, self.event.slug), + target_status_code=200)