소스 검색

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

master
Viggo de Vries 3 년 전
부모
커밋
663ca69d2f
No account linked to committer's email address
3개의 변경된 파일50개의 추가작업 그리고 1개의 파일을 삭제
  1. 8
    0
      src/oscar/apps/basket/views.py
  2. 7
    1
      src/oscar/templatetags/basket_tags.py
  3. 35
    0
      tests/functional/basket/test_manipulation.py

+ 8
- 0
src/oscar/apps/basket/views.py 파일 보기

1
 from django import shortcuts
1
 from django import shortcuts
2
 from django.contrib import messages
2
 from django.contrib import messages
3
+from django.contrib.sessions.serializers import JSONSerializer
3
 from django.core.exceptions import ObjectDoesNotExist
4
 from django.core.exceptions import ObjectDoesNotExist
4
 from django.http import JsonResponse, QueryDict
5
 from django.http import JsonResponse, QueryDict
5
 from django.shortcuts import redirect
6
 from django.shortcuts import redirect
332
         clean_msgs = [m.replace('* ', '') for m in msgs if m.startswith('* ')]
333
         clean_msgs = [m.replace('* ', '') for m in msgs if m.startswith('* ')]
333
         messages.error(self.request, ",".join(clean_msgs))
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
         return redirect_to_referrer(self.request, 'basket:summary')
343
         return redirect_to_referrer(self.request, 'basket:summary')
336
 
344
 
337
     def form_valid(self, form):
345
     def form_valid(self, form):

+ 7
- 1
src/oscar/templatetags/basket_tags.py 파일 보기

1
 from django import template
1
 from django import template
2
+from django.contrib.sessions.serializers import JSONSerializer
2
 
3
 
3
 from oscar.core.loading import get_class, get_model
4
 from oscar.core.loading import get_class, get_model
4
 
5
 
24
     if quantity_type == QNT_SINGLE:
25
     if quantity_type == QNT_SINGLE:
25
         form_class = SimpleAddToBasketForm
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
     return form
35
     return form

+ 35
- 0
tests/functional/basket/test_manipulation.py 파일 보기

1
 from oscar.apps.basket import models
1
 from oscar.apps.basket import models
2
+from oscar.core.loading import get_model
2
 from oscar.test import factories
3
 from oscar.test import factories
3
 from oscar.test.testcases import WebTestCase
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
 class TestAddingToBasket(WebTestCase):
11
 class TestAddingToBasket(WebTestCase):
7
 
12
 
34
 
39
 
35
         basket = baskets[0]
40
         basket = baskets[0]
36
         self.assertEqual(3, basket.num_items)
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())

Loading…
취소
저장