diff --git a/.readthedocs.yml b/.readthedocs.yml index f968835c..5be54601 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,13 +1,17 @@ version: 2 +build: + os: "ubuntu-22.04" + tools: + python: "3.11" + sphinx: configuration: docs/source/conf.py python: - version: 3.7 install: + - requirements: docs/requirements.txt - method: pip path: . extra_requirements: - dev - - requirements: docs/requirements.txt \ No newline at end of file diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 24461cf2..69564e34 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -2,6 +2,11 @@ Changelog ========= +3.2.4 (2023-09-08) +------------------ +this release is compatible with Oscar 3.2.1. This adds support for Django versions up to Django 4.2 + + 3.2.0 (2023-03-03) ------------------ This release is compatible with Oscar 3.2 . Supported Django versions are 3.2, and supported Python versions are 3.7, 3.8, 3.9, 3.10 and 3.11. This is my (maerteijn) last release as maintainer of OscarAPI. diff --git a/oscarapi/basket/operations.py b/oscarapi/basket/operations.py index d0e7821d..34e9d766 100644 --- a/oscarapi/basket/operations.py +++ b/oscarapi/basket/operations.py @@ -74,7 +74,7 @@ def get_anonymous_basket(request): basket_id = get_basket_id_from_session(request) try: - basket = Basket.open.get(pk=basket_id) + basket = Basket.open.get(pk=basket_id, owner=None) except Basket.DoesNotExist: basket = None @@ -83,7 +83,6 @@ def get_anonymous_basket(request): def get_user_basket(user): "get basket for a user." - try: basket, __ = Basket.open.get_or_create(owner=user) except Basket.MultipleObjectsReturned: diff --git a/oscarapi/middleware.py b/oscarapi/middleware.py index d15da651..933a2691 100644 --- a/oscarapi/middleware.py +++ b/oscarapi/middleware.py @@ -190,7 +190,7 @@ def process_response(self, request, response): # We just have to make sure it is stored as a cookie, because it # could have been created by oscarapi. cookie_key = self.get_cookie_key(request) - basket = get_basket(request) + basket = get_basket(request, prepare=False) cookie = self.get_basket_hash(basket.id) # Delete any surplus cookies diff --git a/oscarapi/settings.py b/oscarapi/settings.py index c1abc4c3..542e11ba 100644 --- a/oscarapi/settings.py +++ b/oscarapi/settings.py @@ -40,7 +40,7 @@ "OSCARAPI_VOUCHER_FIELDS", default=("name", "code", "start_datetime", "end_datetime"), ) -"ik ben harrie" + BASKET_FIELDS = overridable( "OSCARAPI_BASKET_FIELDS", default=( diff --git a/oscarapi/tests/unit/testbasket.py b/oscarapi/tests/unit/testbasket.py index 536a8c5e..cbbf62df 100644 --- a/oscarapi/tests/unit/testbasket.py +++ b/oscarapi/tests/unit/testbasket.py @@ -1,7 +1,7 @@ import json -from mock import patch - +from unittest.mock import patch +from django.test import override_settings from django.contrib.auth import get_user_model from django.urls import reverse @@ -1147,3 +1147,107 @@ def test_get_user_basket_with_multiple_baskets(self): user_basket = get_user_basket(user) self.assertEqual(Basket.open.count(), 1) self.assertEqual(user_basket, Basket.open.first()) + + +@override_settings( + MIDDLEWARE=( + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "oscarapi.middleware.ApiBasketMiddleWare", + "django.contrib.flatpages.middleware.FlatpageFallbackMiddleware", + ) +) +class ApiBasketMiddleWareTest(APITest): + fixtures = [ + "product", + "productcategory", + "productattribute", + "productclass", + "productattributevalue", + "category", + "attributeoptiongroup", + "attributeoption", + "stockrecord", + "partner", + "option", + ] + + def test_basket_login_logout(self): + self.assertEqual( + Basket.objects.count(), 0, "Initially there should be no baskets" + ) + + # add something to the anonymous basket, so we get a cookie basket + url = reverse("basket:add", kwargs={"pk": 1}) + post_params = {"child_id": 2, "action": "add", "quantity": 5} + response = self.client.post(url, post_params, follow=True) + + self.assertEqual( + Basket.objects.count(), + 1, + "After posting to the basket, 1 basket should be created.", + ) + self.assertIn( + "oscar_open_basket", + self.client.cookies, + "An basket cookie should have been created", + ) + self.assertStartsWith(self.client.cookies["oscar_open_basket"].value, "1") + + # retrieve the basket with oscarapi. + self.response = self.get("api-basket") + self.response.assertValueEqual( + "owner", None, "The basket should not have an owner" + ) + self.response.assertValueEqual("id", 1) + self.assertStartsWith(self.client.cookies["oscar_open_basket"].value, "1") + + # now lets log in with oscarapi + response = self.post("api-login", username="nobody", password="nobody") + # and lets retrieve the basket + self.response = self.get("api-basket") + self.response.assertValueEqual( + "owner", + "http://testserver/api/users/2/", + "the basket after login should have an owner", + ) + self.assertEqual( + self.client.cookies["oscar_open_basket"].value, + "1:Rdm76bzEHM-N1G6WSTj0Zu9ByZ80a8ggxSkqqvGbC6s", + "After logging out the cookie unfortunately does not go away", + ) + + response = self.client.post(url, post_params, follow=True) + self.assertEqual(response.status_code, 200) + self.assertEqual(Basket.objects.count(), 2) + self.assertEqual( + self.client.cookies["oscar_open_basket"].value, + "", + "The basket cookie should be removed", + ) + + self.response = self.delete("api-login") + self.assertStartsWith( + self.client.cookies["oscar_open_basket"].value, + "", + "After loging out, nothing happened to the basket cookie", + ) + + self.response = self.get("api-basket") + self.response.assertValueEqual( + "owner", None, "The logged out user's basket should not have an owner" + ) + self.assertEqual( + Basket.objects.count(), + 3, + "A new basket should be created for the anonymous (logged out) user", + ) + self.assertStartsWith( + self.client.cookies["oscar_open_basket"].value, + "3", + "The basket cookie is re-established after accessing the basket when logged out", + ) diff --git a/oscarapi/tests/unit/testcheckout.py b/oscarapi/tests/unit/testcheckout.py index bdebc8c9..4d71a3e9 100644 --- a/oscarapi/tests/unit/testcheckout.py +++ b/oscarapi/tests/unit/testcheckout.py @@ -1,5 +1,5 @@ from decimal import Decimal -from mock import patch +from unittest.mock import patch from django.contrib.auth import get_user_model from django.urls import reverse diff --git a/oscarapi/tests/unit/testproduct.py b/oscarapi/tests/unit/testproduct.py index 19b6a700..8abedbf6 100644 --- a/oscarapi/tests/unit/testproduct.py +++ b/oscarapi/tests/unit/testproduct.py @@ -1,4 +1,4 @@ -import mock +from unittest import mock import decimal import datetime import json diff --git a/oscarapi/tests/unit/testuser.py b/oscarapi/tests/unit/testuser.py index 8443a88a..4fcb7036 100644 --- a/oscarapi/tests/unit/testuser.py +++ b/oscarapi/tests/unit/testuser.py @@ -1,4 +1,4 @@ -from mock import patch +from unittest.mock import patch from django.contrib.auth import get_user_model from django.urls import reverse diff --git a/oscarapi/tests/utils.py b/oscarapi/tests/utils.py index 363ecb43..a275f290 100644 --- a/oscarapi/tests/utils.py +++ b/oscarapi/tests/utils.py @@ -121,6 +121,12 @@ def reload_modules(modules=()): for module in modules: reload_module(module) + def assertStartsWith(self, value, startvalue, message=""): + if not value.startswith(startvalue): + self.fail( + "'%s' does not start with '%s'. %s" % (value, startvalue, message) + ) + class ParsedResponse(object): def __init__(self, response, unittestcase): diff --git a/setup.py b/setup.py index 6e16e290..4f5e62c0 100755 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import find_packages, setup -__version__ = "3.2.2" +__version__ = "3.2.4" setup( # package name in pypi