Parcourir la source

Add basket post data to the form when invalid (#3911)

master
Viggo de Vries il y a 3 ans
Parent
révision
663ca69d2f
Aucun compte lié à l'adresse e-mail de l'auteur

+ 8
- 0
src/oscar/apps/basket/views.py Voir le fichier

@@ -1,5 +1,6 @@
1 1
 from django import shortcuts
2 2
 from django.contrib import messages
3
+from django.contrib.sessions.serializers import JSONSerializer
3 4
 from django.core.exceptions import ObjectDoesNotExist
4 5
 from django.http import JsonResponse, QueryDict
5 6
 from django.shortcuts import redirect
@@ -332,6 +333,13 @@ class BasketAddView(FormView):
332 333
         clean_msgs = [m.replace('* ', '') for m in msgs if m.startswith('* ')]
333 334
         messages.error(self.request, ",".join(clean_msgs))
334 335
 
336
+        # We serialize the POST data with JSONSerializer before adding it to the session.
337
+        # Without this, we could expose the site to a security vulnerability
338
+        # if the SESSION_SERIALIZER has been configured to 'django.contrib.sessions.serializers.PickleSerializer'.
339
+        # see: https://docs.djangoproject.com/en/3.2/topics/http/sessions/#cookie-session-backend
340
+        serialized_data = JSONSerializer().dumps(self.request.POST)
341
+        self.request.session["add_to_basket_form_post_data_%s" % self.product.pk] = serialized_data.decode("latin-1")
342
+
335 343
         return redirect_to_referrer(self.request, 'basket:summary')
336 344
 
337 345
     def form_valid(self, form):

+ 7
- 1
src/oscar/templatetags/basket_tags.py Voir le fichier

@@ -1,4 +1,5 @@
1 1
 from django import template
2
+from django.contrib.sessions.serializers import JSONSerializer
2 3
 
3 4
 from oscar.core.loading import get_class, get_model
4 5
 
@@ -24,6 +25,11 @@ def basket_form(request, product, quantity_type='single'):
24 25
     if quantity_type == QNT_SINGLE:
25 26
         form_class = SimpleAddToBasketForm
26 27
 
27
-    form = form_class(request.basket, product=product, initial=initial)
28
+    basket_post_data = request.session.pop("add_to_basket_form_post_data_%s" % product.pk, None)
29
+
30
+    if basket_post_data is not None:
31
+        basket_post_data = JSONSerializer().loads(basket_post_data.encode("latin-1"))
32
+
33
+    form = form_class(request.basket, data=basket_post_data, product=product, initial=initial)
28 34
 
29 35
     return form

+ 35
- 0
tests/functional/basket/test_manipulation.py Voir le fichier

@@ -1,7 +1,12 @@
1 1
 from oscar.apps.basket import models
2
+from oscar.core.loading import get_model
2 3
 from oscar.test import factories
3 4
 from oscar.test.testcases import WebTestCase
4 5
 
6
+Option = get_model("catalogue", "Option")
7
+AttributeOptionGroup = get_model("catalogue", "AttributeOptionGroup")
8
+AttributeOption = get_model("catalogue", "AttributeOption")
9
+
5 10
 
6 11
 class TestAddingToBasket(WebTestCase):
7 12
 
@@ -34,3 +39,33 @@ class TestAddingToBasket(WebTestCase):
34 39
 
35 40
         basket = baskets[0]
36 41
         self.assertEqual(3, basket.num_items)
42
+
43
+    def test_validation_errors_in_form(self):
44
+        product = factories.ProductFactory()
45
+        product_class = product.get_product_class()
46
+        group = AttributeOptionGroup.objects.create(name="checkbox options")
47
+        AttributeOption.objects.create(group=group, option="1")
48
+        AttributeOption.objects.create(group=group, option="2")
49
+
50
+        option = Option.objects.create(
51
+            type=Option.CHECKBOX,
52
+            required=True,
53
+            name="Required checkbox",
54
+            option_group=group
55
+        )
56
+        text_option = Option.objects.create(type=Option.TEXT, required=False, name="Open tekst")
57
+
58
+        product_class.options.add(option)
59
+        product_class.options.add(text_option)
60
+        product_class.save()
61
+
62
+        detail_page = self.get(product.get_absolute_url())
63
+        detail_page.forms["add_to_basket_form"]["open-tekst"] = "test harrie"
64
+        response = detail_page.forms['add_to_basket_form'].submit().follow()
65
+
66
+        self.assertEqual(response.forms["add_to_basket_form"]["open-tekst"].value, "test harrie")
67
+        baskets = models.Basket.objects.all()
68
+        self.assertEqual(1, len(baskets))
69
+
70
+        basket = baskets[0]
71
+        self.assertEqual(0, basket.lines.count())

Chargement…
Annuler
Enregistrer