From 3d23161cc0a51dffca838822e1c70c0d6ede4ba1 Mon Sep 17 00:00:00 2001 From: Patryk Zawadzki Date: Fri, 6 Mar 2020 18:43:44 +0100 Subject: [PATCH] Upgrade to Django 3.0 --- .travis.yml | 5 +- poetry.lock | 92 ++++++++++++++--------- pyproject.toml | 9 +-- requirements.txt | 15 ++-- requirements_dev.txt | 15 ++-- saleor/checkout/context_processors.py | 8 -- saleor/demo/views.py | 4 +- saleor/graphql/core/fields.py | 16 ++-- saleor/graphql/core/types/filter_input.py | 3 +- saleor/graphql/middleware.py | 38 +++------- saleor/graphql/views.py | 4 +- saleor/settings.py | 9 ++- tests/api/test_account.py | 6 +- tests/api/test_middleware.py | 5 +- tests/test_cart.py | 11 --- tox.ini | 4 +- 16 files changed, 116 insertions(+), 128 deletions(-) delete mode 100644 saleor/checkout/context_processors.py diff --git a/.travis.yml b/.travis.yml index 6f04524ee6a..49b83956ab0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,7 +43,6 @@ env: - DIFF_RESULTS_BASE_URL="http://dhrwmpu5reeyd.cloudfront.net" - QUERIES_RESULTS_PATH=/tmp/queries-results.json matrix: - - DJANGO="2.2" - DJANGO="3.0" - DJANGO="master" @@ -63,8 +62,6 @@ matrix: - env: TOXENV=pydocstyle python: "3.8" allow_failures: - - env: DJANGO="3.0" - python: "3.8" - env: DJANGO="master" python: "3.8" @@ -72,7 +69,7 @@ services: - postgresql addons: - postgresql: 9.4 + postgresql: 9.6 after_success: - ../queries-ci-tools/handle-event.sh diff --git a/poetry.lock b/poetry.lock index 8eaae66ecfb..6cdf3ad6089 100644 --- a/poetry.lock +++ b/poetry.lock @@ -33,6 +33,17 @@ optional = false python-versions = "*" version = "1.4.3" +[[package]] +category = "main" +description = "ASGI specs, helper code, and adapters" +name = "asgiref" +optional = false +python-versions = "*" +version = "3.2.3" + +[package.extras] +tests = ["pytest (>=4.3.0,<4.4.0)", "pytest-asyncio (>=0.10.0,<0.11.0)"] + [[package]] category = "dev" description = "A few extensions to pyyaml." @@ -424,12 +435,13 @@ category = "main" description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." name = "django" optional = false -python-versions = ">=3.5" -version = "2.2.10" +python-versions = ">=3.6" +version = "3.0.4" [package.dependencies] +asgiref = ">=3.2,<4.0" pytz = "*" -sqlparse = "*" +sqlparse = ">=0.2.2" [package.extras] argon2 = ["argon2-cffi (>=16.1.0)"] @@ -447,18 +459,6 @@ version = "1.0.3" django = "*" six = "*" -[[package]] -category = "main" -description = "Utilities for using Babel in Django" -name = "django-babel" -optional = false -python-versions = "*" -version = "0.6.2" - -[package.dependencies] -babel = ">=1.3" -django = ">=1.8,<3.0" - [[package]] category = "main" description = "Provides a country field for Django models." @@ -539,12 +539,13 @@ description = "JSON Web Token for Django GraphQL" name = "django-graphql-jwt" optional = false python-versions = "*" -version = "0.2.1" +version = "0.3.0" [package.dependencies] Django = ">=1.11" PyJWT = ">=1.5.0" graphene-django = ">=2.0.0" +graphql-core = ">=2.1,<3" [[package]] category = "main" @@ -601,12 +602,12 @@ description = "Django fields for the prices module" name = "django-prices" optional = false python-versions = "*" -version = "2.1.0" +version = "2.2.0" [package.dependencies] Babel = ">=2.2" -Django = ">=1.11,<3" -django-babel = "*" +Django = ">=2.2,<4" +enmerkar = ">=0.7.1" prices = ">=1.0.0" [[package]] @@ -615,7 +616,7 @@ description = "openexchangerates.org support for django-prices" name = "django-prices-openexchangerates" optional = false python-versions = "*" -version = "1.0.1" +version = "1.1.0" [package.dependencies] Django = ">=1.11" @@ -720,7 +721,7 @@ description = "A drop-in replacement for django's ImageField that provides a fle name = "django-versatileimagefield" optional = false python-versions = "*" -version = "1.11" +version = "2.0" [package.dependencies] Pillow = ">=2.4.0" @@ -748,6 +749,18 @@ urllib3 = "*" [package.extras] dev = ["pre-commit", "pytest", "mock"] +[[package]] +category = "main" +description = "Utilities for using Babel in Django" +name = "enmerkar" +optional = false +python-versions = "*" +version = "0.7.1" + +[package.dependencies] +babel = ">=1.3" +django = ">=2.2" + [[package]] category = "dev" description = "Discover and load entry points from installed packages." @@ -966,7 +979,7 @@ description = "Graphene Django integration" name = "graphene-django" optional = false python-versions = "*" -version = "2.6.0" +version = "2.8.2" [package.dependencies] Django = ">=1.11" @@ -2237,7 +2250,7 @@ idna = ">=2.0" multidict = ">=4.0" [metadata] -content-hash = "7d2f74a319b73f363e13c6d25cd8ea65180eaec3e0b0dca45e4e436b40110b16" +content-hash = "884b42bafa5b9a53e62d75ec70c0d7f6fd234578891d94c40dac54f3b9b81581" python-versions = "~3.8" [metadata.files] @@ -2257,6 +2270,10 @@ appdirs = [ {file = "appdirs-1.4.3-py2.py3-none-any.whl", hash = "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"}, {file = "appdirs-1.4.3.tar.gz", hash = "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"}, ] +asgiref = [ + {file = "asgiref-3.2.3-py2.py3-none-any.whl", hash = "sha256:ea448f92fc35a0ef4b1508f53a04c4670255a3f33d22a81c8fc9c872036adbe5"}, + {file = "asgiref-3.2.3.tar.gz", hash = "sha256:7e06d934a7718bf3975acbf87780ba678957b87c7adc056f13b6215d610695a0"}, +] "aspy.yaml" = [ {file = "aspy.yaml-1.3.0-py2.py3-none-any.whl", hash = "sha256:463372c043f70160a9ec950c3f1e4c3a82db5fca01d334b6bc89c7164d744bdc"}, {file = "aspy.yaml-1.3.0.tar.gz", hash = "sha256:e7c742382eff2caed61f87a39d13f99109088e5e93f04d76eb8d4b28aa143f45"}, @@ -2436,17 +2453,13 @@ dj-email-url = [ {file = "dj_email_url-0.2.0-py2.py3-none-any.whl", hash = "sha256:136ac43c7f29022130fc4769b4ca8b01cd1c39fedf1659c641c143808182a084"}, ] django = [ - {file = "Django-2.2.10-py3-none-any.whl", hash = "sha256:9a4635813e2d498a3c01b10c701fe4a515d76dd290aaa792ccb65ca4ccb6b038"}, - {file = "Django-2.2.10.tar.gz", hash = "sha256:1226168be1b1c7efd0e66ee79b0e0b58b2caa7ed87717909cd8a57bb13a7079a"}, + {file = "Django-3.0.4-py3-none-any.whl", hash = "sha256:89e451bfbb815280b137e33e454ddd56481fdaa6334054e6e031041ee1eda360"}, + {file = "Django-3.0.4.tar.gz", hash = "sha256:50b781f6cbeb98f673aa76ed8e572a019a45e52bdd4ad09001072dfd91ab07c8"}, ] django-appconf = [ {file = "django-appconf-1.0.3.tar.gz", hash = "sha256:35f13ca4d567f132b960e2cd4c832c2d03cb6543452d34e29b7ba10371ba80e3"}, {file = "django_appconf-1.0.3-py2.py3-none-any.whl", hash = "sha256:c98a7af40062e996b921f5962a1c4f3f0c979fa7885f7be4710cceb90ebe13a6"}, ] -django-babel = [ - {file = "django-babel-0.6.2.tar.gz", hash = "sha256:1e621b198e1f98ae4f93e43463cf78cbedbace475eb6e0853ba1e2567f3b8119"}, - {file = "django_babel-0.6.2-py2.py3-none-any.whl", hash = "sha256:b62084a6f0cbf2e7af719bd129abfe54608a52645c0677aff5a728f586873af7"}, -] django-countries = [ {file = "django-countries-5.5.tar.gz", hash = "sha256:1cefad9ec804d6a0318b91c5394b5aef00336755928f44d0a6420507719d65c8"}, {file = "django_countries-5.5-py2.py3-none-any.whl", hash = "sha256:22e96236101783cfe5222ef5174972242a7e8176336d119a4dc111aedce35897"}, @@ -2470,7 +2483,8 @@ django-graphiql-debug-toolbar = [ {file = "django-graphiql-debug-toolbar-0.1.4.tar.gz", hash = "sha256:946fba21418b3fd57e7e357d4cd110fb7881e08d3b7a0a8a00400fa2e75965f5"}, ] django-graphql-jwt = [ - {file = "django-graphql-jwt-0.2.1.tar.gz", hash = "sha256:6dcf9dd4990098e289d76ab4220edbf436a2e26dc6af1d4a526ac699ad93bf14"}, + {file = "django-graphql-jwt-0.3.0.tar.gz", hash = "sha256:c9c611d98510b57146c21484478eae793249553af3766a593e8f25ce73d3255a"}, + {file = "django_graphql_jwt-0.3.0-py2.py3-none-any.whl", hash = "sha256:bcf0882a492e2148cba7cba3c39cf57834f736a2c289b66852239faf9b59b61e"}, ] django-js-asset = [ {file = "django-js-asset-1.2.2.tar.gz", hash = "sha256:c163ae80d2e0b22d8fb598047cd0dcef31f81830e127cfecae278ad574167260"}, @@ -2488,10 +2502,12 @@ django-phonenumber-field = [ {file = "django_phonenumber_field-2.4.0-py2.py3-none-any.whl", hash = "sha256:a4ddedf21df5443fe1f064b8162117b214b15d5b93b8109b84e031456fb1fe5c"}, ] django-prices = [ - {file = "django-prices-2.1.0.tar.gz", hash = "sha256:bf237495ca0d1e8ce6183909815e11d3f8e8c6a27ef9ddbb3b1e9829874d6e55"}, + {file = "django-prices-2.2.0.tar.gz", hash = "sha256:cdbea06db683c589d4cf3ec48d4b2385000ddc4df6e641f48cea563e19f645a3"}, + {file = "django_prices-2.2.0-py3-none-any.whl", hash = "sha256:4ef054a660663c216a869126f1d209752381d5e311e5808438d29c944c2009d3"}, ] django-prices-openexchangerates = [ - {file = "django-prices-openexchangerates-1.0.1.tar.gz", hash = "sha256:59ede6a48003c463dffeccee9a7f0a292baf763b7dc141255b693abe1f79208c"}, + {file = "django-prices-openexchangerates-1.1.0.tar.gz", hash = "sha256:7d8d31c988dc42e9a90621eded3cef71de255bb6071aef942390bbd88edd4640"}, + {file = "django_prices_openexchangerates-1.1.0-py3-none-any.whl", hash = "sha256:e8a8e85020ab62071bec29bf48eb7e688822141291e9d855b045efe1ab27ea74"}, ] django-prices-vatlayer = [ {file = "django-prices-vatlayer-1.0.2.tar.gz", hash = "sha256:cd0e45a8e71b680c5fa8d7b2022535d7ccfd2bf71b10b18aa7f78b3aa0d596af"}, @@ -2515,8 +2531,8 @@ django-templated-email = [ {file = "django-templated-email-2.3.0.tar.gz", hash = "sha256:536c4e5ae099eabfb9aab36087d4d7799948c654e73da55a744213d086d5bb33"}, ] django-versatileimagefield = [ - {file = "django-versatileimagefield-1.11.tar.gz", hash = "sha256:8322ee9d7bf5ffa5360990320d2cc2efc7017feff35422636d49f625721edf82"}, - {file = "django_versatileimagefield-1.11-py2.py3-none-any.whl", hash = "sha256:90e1614db9ee593f502f4e5ec0942611589e1d91567a20447c8cf48459ee52d5"}, + {file = "django-versatileimagefield-2.0.tar.gz", hash = "sha256:b197e7066f23bb73b001a61525f2b1cae3dd654bf208a944a7ff5a3fe6107b51"}, + {file = "django_versatileimagefield-2.0-py2.py3-none-any.whl", hash = "sha256:090f89fd72379dd072d4e76dd708245cddc4ff601de27ea5a7d26f005019ef4c"}, ] docutils = [ {file = "docutils-0.15.2-py2-none-any.whl", hash = "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827"}, @@ -2526,6 +2542,10 @@ docutils = [ draftjs-sanitizer = [ {file = "draftjs-sanitizer-1.0.0.tar.gz", hash = "sha256:4603a9296153cd06d5a1d76a45a1ff0295363516af983d8dde28cafc5cd67583"}, ] +enmerkar = [ + {file = "enmerkar-0.7.1-py3-none-any.whl", hash = "sha256:ba5a79e022963580c994ce8f4fe8477d574159adbe86e5271b1a3d4127b8794d"}, + {file = "enmerkar-0.7.1.tar.gz", hash = "sha256:a4a6c859b4ed293deee40ff61d6695b3ff7bc153770a1799f2be872181282e00"}, +] entrypoints = [ {file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"}, {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, @@ -2588,8 +2608,8 @@ graphene = [ {file = "graphene-2.1.8.tar.gz", hash = "sha256:2cbe6d4ef15cfc7b7805e0760a0e5b80747161ce1b0f990dfdc0d2cf497c12f9"}, ] graphene-django = [ - {file = "graphene-django-2.6.0.tar.gz", hash = "sha256:0d1404ab1ba7873a8e848d87d138f615391d100ed0c046482c164429cfb992ef"}, - {file = "graphene_django-2.6.0-py2.py3-none-any.whl", hash = "sha256:fa9e815f63e3c972773adc96c3f3c81e537dba0edcd0f1be92c799bc0b6ed0a8"}, + {file = "graphene-django-2.8.2.tar.gz", hash = "sha256:1f65861af9422e42418c6caad3ab6b75ee52b2410dc860de3060a5dcd3840359"}, + {file = "graphene_django-2.8.2-py2.py3-none-any.whl", hash = "sha256:d9e019a23f442ca31f0e012f578f2b84d40fbf66b88930fc747f7ad8f9a9f7c8"}, ] graphene-django-optimizer = [ {file = "graphene-django-optimizer-0.6.1.tar.gz", hash = "sha256:2c3902cfc739ae7f9953c9130fa4030d4f1bd9e81c820713c4270137e63f89cb"}, diff --git a/pyproject.toml b/pyproject.toml index b49d7b0d182..8f29d515f64 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,11 +20,10 @@ braintree = "~3.49.0" celery = { version = "^4.3.0", extras = ["redis"] } dj-database-url = "^0" dj-email-url = "^0" -django = "~2.2" -django-babel = "^0" +django = "^3.0.0" django-countries = "^5.3" django-filter = "^2.2" -django-graphql-jwt = "<=0.2.1" # https://github.com/mirumee/saleor/issues/4652 +django-graphql-jwt = "^0.3.0" # https://github.com/mirumee/saleor/issues/4652 django-measurement = "^3.0" django-mptt = "^0" django-phonenumber-field = "^2.4" @@ -34,14 +33,14 @@ django-prices-vatlayer = "^1.0.2" django-silk = "~2.0" django-storages = { version = "^1.7.1", extras = [ "google" ] } django-templated-email = "^2.3.0" -django-versatileimagefield = "^1.11" +django-versatileimagefield = "^2.0" draftjs-sanitizer = "^1.0.0" faker = "^2.0" freezegun = "^0" google-cloud-storage = "^1.18.0" google-i18n-address = "^2.3.5" google-measurement-protocol = "^1.0" -graphene-django = "2.6.0" +graphene-django = "^2.8.0" graphene-django-optimizer = "^0.6" graphene-federation = "^0.0.3" html-to-draftjs = "^1.0.1" diff --git a/requirements.txt b/requirements.txt index ee49f0ea993..2d0779fd4d9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ amqp==2.5.2 aniso8601==7.0.0 +asgiref==3.2.3 autopep8==1.5 babel==2.7.0 beautifulsoup4==4.7.1 @@ -19,26 +20,26 @@ cssselect2==0.2.2 defusedxml==0.6.0 dj-database-url==0.5.0 dj-email-url==0.2.0 -django==2.2.10 +django==3.0.4 django-appconf==1.0.3 -django-babel==0.6.2 django-countries==5.5 django-filter==2.2.0 -django-graphql-jwt==0.2.1 +django-graphql-jwt==0.3.0 django-js-asset==1.2.2 django-measurement==3.2.0 django-mptt==0.11.0 django-phonenumber-field==2.4.0 -django-prices==2.1.0 -django-prices-openexchangerates==1.0.1 +django-prices==2.2.0 +django-prices-openexchangerates==1.1.0 django-prices-vatlayer==1.0.2 django-render-block==0.6 django-silk==2.0.0 django-storages==1.9.1 django-templated-email==2.3.0 -django-versatileimagefield==1.11 +django-versatileimagefield==2.0 docutils==0.15.2 draftjs-sanitizer==1.0.0 +enmerkar==0.7.1 faker==2.0.5 freezegun==0.3.15 google-api-core==1.16.0 @@ -51,7 +52,7 @@ google-resumable-media==0.5.0 googleapis-common-protos==1.51.0 gprof2dot==2016.10.13 graphene==2.1.8 -graphene-django==2.6.0 +graphene-django==2.8.2 graphene-django-optimizer==0.6.1 graphene-federation==0.0.3 graphql-core==2.3.1 diff --git a/requirements_dev.txt b/requirements_dev.txt index 5ca7b859900..459046ca620 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -2,6 +2,7 @@ amqp==2.5.2 aniso8601==7.0.0 apipkg==1.5 appdirs==1.4.3 +asgiref==3.2.3 aspy.yaml==1.3.0 astroid==2.3.3 atomicwrites==1.3.0; sys_platform == "win32" @@ -33,31 +34,31 @@ defusedxml==0.6.0 distlib==0.3.0 dj-database-url==0.5.0 dj-email-url==0.2.0 -django==2.2.10 +django==3.0.4 django-appconf==1.0.3 -django-babel==0.6.2 django-countries==5.5 django-debug-toolbar==2.2 django-debug-toolbar-request-history==0.1.1 django-extensions==2.2.8 django-filter==2.2.0 django-graphiql-debug-toolbar==0.1.4 -django-graphql-jwt==0.2.1 +django-graphql-jwt==0.3.0 django-js-asset==1.2.2 django-measurement==3.2.0 django-mptt==0.11.0 django-phonenumber-field==2.4.0 -django-prices==2.1.0 -django-prices-openexchangerates==1.0.1 +django-prices==2.2.0 +django-prices-openexchangerates==1.1.0 django-prices-vatlayer==1.0.2 django-render-block==0.6 django-silk==2.0.0 django-storages==1.9.1 django-stubs==1.2.0 django-templated-email==2.3.0 -django-versatileimagefield==1.11 +django-versatileimagefield==2.0 docutils==0.15.2 draftjs-sanitizer==1.0.0 +enmerkar==0.7.1 entrypoints==0.3 execnet==1.7.1 faker==2.0.5 @@ -74,7 +75,7 @@ google-resumable-media==0.5.0 googleapis-common-protos==1.51.0 gprof2dot==2016.10.13 graphene==2.1.8 -graphene-django==2.6.0 +graphene-django==2.8.2 graphene-django-optimizer==0.6.1 graphene-federation==0.0.3 graphql-core==2.3.1 diff --git a/saleor/checkout/context_processors.py b/saleor/checkout/context_processors.py deleted file mode 100644 index efd4020e6ea..00000000000 --- a/saleor/checkout/context_processors.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Checkout-related context processors.""" -from .utils import get_checkout_from_request - - -def checkout_counter(request): - """Expose the number of items in checkout.""" - checkout = get_checkout_from_request(request) - return {"checkout_counter": checkout.quantity} diff --git a/saleor/demo/views.py b/saleor/demo/views.py index 1bdde9c2426..430e22b1986 100644 --- a/saleor/demo/views.py +++ b/saleor/demo/views.py @@ -1,4 +1,4 @@ -from django.shortcuts import render_to_response +from django.shortcuts import render from ..graphql.views import API_PATH, GraphQLView @@ -30,4 +30,4 @@ def render_playground(self, request): "query": EXAMPLE_QUERY, "api_url": request.build_absolute_uri(str(API_PATH)), } - return render_to_response("graphql/playground.html", ctx) + return render(request, "graphql/playground.html", ctx) diff --git a/saleor/graphql/core/fields.py b/saleor/graphql/core/fields.py index 130a9bbb635..1d569cd90c9 100644 --- a/saleor/graphql/core/fields.py +++ b/saleor/graphql/core/fields.py @@ -68,6 +68,7 @@ def connection_resolver( resolver, connection, default_manager, + queryset_resolver, max_limit, enforce_first_or_last, root, @@ -86,6 +87,7 @@ def connection_resolver( resolver, connection, default_manager, + queryset_resolver, max_limit, enforce_first_or_last, root, @@ -94,10 +96,7 @@ def connection_resolver( ) @classmethod - def resolve_connection(cls, connection, default_manager, args, iterable): - if iterable is None: - iterable = default_manager - + def resolve_connection(cls, connection, args, iterable): if isinstance(iterable, QuerySet): _len = iterable.count() else: @@ -133,6 +132,7 @@ def connection_resolver( resolver, connection, default_manager, + queryset_resolver, max_limit, enforce_first_or_last, filterset_class, @@ -175,7 +175,13 @@ def connection_resolver( iterable = resolver(root, info, **args) - on_resolve = partial(cls.resolve_connection, connection, default_manager, args) + if iterable is None: + iterable = default_manager + # thus the iterable gets refiltered by resolve_queryset + # but iterable might be promise + iterable = queryset_resolver(connection, iterable, info, args) + + on_resolve = partial(cls.resolve_connection, connection, args) filter_input = args.get(filters_name) diff --git a/saleor/graphql/core/types/filter_input.py b/saleor/graphql/core/types/filter_input.py index e340de81373..1690ee05772 100644 --- a/saleor/graphql/core/types/filter_input.py +++ b/saleor/graphql/core/types/filter_input.py @@ -1,4 +1,3 @@ -import six from graphene import InputField, InputObjectType from graphene.types.inputobjecttype import InputObjectTypeOptions from graphene.types.utils import yank_fields_from_attrs @@ -52,7 +51,7 @@ def get_filtering_args_from_filterset(cls): cls.filterset_class = get_filterset_class(cls.custom_filterset_class, **meta) args = {} - for name, filter_field in six.iteritems(cls.filterset_class.base_filters): + for name, filter_field in cls.filterset_class.base_filters.items(): input_class = getattr(filter_field, "input_class", None) if input_class: field_type = convert_form_field(filter_field) diff --git a/saleor/graphql/middleware.py b/saleor/graphql/middleware.py index 9ea972c2a19..8d386a22afd 100644 --- a/saleor/graphql/middleware.py +++ b/saleor/graphql/middleware.py @@ -5,7 +5,6 @@ from django.conf import settings from django.contrib.auth.models import AnonymousUser from django.utils.functional import SimpleLazyObject -from graphene_django.settings import graphene_settings from graphql import ResolveInfo from graphql_jwt.middleware import JSONWebTokenMiddleware @@ -14,29 +13,13 @@ from .views import API_PATH, GraphQLView -def jwt_middleware(get_response): - """Authenticate a user using JWT and ignore the session-based authentication. +class JWTMiddleware(JSONWebTokenMiddleware): + def resolve(self, next, root, info, **kwargs): + request = info.context - This middleware resets authentication made by any previous middlewares - and authenticates the user - with graphql_jwt.middleware.JSONWebTokenMiddleware. - """ - # Disable warnings for django-graphene-jwt - graphene_settings.MIDDLEWARE.append(JSONWebTokenMiddleware) - jwt_middleware_inst = JSONWebTokenMiddleware(get_response=get_response) - graphene_settings.MIDDLEWARE.remove(JSONWebTokenMiddleware) - - def _jwt_middleware(request): - if request.path == API_PATH: - # clear user authenticated by AuthenticationMiddleware - request._cached_user = AnonymousUser() + if not hasattr(request, "user"): request.user = AnonymousUser() - - # authenticate using JWT middleware - jwt_middleware_inst.process_request(request) - return get_response(request) - - return _jwt_middleware + return super().resolve(next, root, info, **kwargs) class OpentracingGrapheneMiddleware: @@ -58,13 +41,14 @@ def get_service_account(auth_token) -> Optional[ServiceAccount]: return qs.first() -def service_account_middleware(get_response): +def service_account_middleware(next, root, info, **kwargs): service_account_auth_header = "HTTP_AUTHORIZATION" prefix = "bearer" + request = info.context - def _service_account_middleware(request): - if request.path == API_PATH: + if request.path == API_PATH: + if not hasattr(request, "service_account"): request.service_account = None auth = request.META.get(service_account_auth_header, "").split() if len(auth) == 2: @@ -73,9 +57,7 @@ def _service_account_middleware(request): request.service_account = SimpleLazyObject( lambda: get_service_account(auth_token) ) - return get_response(request) - - return _service_account_middleware + return next(root, info, **kwargs) def process_view(self, request, view_func, *args): diff --git a/saleor/graphql/views.py b/saleor/graphql/views.py index 581667c18fe..37e26caea27 100644 --- a/saleor/graphql/views.py +++ b/saleor/graphql/views.py @@ -9,7 +9,7 @@ from django.db import connection from django.db.backends.postgresql.base import DatabaseWrapper from django.http import HttpRequest, HttpResponseNotAllowed, JsonResponse -from django.shortcuts import render_to_response +from django.shortcuts import render from django.urls import reverse from django.utils.functional import SimpleLazyObject from django.views.generic import View @@ -98,7 +98,7 @@ def dispatch(self, request, *args, **kwargs): return response def render_playground(self, request): - return render_to_response("graphql/playground.html", {}) + return render(request, "graphql/playground.html", {}) def _handle_query(self, request: HttpRequest) -> JsonResponse: try: diff --git a/saleor/settings.py b/saleor/settings.py index 9b8a032e683..62f0a53bb30 100644 --- a/saleor/settings.py +++ b/saleor/settings.py @@ -160,7 +160,6 @@ def get_bool_from_env(name, default_value): "django.template.context_processors.debug", "django.template.context_processors.media", "django.template.context_processors.static", - "saleor.checkout.context_processors.checkout_counter", "saleor.site.context_processors.site", ] @@ -194,8 +193,6 @@ def get_bool_from_env(name, default_value): "saleor.core.middleware.currency", "saleor.core.middleware.site", "saleor.core.middleware.extensions", - "saleor.graphql.middleware.jwt_middleware", - "saleor.graphql.middleware.service_account_middleware", ] INSTALLED_APPS = [ @@ -532,9 +529,13 @@ def get_host(): sentry_sdk.init(dsn=SENTRY_DSN, integrations=[DjangoIntegration()]) GRAPHENE = { - "MIDDLEWARE": ("saleor.graphql.middleware.OpentracingGrapheneMiddleware",), "RELAY_CONNECTION_ENFORCE_FIRST_OR_LAST": True, "RELAY_CONNECTION_MAX_LIMIT": 100, + "MIDDLEWARE": [ + "saleor.graphql.middleware.OpentracingGrapheneMiddleware", + "saleor.graphql.middleware.JWTMiddleware", + "saleor.graphql.middleware.service_account_middleware", + ], } EXTENSIONS_MANAGER = "saleor.extensions.manager.ExtensionsManager" diff --git a/tests/api/test_account.py b/tests/api/test_account.py index 379f2c27480..9931b60532f 100644 --- a/tests/api/test_account.py +++ b/tests/api/test_account.py @@ -2185,7 +2185,7 @@ def test_account_reset_password( url_validator(url) -def test_account_confirmation(user_api_client, customer_user): +def test_account_confirmation(api_client, customer_user): customer_user.is_active = False customer_user.save() @@ -2193,7 +2193,9 @@ def test_account_confirmation(user_api_client, customer_user): "email": customer_user.email, "token": default_token_generator.make_token(customer_user), } - user_api_client.post_graphql(CONFIRM_ACCOUNT_MUTATION, variables) + response = api_client.post_graphql(CONFIRM_ACCOUNT_MUTATION, variables) + content = get_graphql_content(response) + assert not content["data"]["confirmAccount"]["errors"] customer_user.refresh_from_db() assert customer_user.is_active is True diff --git a/tests/api/test_middleware.py b/tests/api/test_middleware.py index 8c965c746d3..29f37e6db1c 100644 --- a/tests/api/test_middleware.py +++ b/tests/api/test_middleware.py @@ -12,7 +12,8 @@ def test_service_account_middleware_accepts_api_requests(service_account, rf): token = service_account.tokens.first().auth_token request.META = {"HTTP_AUTHORIZATION": f"Bearer {token}"} - middleware = service_account_middleware(Mock()) - middleware(request) + service_account_middleware( + lambda root, info: info.context, Mock(), Mock(context=request) + ) assert request.service_account == service_account diff --git a/tests/test_cart.py b/tests/test_cart.py index 6883070d52d..cc7f1d5dd9b 100644 --- a/tests/test_cart.py +++ b/tests/test_cart.py @@ -1,4 +1,3 @@ -from unittest.mock import Mock from uuid import uuid4 import pytest @@ -6,7 +5,6 @@ from prices import Money, TaxedMoney from saleor.checkout import calculations, utils -from saleor.checkout.context_processors import checkout_counter from saleor.checkout.models import Checkout from saleor.checkout.utils import add_variant_to_checkout from saleor.product.models import Category @@ -103,15 +101,6 @@ def test_shipping_detection(checkout, product): assert checkout.is_shipping_required() -def test_checkout_counter(monkeypatch): - monkeypatch.setattr( - "saleor.checkout.context_processors.get_checkout_from_request", - Mock(return_value=Mock(quantity=4)), - ) - ret = checkout_counter(Mock()) - assert ret == {"checkout_counter": 4} - - def test_get_prices_of_discounted_specific_product( checkout_with_item, collection, voucher_specific_product_type ): diff --git a/tox.ini b/tox.ini index ed1ad451837..5a27566f574 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py38-django{22,30,_master} +envlist = py38-django{30,_master} skipsdist = True [testenv] @@ -10,7 +10,6 @@ deps = -rrequirements.txt -rrequirements_dev.txt commands = - django22: pip install "django>=2.2a1,<2.3" --upgrade --pre django30: pip install "django>=3.0a1,<3.1" --upgrade --pre django_master: pip install https://github.com/django/django/archive/master.tar.gz python manage.py collectstatic --noinput --verbosity=0 @@ -63,6 +62,5 @@ unignore_outcomes = True [travis:env] DJANGO = - 2.2: django22 3.0: django30 master: django_master