diff --git a/.bumpversion.cfg b/.bumpversion.cfg index f2c8fe93..b2f6deac 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,7 +1,7 @@ [bumpversion] commit = False tag = False -current_version = 2.4.3 +current_version = 2.4.4 [bumpversion:file:README.rst] diff --git a/.github/workflows/oaf-check.yml b/.github/workflows/oaf-check.yml new file mode 100644 index 00000000..720a2064 --- /dev/null +++ b/.github/workflows/oaf-check.yml @@ -0,0 +1,23 @@ +name: Check Open API Framework Version + +on: + workflow_dispatch: + schedule: + - cron: '36 0 * * 0' + +jobs: + run: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Install dependencies + run: pip install -U pip-tools + - name: Run compile dependencies + run: ./bin/compile_dependencies.sh --upgrade-package open-api-framework + + - name: Check git diff + run: git diff --exit-code -- requirements/*.txt diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2cffa4d3..a8fe18ca 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,11 +2,35 @@ Change history ============== +3.0.0 (WIP) +----------- + +**Breaking changes** + +* dropped support for v1 endpoints (#453) + + +2.4.4 (2024-10-01) +------------------ + +**Bugfixes and QOL** + +* fixed CSP errors on the OAS page (#458) +* fixed OIDC login by making SameSite setting lax (#458) +* fixed adding permissions in the Admin (#449) +* fixed ``NOTIFICATIONS_DISABLED`` setting (#452) + +**Project maintenance** + +* added CI action to check if OAF is up-to-date (#443) + + 2.4.3 (2024-09-18) ------------------ **New features** +* added an endpoint to retrieve a specific object version (#328) * supported the `in` operator in `data_attrs` to match one element (#414) **Bugfixes and QOL** @@ -15,9 +39,9 @@ Change history * fixed 2FA app title (#442) * bumped setuptools and npm dependencies (#441) -**Project maintaince** +**Project maintenance** -* disabled cofiguration steps by default (#446) +* disabled configuration steps by default (#446) * increase default values for uwsgi processes and threads (#448) .. warning:: diff --git a/README.NL.rst b/README.NL.rst index bfb53159..965b3d1a 100644 --- a/README.NL.rst +++ b/README.NL.rst @@ -2,7 +2,7 @@ Objecten API ============ -:Version: 2.4.3 +:Version: 2.4.4 :Source: https://github.com/maykinmedia/objecttypes-api :Keywords: objecten, assets, zaakobjecten @@ -38,10 +38,10 @@ Versie Release datum API specificatie ============== ============== ============================= latest n/a `ReDoc `_, `Swagger `_, - (`verschillen `_) -2.4.3 2024-03-22 `ReDoc `_, - `Swagger `_ - (`verschillen `_) + (`verschillen `_) +2.4.4 2024-03-22 `ReDoc `_, + `Swagger `_ + (`verschillen `_) 2.3.0 2024-03-15 `ReDoc `_, `Swagger `_ (`verschillen `_) diff --git a/README.rst b/README.rst index bb3f6544..319c080b 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ Objects API =========== -:Version: 2.4.3 +:Version: 2.4.4 :Source: https://github.com/maykinmedia/objects-api :Keywords: objects, assets, zaakobjecten @@ -36,10 +36,10 @@ Version Release date API specification ============== ============== ============================= latest n/a `ReDoc `_, `Swagger `_, - (`diff `_) -2.4.3 2024-03-22 `ReDoc `_, - `Swagger `_ - (`diff `_) + (`diff `_) +2.4.4 2024-03-22 `ReDoc `_, + `Swagger `_ + (`diff `_) 2.3.0 2024-03-15 `ReDoc `_, `Swagger `_ (`diff `_) diff --git a/docs/api/index.rst b/docs/api/index.rst index 847cafc8..714308e0 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -14,9 +14,9 @@ API Specification version(s) `Redoc `__, `Swagger `__ ) -`Objects API`_ 2.4.3 ( - `Redoc `__, - `Swagger `__ +`Objects API`_ 2.4.4 ( + `Redoc `__, + `Swagger `__ ) ====================== ========================================== diff --git a/docs/installation/config.rst b/docs/installation/config.rst index 22f6fa0b..ade5c652 100644 --- a/docs/installation/config.rst +++ b/docs/installation/config.rst @@ -16,7 +16,7 @@ Available environment variables Required -------- -* ``SECRET_KEY``: Secret key that's used for certain cryptographic utilities. You should generate one via `miniwebtool `_. +* ``SECRET_KEY``: Secret key that's used for certain cryptographic utilities. . * ``ALLOWED_HOSTS``: a comma separated (without spaces!) list of domains that serve the installation. Used to protect against Host header attacks. Defaults to: ``(empty string)``. * ``CACHE_DEFAULT``: redis cache address for the default cache (this **MUST** be set when using Docker). Defaults to: ``localhost:6379/0``. * ``CACHE_AXES``: redis cache address for the brute force login protection cache (this **MUST** be set when using Docker). Defaults to: ``localhost:6379/0``. @@ -86,7 +86,7 @@ Optional * ``LOG_LEVEL``: control the verbosity of logging output. Available values are ``CRITICAL``, ``ERROR``, ``WARNING``, ``INFO`` and ``DEBUG``. Defaults to: ``WARNING``. * ``LOG_QUERIES``: enable (query) logging at the database backend level. Note that you must also set ``DEBUG=1``, which should be done very sparingly!. Defaults to: ``False``. * ``LOG_REQUESTS``: enable logging of the outgoing requests. Defaults to: ``False``. -* ``SESSION_COOKIE_SAMESITE``: The value of the SameSite flag on the session cookie. This flag prevents the cookie from being sent in cross-site requests thus preventing CSRF attacks and making some methods of stealing session cookie impossible. Defaults to: ``Strict``. +* ``SESSION_COOKIE_SAMESITE``: The value of the SameSite flag on the session cookie. This flag prevents the cookie from being sent in cross-site requests thus preventing CSRF attacks and making some methods of stealing session cookie impossible.Currently interferes with OIDC. Keep the value set at Lax if used. Defaults to: ``Lax``. * ``CSRF_COOKIE_SAMESITE``: The value of the SameSite flag on the CSRF cookie. This flag prevents the cookie from being sent in cross-site requests. Defaults to: ``Strict``. * ``ENVIRONMENT``: An identifier for the environment, displayed in the admin depending on the settings module used and included in the error monitoring (see ``SENTRY_DSN``). The default is set according to ``DJANGO_SETTINGS_MODULE``. * ``SUBPATH``: If hosted on a subpath, provide the value here. If you provide ``/gateway``, the component assumes its running at the base URL: ``https://somedomain/gateway/``. Defaults to an empty string. Defaults to: ``None``. diff --git a/package-lock.json b/package-lock.json index 3fb41a6c..ae023c01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "objects", - "version": "2.4.3", + "version": "2.4.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "objects", - "version": "2.4.3", + "version": "2.4.4", "license": "UNLICENSED", "dependencies": { "microscope-sass": "latest", diff --git a/package.json b/package.json index 622f4bcd..22f4ddc7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "objects", - "version": "2.4.3", + "version": "2.4.4", "description": "objects project", "main": "src/objects/static/bundles/objects-js.js", "directories": { diff --git a/publiccode.yaml b/publiccode.yaml index d2e4d661..78f4ed23 100644 --- a/publiccode.yaml +++ b/publiccode.yaml @@ -7,7 +7,7 @@ publiccodeYmlVersion: '0.2' name: Objects API url: 'http://github.com/maykinmedia/objects-api.git' softwareType: standalone/backend -softwareVersion: 2.4.3 +softwareVersion: 2.4.4 releaseDate: '2021-01-13' logo: 'https://github.com/maykinmedia/objects-api/blob/master/docs/logo.png' platforms: diff --git a/requirements/base.txt b/requirements/base.txt index 1b36d072..fca3e8d3 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -97,6 +97,7 @@ django==4.2.15 # djangorestframework-inclusions # drf-nested-routers # drf-spectacular + # drf-spectacular-sidecar # drf-yasg # maykin-2fa # mozilla-django-oidc @@ -177,8 +178,12 @@ djangorestframework-inclusions==1.2.0 # via open-api-framework drf-nested-routers==0.93.3 # via commonground-api-common -drf-spectacular==0.27.2 - # via open-api-framework +drf-spectacular[sidecar]==0.27.2 + # via + # drf-spectacular + # open-api-framework +drf-spectacular-sidecar==2024.7.1 + # via drf-spectacular drf-yasg==1.21.7 # via commonground-api-common ecs-logging==2.1.0 @@ -238,7 +243,7 @@ notifications-api-common==0.2.2 # via # -r requirements/base.in # commonground-api-common -open-api-framework==0.8.0 +open-api-framework==0.8.1 # via -r requirements/base.in orderedmultidict==1.0.1 # via furl diff --git a/requirements/ci.txt b/requirements/ci.txt index 461167ee..60bcebb4 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -139,6 +139,7 @@ django==4.2.15 # djangorestframework-inclusions # drf-nested-routers # drf-spectacular + # drf-spectacular-sidecar # drf-yasg # maykin-2fa # mozilla-django-oidc @@ -271,10 +272,15 @@ drf-nested-routers==0.93.3 # via # -r requirements/base.txt # commonground-api-common -drf-spectacular==0.27.2 +drf-spectacular[sidecar]==0.27.2 # via # -r requirements/base.txt + # drf-spectacular # open-api-framework +drf-spectacular-sidecar==2024.7.1 + # via + # -r requirements/base.txt + # drf-spectacular drf-yasg==1.21.7 # via # -r requirements/base.txt @@ -381,7 +387,7 @@ notifications-api-common==0.2.2 # via # -r requirements/base.txt # commonground-api-common -open-api-framework==0.8.0 +open-api-framework==0.8.1 # via -r requirements/base.txt orderedmultidict==1.0.1 # via diff --git a/requirements/dev.txt b/requirements/dev.txt index 9e0a12f1..9e7bf619 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -161,6 +161,7 @@ django==4.2.15 # djangorestframework-inclusions # drf-nested-routers # drf-spectacular + # drf-spectacular-sidecar # drf-yasg # maykin-2fa # mozilla-django-oidc @@ -303,10 +304,15 @@ drf-nested-routers==0.93.3 # via # -r requirements/ci.txt # commonground-api-common -drf-spectacular==0.27.2 +drf-spectacular[sidecar]==0.27.2 # via # -r requirements/ci.txt + # drf-spectacular # open-api-framework +drf-spectacular-sidecar==2024.7.1 + # via + # -r requirements/ci.txt + # drf-spectacular drf-yasg==1.21.7 # via # -r requirements/ci.txt @@ -430,7 +436,7 @@ notifications-api-common==0.2.2 # via # -r requirements/ci.txt # commonground-api-common -open-api-framework==0.8.0 +open-api-framework==0.8.1 # via -r requirements/ci.txt orderedmultidict==1.0.1 # via diff --git a/src/objects/__init__.py b/src/objects/__init__.py index 5f18cdd4..0ba1c8ff 100644 --- a/src/objects/__init__.py +++ b/src/objects/__init__.py @@ -1,6 +1,6 @@ from .celery import app as celery_app __all__ = ("celery_app",) -__version__ = "2.4.3" +__version__ = "2.4.4" __author__ = "Maykin Media" __homepage__ = "https://github.com/maykinmedia/objects-api" diff --git a/src/objects/api/v2/openapi.yaml b/src/objects/api/v2/openapi.yaml index 125a9b28..7e49cd0f 100644 --- a/src/objects/api/v2/openapi.yaml +++ b/src/objects/api/v2/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: Objects API - version: 2.4.3 (v2) + version: 2.4.4 (v2) description: | An API to manage Objects. diff --git a/src/objects/conf/api.py b/src/objects/conf/api.py index 1bd23544..cd173212 100644 --- a/src/objects/conf/api.py +++ b/src/objects/conf/api.py @@ -1,7 +1,5 @@ -from vng_api_common.conf.api import * # noqa - imports white-listed - -API_VERSION = "2.4.3" -VERSIONS = {"v1": "1.3.0", "v2": "2.4.3"} +API_VERSION = "2.4.4" +VERSIONS = {"v1": "1.3.0", "v2": "2.4.4"} # api settings REST_FRAMEWORK = { @@ -89,6 +87,7 @@ """ SPECTACULAR_SETTINGS = { + "REDOC_DIST": "SIDECAR", "SCHEMA_PATH_PREFIX": r"/api/v[1-9]+", "SCHEMA_PATH_PREFIX_TRIM": True, "TITLE": "Objects API", diff --git a/src/objects/token/admin.py b/src/objects/token/admin.py index 03959f9c..3d7d82b6 100644 --- a/src/objects/token/admin.py +++ b/src/objects/token/admin.py @@ -52,6 +52,10 @@ def get_data_field_choices(self): except requests.JSONDecodeError: continue + # TODO: remove check once API V1 is removed + if "results" in response_data: + response_data = response_data["results"] + # use only first level of properties data_fields[object_type.id] = { version["version"]: { diff --git a/src/objects/token/tests/cassettes/PermissionAdminTests.test_with_object_types_api_v1.yaml b/src/objects/token/tests/cassettes/PermissionAdminTests.test_with_object_types_api_v1.yaml new file mode 100644 index 00000000..d787d463 --- /dev/null +++ b/src/objects/token/tests/cassettes/PermissionAdminTests.test_with_object_types_api_v1.yaml @@ -0,0 +1,96 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.3 + method: GET + uri: http://127.0.0.1:8008/api/v1/objecttypes + response: + body: + string: '[{"url":"http://127.0.0.1:8008/api/v1/objecttypes/71a2452a-66c3-4030-b5ec-a06035102e9e","uuid":"71a2452a-66c3-4030-b5ec-a06035102e9e","name":"Garry","namePlural":"Garrys","description":"","dataClassification":"open","maintainerOrganization":"","maintainerDepartment":"","contactPerson":"","contactEmail":"","source":"","updateFrequency":"unknown","providerOrganization":"","documentationUrl":"","labels":{},"createdAt":"2024-09-24","modifiedAt":"2024-09-24","allowGeometry":true,"versions":["http://127.0.0.1:8008/api/v1/objecttypes/71a2452a-66c3-4030-b5ec-a06035102e9e/versions/1"]}]' + headers: + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '584' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Date: + - Tue, 24 Sep 2024 14:49:45 GMT + Referrer-Policy: + - same-origin + Server: + - WSGIServer/0.2 CPython/3.11.10 + Server-Timing: + - TimerPanel_utime;dur=66.08599999999998;desc="User CPU time", TimerPanel_stime;dur=41.489;desc="System + CPU time", TimerPanel_total;dur=107.57499999999999;desc="Total CPU time", + TimerPanel_total_time;dur=109.82951400001184;desc="Elapsed time", SQLPanel_sql_time;dur=2.634805998241063;desc="SQL + 3 queries", CachePanel_total_time;dur=0;desc="Cache 0 Calls" + Vary: + - origin, Cookie + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + djdt-store-id: + - 011b401c548140e393c17931b9eed7e2 + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.3 + method: GET + uri: http://127.0.0.1:8008/api/v1/objecttypes/71a2452a-66c3-4030-b5ec-a06035102e9e/versions + response: + body: + string: '[{"url":"http://127.0.0.1:8008/api/v1/objecttypes/71a2452a-66c3-4030-b5ec-a06035102e9e/versions/1","version":1,"objectType":"http://127.0.0.1:8008/api/v1/objecttypes/71a2452a-66c3-4030-b5ec-a06035102e9e","status":"draft","jsonSchema":{"string":"value"},"createdAt":"2024-09-24","modifiedAt":"2024-09-24","publishedAt":null}]' + headers: + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '324' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Date: + - Tue, 24 Sep 2024 14:49:45 GMT + Referrer-Policy: + - same-origin + Server: + - WSGIServer/0.2 CPython/3.11.10 + Server-Timing: + - TimerPanel_utime;dur=26.51400000000004;desc="User CPU time", TimerPanel_stime;dur=8.871000000000018;desc="System + CPU time", TimerPanel_total;dur=35.385000000000055;desc="Total CPU time", + TimerPanel_total_time;dur=29.870047997974325;desc="Elapsed time", SQLPanel_sql_time;dur=3.140712000458734;desc="SQL + 3 queries", CachePanel_total_time;dur=0;desc="Cache 0 Calls" + Vary: + - origin, Cookie + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + djdt-store-id: + - 58b76bf29d284ba694ccdabb76919aa7 + status: + code: 200 + message: OK +version: 1 diff --git a/src/objects/token/tests/cassettes/PermissionAdminTests.test_with_object_types_api_v2.yaml b/src/objects/token/tests/cassettes/PermissionAdminTests.test_with_object_types_api_v2.yaml new file mode 100644 index 00000000..461b90cc --- /dev/null +++ b/src/objects/token/tests/cassettes/PermissionAdminTests.test_with_object_types_api_v2.yaml @@ -0,0 +1,96 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.3 + method: GET + uri: http://127.0.0.1:8008/api/v2/objecttypes + response: + body: + string: '{"count":1,"next":null,"previous":null,"results":[{"url":"http://127.0.0.1:8008/api/v2/objecttypes/71a2452a-66c3-4030-b5ec-a06035102e9e","uuid":"71a2452a-66c3-4030-b5ec-a06035102e9e","name":"Garry","namePlural":"Garrys","description":"","dataClassification":"open","maintainerOrganization":"","maintainerDepartment":"","contactPerson":"","contactEmail":"","source":"","updateFrequency":"unknown","providerOrganization":"","documentationUrl":"","labels":{},"createdAt":"2024-09-24","modifiedAt":"2024-09-24","allowGeometry":true,"versions":["http://127.0.0.1:8008/api/v2/objecttypes/71a2452a-66c3-4030-b5ec-a06035102e9e/versions/1"]}]}' + headers: + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '634' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Date: + - Tue, 24 Sep 2024 14:49:45 GMT + Referrer-Policy: + - same-origin + Server: + - WSGIServer/0.2 CPython/3.11.10 + Server-Timing: + - TimerPanel_utime;dur=17.129999999999868;desc="User CPU time", TimerPanel_stime;dur=2.0120000000000138;desc="System + CPU time", TimerPanel_total;dur=19.141999999999882;desc="Total CPU time", + TimerPanel_total_time;dur=21.54170200083172;desc="Elapsed time", SQLPanel_sql_time;dur=2.798614998027915;desc="SQL + 4 queries", CachePanel_total_time;dur=0;desc="Cache 0 Calls" + Vary: + - origin, Cookie + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + djdt-store-id: + - a591b4b56a884263835fbf632b782baf + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.3 + method: GET + uri: http://127.0.0.1:8008/api/v2/objecttypes/71a2452a-66c3-4030-b5ec-a06035102e9e/versions + response: + body: + string: '{"count":1,"next":null,"previous":null,"results":[{"url":"http://127.0.0.1:8008/api/v2/objecttypes/71a2452a-66c3-4030-b5ec-a06035102e9e/versions/1","version":1,"objectType":"http://127.0.0.1:8008/api/v2/objecttypes/71a2452a-66c3-4030-b5ec-a06035102e9e","status":"draft","jsonSchema":{"string":"value"},"createdAt":"2024-09-24","modifiedAt":"2024-09-24","publishedAt":null}]}' + headers: + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '374' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Date: + - Tue, 24 Sep 2024 14:49:45 GMT + Referrer-Policy: + - same-origin + Server: + - WSGIServer/0.2 CPython/3.11.10 + Server-Timing: + - TimerPanel_utime;dur=17.527999999999988;desc="User CPU time", TimerPanel_stime;dur=0.8290000000000242;desc="System + CPU time", TimerPanel_total;dur=18.357000000000014;desc="Total CPU time", + TimerPanel_total_time;dur=20.605010002327617;desc="Elapsed time", SQLPanel_sql_time;dur=2.700799006561283;desc="SQL + 4 queries", CachePanel_total_time;dur=0;desc="Cache 0 Calls" + Vary: + - origin, Cookie + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + djdt-store-id: + - fa6e9a070865404f8c02c2ad60df23b2 + status: + code: 200 + message: OK +version: 1 diff --git a/src/objects/token/tests/test_admin.py b/src/objects/token/tests/test_admin.py new file mode 100644 index 00000000..0db3ea0d --- /dev/null +++ b/src/objects/token/tests/test_admin.py @@ -0,0 +1,92 @@ +from django.test import TestCase, tag +from django.urls import reverse + +from maykin_2fa.test import disable_admin_mfa +from vcr.unittest import VCRMixin +from zgw_consumers.constants import AuthTypes +from zgw_consumers.test.factories import ServiceFactory + +from objects.accounts.tests.factories import UserFactory +from objects.core.tests.factories import ObjectTypeFactory + + +@disable_admin_mfa() +class PermissionAdminTests(VCRMixin, TestCase): + + object_types_api = "http://127.0.0.1:8008/api/{version}/" + + def setUp(self): + super().setUp() + + self.user = UserFactory(superuser=True) + self.client.force_login(self.user) + self.url = reverse("admin:token_permission_add") + + def _get_vcr(self, **kwargs): + vcr = super()._get_vcr(**kwargs) + vcr.filter_headers = ["authorization"] + return vcr + + @tag("#449") + def test_with_object_types_api_v1(self): + """ + Regression test for #449. + Test if Permission admin can still handle objecttypes API V1 + """ + + v1_service = ServiceFactory( + api_root=self.object_types_api.format(version="v1"), + auth_type=AuthTypes.api_key, + header_key="Authorization", + header_value="Token 5cebbb33ffa725b6ed5e9e98300061218ba98d71", + ) + object_type = ObjectTypeFactory( + service=v1_service, uuid="71a2452a-66c3-4030-b5ec-a06035102e9e" + ) + + response = self.client.get(self.url) + + self.assertEqual(response.status_code, 200) + + form = response.context["adminform"].form + choices = list(form.fields["object_type"].choices) + + self.assertEqual( + choices[1][0].value, + object_type.id, + ) + self.assertEqual( + choices[1][1], + f"{v1_service.label}: {object_type._name}", + ) + + @tag("#449") + def test_with_object_types_api_v2(self): + """ + Regression test for #449. + Test if Permission admin can handle objecttypes API V2 which added pagination + """ + v2_service = ServiceFactory( + api_root=self.object_types_api.format(version="v2"), + auth_type=AuthTypes.api_key, + header_key="Authorization", + header_value="Token 5cebbb33ffa725b6ed5e9e98300061218ba98d71", + ) + object_type = ObjectTypeFactory( + service=v2_service, uuid="71a2452a-66c3-4030-b5ec-a06035102e9e" + ) + + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + + form = response.context["adminform"].form + choices = list(form.fields["object_type"].choices) + + self.assertEqual( + choices[1][0].value, + object_type.id, + ) + self.assertEqual( + choices[1][1], + f"{v2_service.label}: {object_type._name}", + )