mirror of
https://github.com/pretix/pretix.git
synced 2026-05-08 15:44:02 +00:00
Fix useless cart sessions being created (#6045)
* Do not create useless cart session accessing invoice address * Skip useless code paths in CartMixin * Do not create cart session on view with active session * Create regression tests
This commit is contained in:
@@ -70,18 +70,21 @@ def cached_invoice_address(request):
|
|||||||
# do not create a session, if we don't have a session we also don't have an invoice address ;)
|
# do not create a session, if we don't have a session we also don't have an invoice address ;)
|
||||||
request._checkout_flow_invoice_address = InvoiceAddress()
|
request._checkout_flow_invoice_address = InvoiceAddress()
|
||||||
return request._checkout_flow_invoice_address
|
return request._checkout_flow_invoice_address
|
||||||
cs = cart_session(request)
|
cs = cart_session(request, create=False)
|
||||||
iapk = cs.get('invoice_address')
|
if cs is None:
|
||||||
if not iapk:
|
|
||||||
request._checkout_flow_invoice_address = InvoiceAddress()
|
request._checkout_flow_invoice_address = InvoiceAddress()
|
||||||
else:
|
else:
|
||||||
try:
|
iapk = cs.get('invoice_address')
|
||||||
with scopes_disabled():
|
if not iapk:
|
||||||
request._checkout_flow_invoice_address = InvoiceAddress.objects.get(
|
|
||||||
pk=iapk, order__isnull=True
|
|
||||||
)
|
|
||||||
except InvoiceAddress.DoesNotExist:
|
|
||||||
request._checkout_flow_invoice_address = InvoiceAddress()
|
request._checkout_flow_invoice_address = InvoiceAddress()
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
with scopes_disabled():
|
||||||
|
request._checkout_flow_invoice_address = InvoiceAddress.objects.get(
|
||||||
|
pk=iapk, order__isnull=True
|
||||||
|
)
|
||||||
|
except InvoiceAddress.DoesNotExist:
|
||||||
|
request._checkout_flow_invoice_address = InvoiceAddress()
|
||||||
return request._checkout_flow_invoice_address
|
return request._checkout_flow_invoice_address
|
||||||
|
|
||||||
|
|
||||||
@@ -111,6 +114,12 @@ class CartMixin:
|
|||||||
return cached_invoice_address(self.request)
|
return cached_invoice_address(self.request)
|
||||||
|
|
||||||
def get_cart(self, answers=False, queryset=None, order=None, downloads=False, payments=None):
|
def get_cart(self, answers=False, queryset=None, order=None, downloads=False, payments=None):
|
||||||
|
if not self.request.session.session_key and not order:
|
||||||
|
# The user has not even a session ID yet, so they can't have a cart and we can save a lot of work
|
||||||
|
return {
|
||||||
|
'positions': [],
|
||||||
|
# Other keys are not used on non-checkout pages
|
||||||
|
}
|
||||||
if queryset is not None:
|
if queryset is not None:
|
||||||
prefetch = []
|
prefetch = []
|
||||||
if answers:
|
if answers:
|
||||||
@@ -166,7 +175,8 @@ class CartMixin:
|
|||||||
else:
|
else:
|
||||||
fees = []
|
fees = []
|
||||||
|
|
||||||
if not order:
|
if not order and lcp:
|
||||||
|
# Do not re-round for empty cart (useless) or confirmed order (incorrect)
|
||||||
apply_rounding(self.request.event.settings.tax_rounding, self.invoice_address, self.request.event.currency, [*lcp, *fees])
|
apply_rounding(self.request.event.settings.tax_rounding, self.invoice_address, self.request.event.currency, [*lcp, *fees])
|
||||||
|
|
||||||
total = sum([c.price for c in lcp]) + sum([f.value for f in fees])
|
total = sum([c.price for c in lcp]) + sum([f.value for f in fees])
|
||||||
@@ -277,6 +287,12 @@ class CartMixin:
|
|||||||
}
|
}
|
||||||
|
|
||||||
def current_selected_payments(self, positions, fees, invoice_address, *, warn=False):
|
def current_selected_payments(self, positions, fees, invoice_address, *, warn=False):
|
||||||
|
from pretix.presale.views.cart import get_or_create_cart_id
|
||||||
|
|
||||||
|
if not get_or_create_cart_id(self.request, create=False):
|
||||||
|
# No active cart ID, no payments there
|
||||||
|
return []
|
||||||
|
|
||||||
raw_payments = copy.deepcopy(self.cart_session.get('payments', []))
|
raw_payments = copy.deepcopy(self.cart_session.get('payments', []))
|
||||||
fees = [f for f in fees if f.fee_type != OrderFee.FEE_TYPE_PAYMENT] # we re-compute these here
|
fees = [f for f in fees if f.fee_type != OrderFee.FEE_TYPE_PAYMENT] # we re-compute these here
|
||||||
|
|
||||||
|
|||||||
@@ -417,7 +417,7 @@ def get_or_create_cart_id(request, create=True):
|
|||||||
return new_id
|
return new_id
|
||||||
|
|
||||||
|
|
||||||
def cart_session(request):
|
def cart_session(request, create=True):
|
||||||
"""
|
"""
|
||||||
Before pretix 1.8.0, all checkout-related information (like the entered email address) was stored
|
Before pretix 1.8.0, all checkout-related information (like the entered email address) was stored
|
||||||
in the user's regular session dictionary. This led to data interference and leaks for example if a
|
in the user's regular session dictionary. This led to data interference and leaks for example if a
|
||||||
@@ -428,7 +428,9 @@ def cart_session(request):
|
|||||||
active cart session sub-dictionary for read and write access.
|
active cart session sub-dictionary for read and write access.
|
||||||
"""
|
"""
|
||||||
request.session.modified = True
|
request.session.modified = True
|
||||||
cart_id = get_or_create_cart_id(request)
|
cart_id = get_or_create_cart_id(request, create=create)
|
||||||
|
if not cart_id and not create:
|
||||||
|
return None
|
||||||
return request.session['carts'][cart_id]
|
return request.session['carts'][cart_id]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import re
|
import re
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from importlib import import_module
|
||||||
from json import loads
|
from json import loads
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
@@ -80,6 +81,34 @@ class EventMiddlewareTest(EventTestMixin, SoupTest):
|
|||||||
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
|
doc = self.get_doc('/%s/%s/' % (self.orga.slug, self.event.slug))
|
||||||
self.assertIn(str(self.event.name), doc.find("h1").text)
|
self.assertIn(str(self.event.name), doc.find("h1").text)
|
||||||
|
|
||||||
|
def test_no_session_cookie_set_on_event_index_view(self):
|
||||||
|
resp = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug))
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
assert settings.SESSION_COOKIE_NAME not in self.client.cookies
|
||||||
|
|
||||||
|
def test_no_cart_session_added_on_event_index_view(self):
|
||||||
|
# Make sure a session is present by doing a cart op on another event
|
||||||
|
event2 = Event.objects.create(
|
||||||
|
organizer=self.orga, name='30C3b', slug='30c3b',
|
||||||
|
date_from=datetime.datetime(now().year + 1, 12, 26, 14, 0, tzinfo=datetime.timezone.utc),
|
||||||
|
live=True,
|
||||||
|
)
|
||||||
|
self.client.post('/%s/%s/cart/add' % (self.orga.slug, event2.slug), {
|
||||||
|
'item_%d' % 1337: '1', # item does not need to exist
|
||||||
|
'ajax': 1
|
||||||
|
})
|
||||||
|
assert settings.SESSION_COOKIE_NAME in self.client.cookies
|
||||||
|
|
||||||
|
# Visit shop, make sure no session is created
|
||||||
|
resp = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug))
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
|
||||||
|
session = SessionStore(self.client.cookies[settings.SESSION_COOKIE_NAME].value).load()
|
||||||
|
assert set(session.keys()) == {
|
||||||
|
f"current_cart_event_{event2.pk}", "carts"
|
||||||
|
}
|
||||||
|
|
||||||
def test_not_found(self):
|
def test_not_found(self):
|
||||||
resp = self.client.get('/%s/%s/' % ('foo', 'bar'))
|
resp = self.client.get('/%s/%s/' % ('foo', 'bar'))
|
||||||
self.assertEqual(resp.status_code, 404)
|
self.assertEqual(resp.status_code, 404)
|
||||||
|
|||||||
Reference in New Issue
Block a user