From 39daf506ce7f3c923961cb70af015c429b3e6a20 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Thu, 12 Dec 2024 23:42:55 +0100 Subject: [PATCH 1/2] :boom: [#3283] Make objects/objecttypes FKs non-nullable in Objects API group Catalogi and Documents API are optional, but the objecttypes and objects API services are not. These fields were null because the model was originally a django-solo singleton model which must be able to be created without any services existing prior. A check script is added to prevent being stuck in half-migrated upgrades. --- Dockerfile | 1 + bin/check_api_groups_null.py | 56 +++++++++++++++++++ .../contrib/objects_api/clients/__init__.py | 18 +++--- ...apigroupconfig_objects_service_and_more.py | 37 ++++++++++++ src/openforms/contrib/objects_api/models.py | 5 +- .../contrib/objects_api/tests/test_admin.py | 3 +- .../contrib/objects_api/tests/test_config.py | 16 ------ .../contrib/objects_api/config.py | 10 ++-- .../objects_api/tests/test_api_endpoints.py | 33 ++--------- .../objects_api/tests/test_config_checks.py | 22 -------- .../objects_api/tests/test_serializer.py | 25 --------- .../contrib/zgw_apis/tests/test_migrations.py | 17 +++++- src/openforms/upgrades/upgrade_paths.py | 2 +- 13 files changed, 133 insertions(+), 112 deletions(-) create mode 100755 bin/check_api_groups_null.py create mode 100644 src/openforms/contrib/objects_api/migrations/0004_alter_objectsapigroupconfig_objects_service_and_more.py diff --git a/Dockerfile b/Dockerfile index 2d402cd02a..d7411f22b6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -93,6 +93,7 @@ COPY \ ./bin/check_celery_worker_liveness.py \ ./bin/report_component_problems.py \ ./bin/check_temporary_uploads.py \ + ./bin/check_api_groups_null.py \ ./bin/fix_selectboxes_component_default_values.py \ ./bin/ diff --git a/bin/check_api_groups_null.py b/bin/check_api_groups_null.py new file mode 100755 index 0000000000..36df0ad59c --- /dev/null +++ b/bin/check_api_groups_null.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +import sys +from pathlib import Path + +import django + +from tabulate import tabulate + +SRC_DIR = Path(__file__).parent.parent / "src" +sys.path.insert(0, str(SRC_DIR.resolve())) + + +def check_for_null_services_in_api_groups(): + from openforms.contrib.objects_api.models import ObjectsAPIGroupConfig + + problems: list[tuple[str, int, str, str]] = [] + + objects_groups = ObjectsAPIGroupConfig.objects.exclude( + objects_service__isnull=False, objecttypes_service__isnull=False + ).values_list("id", "name", "objects_service_id", "objecttypes_service_id") + + for pk, name, objects_service_id, objecttypes_service_id in objects_groups: + problem = ("Objects API", pk, name) + if objects_service_id is None: + problems.append((*problem, "No objects service configured")) + if objecttypes_service_id is None: + problems.append((*problem, "No object types service configured")) + + if not problems: + return False + + print( + "Can't upgrade yet - some API group services are not properly configured yet." + ) + print( + "Go into the admin to fix their configuration, and then try to upgrade again." + ) + tabulate( + problems, + headers=("API group type", "ID", "Name", "Problem"), + ) + return True + + +def main(skip_setup=False) -> bool: + from openforms.setup import setup_env + + if not skip_setup: + setup_env() + django.setup() + + return check_for_null_services_in_api_groups() + + +if __name__ == "__main__": + main() diff --git a/src/openforms/contrib/objects_api/clients/__init__.py b/src/openforms/contrib/objects_api/clients/__init__.py index 31b2442f3a..1d03008d48 100644 --- a/src/openforms/contrib/objects_api/clients/__init__.py +++ b/src/openforms/contrib/objects_api/clients/__init__.py @@ -9,6 +9,8 @@ in the form builder """ +from __future__ import annotations + from typing import TYPE_CHECKING from zgw_consumers.client import build_client @@ -26,25 +28,25 @@ class NoServiceConfigured(RuntimeError): pass -def get_objects_client(config: "ObjectsAPIGroupConfig") -> ObjectsClient: - if not (service := config.objects_service): - raise NoServiceConfigured("No Objects API service configured!") +def get_objects_client(config: ObjectsAPIGroupConfig) -> ObjectsClient: + service = config.objects_service + assert service is not None return build_client(service, client_factory=ObjectsClient) -def get_objecttypes_client(config: "ObjectsAPIGroupConfig") -> ObjecttypesClient: - if not (service := config.objecttypes_service): - raise NoServiceConfigured("No Objecttypes API service configured!") +def get_objecttypes_client(config: ObjectsAPIGroupConfig) -> ObjecttypesClient: + service = config.objecttypes_service + assert service is not None return build_client(service, client_factory=ObjecttypesClient) -def get_documents_client(config: "ObjectsAPIGroupConfig") -> DocumentenClient: +def get_documents_client(config: ObjectsAPIGroupConfig) -> DocumentenClient: if not (service := config.drc_service): raise NoServiceConfigured("No Documents API service configured!") return build_client(service, client_factory=DocumentenClient) -def get_catalogi_client(config: "ObjectsAPIGroupConfig") -> CatalogiClient: +def get_catalogi_client(config: ObjectsAPIGroupConfig) -> CatalogiClient: if not (service := config.catalogi_service): raise NoServiceConfigured("No Catalogi API service configured!") return build_client(service, client_factory=CatalogiClient) diff --git a/src/openforms/contrib/objects_api/migrations/0004_alter_objectsapigroupconfig_objects_service_and_more.py b/src/openforms/contrib/objects_api/migrations/0004_alter_objectsapigroupconfig_objects_service_and_more.py new file mode 100644 index 0000000000..0a14e60b65 --- /dev/null +++ b/src/openforms/contrib/objects_api/migrations/0004_alter_objectsapigroupconfig_objects_service_and_more.py @@ -0,0 +1,37 @@ +# Generated by Django 4.2.17 on 2024-12-12 22:40 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("zgw_consumers", "0022_set_default_service_slug"), + ("objects_api", "0003_objectsapigroupconfig_identifier_unique"), + ] + + operations = [ + migrations.AlterField( + model_name="objectsapigroupconfig", + name="objects_service", + field=models.ForeignKey( + limit_choices_to={"api_type": "orc"}, + on_delete=django.db.models.deletion.PROTECT, + related_name="+", + to="zgw_consumers.service", + verbose_name="Objects API", + ), + ), + migrations.AlterField( + model_name="objectsapigroupconfig", + name="objecttypes_service", + field=models.ForeignKey( + limit_choices_to={"api_type": "orc"}, + on_delete=django.db.models.deletion.PROTECT, + related_name="+", + to="zgw_consumers.service", + verbose_name="Objecttypes API", + ), + ), + ] diff --git a/src/openforms/contrib/objects_api/models.py b/src/openforms/contrib/objects_api/models.py index 3ccac00adb..3cb925129b 100644 --- a/src/openforms/contrib/objects_api/models.py +++ b/src/openforms/contrib/objects_api/models.py @@ -12,7 +12,6 @@ class ObjectsAPIGroupConfig(models.Model): - # TODO OF 3.0: remove `null=True` from the service fields name = models.CharField( _("name"), max_length=255, @@ -30,7 +29,7 @@ class ObjectsAPIGroupConfig(models.Model): verbose_name=_("Objects API"), on_delete=models.PROTECT, limit_choices_to={"api_type": APITypes.orc}, - null=True, + null=False, related_name="+", ) objecttypes_service = models.ForeignKey( @@ -38,7 +37,7 @@ class ObjectsAPIGroupConfig(models.Model): verbose_name=_("Objecttypes API"), on_delete=models.PROTECT, limit_choices_to={"api_type": APITypes.orc}, - null=True, + null=False, related_name="+", ) drc_service = models.ForeignKey( diff --git a/src/openforms/contrib/objects_api/tests/test_admin.py b/src/openforms/contrib/objects_api/tests/test_admin.py index 8ed1f1b0e8..cbbab806cc 100644 --- a/src/openforms/contrib/objects_api/tests/test_admin.py +++ b/src/openforms/contrib/objects_api/tests/test_admin.py @@ -9,7 +9,6 @@ from openforms.accounts.tests.factories import SuperUserFactory from openforms.utils.tests.vcr import OFVCRMixin -from ..models import ObjectsAPIGroupConfig from .factories import ObjectsAPIGroupConfigFactory TEST_FILES = Path(__file__).parent / "files" @@ -20,7 +19,7 @@ class ObjectsAPIGroupConfigAdminTest(OFVCRMixin, WebTest): VCR_TEST_FILES = TEST_FILES def test_name(self): - ObjectsAPIGroupConfig.objects.create(name="test group") + ObjectsAPIGroupConfigFactory.create(name="test group") user = SuperUserFactory.create() response = self.app.get( diff --git a/src/openforms/prefill/contrib/objects_api/tests/test_config.py b/src/openforms/prefill/contrib/objects_api/tests/test_config.py index 07708e0389..0fdea187d3 100644 --- a/src/openforms/prefill/contrib/objects_api/tests/test_config.py +++ b/src/openforms/prefill/contrib/objects_api/tests/test_config.py @@ -1,9 +1,6 @@ from pathlib import Path from unittest.mock import patch -from django.test import override_settings -from django.utils.translation import gettext as _ - from rest_framework.test import APITestCase from zgw_consumers.constants import APITypes, AuthTypes from zgw_consumers.test.factories import ServiceFactory @@ -41,19 +38,6 @@ def setUp(self): for_test_docker_compose=True ) - @override_settings(LANGUAGE_CODE="en") - def test_undefined_service_raises_exception(self): - self.objects_api_group.objects_service = None - self.objects_api_group.save() - - with self.assertRaisesMessage( - InvalidPluginConfiguration, - _( - "Objects API endpoint is not configured for Objects API group {objects_api_group}." - ).format(objects_api_group=self.objects_api_group), - ): - plugin.check_config() - def test_invalid_service_raises_exception(self): objects_service = ServiceFactory.create( api_root="http://localhost:8002/api/v2/invalid", diff --git a/src/openforms/registrations/contrib/objects_api/config.py b/src/openforms/registrations/contrib/objects_api/config.py index 9e40781008..f6fc91ffcf 100644 --- a/src/openforms/registrations/contrib/objects_api/config.py +++ b/src/openforms/registrations/contrib/objects_api/config.py @@ -1,6 +1,6 @@ import warnings -from django.db.models import IntegerChoices, Q +from django.db.models import IntegerChoices from django.utils.translation import gettext_lazy as _ from drf_spectacular.utils import OpenApiExample, extend_schema_serializer @@ -67,11 +67,9 @@ class ObjecttypeVariableMappingSerializer(serializers.Serializer): class ObjectsAPIOptionsSerializer(JsonSchemaSerializerMixin, serializers.Serializer): objects_api_group = PrimaryKeyRelatedAsChoicesField( - queryset=ObjectsAPIGroupConfig.objects.exclude( - Q(objects_service=None) - | Q(objecttypes_service=None) - | Q(drc_service=None) - | Q(catalogi_service=None) + queryset=ObjectsAPIGroupConfig.objects.filter( + drc_service__isnull=False, + catalogi_service__isnull=False, ), label=("Objects API group"), help_text=_("Which Objects API group to use."), diff --git a/src/openforms/registrations/contrib/objects_api/tests/test_api_endpoints.py b/src/openforms/registrations/contrib/objects_api/tests/test_api_endpoints.py index 141524a1b1..a24484981f 100644 --- a/src/openforms/registrations/contrib/objects_api/tests/test_api_endpoints.py +++ b/src/openforms/registrations/contrib/objects_api/tests/test_api_endpoints.py @@ -4,7 +4,6 @@ from rest_framework.reverse import reverse_lazy from rest_framework.test import APITestCase from zgw_consumers.constants import APITypes, AuthTypes -from zgw_consumers.models import Service from zgw_consumers.test.factories import ServiceFactory from openforms.accounts.tests.factories import StaffUserFactory, UserFactory @@ -12,26 +11,9 @@ from openforms.utils.tests.feature_flags import enable_feature_flag from openforms.utils.tests.vcr import OFVCRMixin -from ..models import ObjectsAPIGroupConfig - TEST_FILES = Path(__file__).parent / "files" -def get_test_config() -> ObjectsAPIGroupConfig: - """Returns a preconfigured ``ObjectsAPIGroupConfig`` instance matching the docker compose configuration.""" - - return ObjectsAPIGroupConfig( - objecttypes_service=Service( - api_root="http://localhost:8001/api/v2/", - api_type=APITypes.orc, - oas="https://example.com/", - header_key="Authorization", - header_value="Token 171be5abaf41e7856b423ad513df1ef8f867ff48", - auth_type=AuthTypes.api_key, - ) - ) - - class ObjecttypesAPIEndpointTests(OFVCRMixin, APITestCase): VCR_TEST_FILES = TEST_FILES @@ -40,9 +22,8 @@ class ObjecttypesAPIEndpointTests(OFVCRMixin, APITestCase): @classmethod def setUpTestData(cls) -> None: super().setUpTestData() - cls.config = get_test_config() - cls.config.objecttypes_service.save() - cls.config.save() + + cls.config = ObjectsAPIGroupConfigFactory.create(for_test_docker_compose=True) def test_auth_required(self): response = self.client.get(self.endpoint) @@ -101,9 +82,8 @@ class ObjecttypeVersionsAPIEndpointTests(OFVCRMixin, APITestCase): @classmethod def setUpTestData(cls) -> None: super().setUpTestData() - cls.config = get_test_config() - cls.config.objecttypes_service.save() - cls.config.save() + + cls.config = ObjectsAPIGroupConfigFactory.create(for_test_docker_compose=True) def test_auth_required(self): response = self.client.get(self.endpoint) @@ -156,9 +136,8 @@ class TargetPathsAPIEndpointTests(OFVCRMixin, APITestCase): @classmethod def setUpTestData(cls) -> None: super().setUpTestData() - cls.config = get_test_config() - cls.config.objecttypes_service.save() - cls.config.save() + + cls.config = ObjectsAPIGroupConfigFactory.create(for_test_docker_compose=True) def test_auth_required(self): response = self.client.post(self.endpoint) diff --git a/src/openforms/registrations/contrib/objects_api/tests/test_config_checks.py b/src/openforms/registrations/contrib/objects_api/tests/test_config_checks.py index 67322da045..013d1e7cd1 100644 --- a/src/openforms/registrations/contrib/objects_api/tests/test_config_checks.py +++ b/src/openforms/registrations/contrib/objects_api/tests/test_config_checks.py @@ -40,28 +40,6 @@ def _mockForValidServiceConfiguration(self, m: requests_mock.Mocker) -> None: headers={"API-version": "1.0.0"}, ) - def test_no_objects_service_configured(self): - self.config.objects_service = None - self.config.save() - plugin = ObjectsAPIRegistration(PLUGIN_IDENTIFIER) - - with self.assertRaises(InvalidPluginConfiguration): - plugin.check_config() - - @requests_mock.Mocker() - def test_no_objecttypes_service_configured(self, m: requests_mock.Mocker): - # Objects API needs to be set up as services are checked in a certain order - m.get( - "https://objects.example.com/api/v1/objects?pageSize=1", - json={"results": []}, - ) - self.config.objecttypes_service = None - self.config.save() - plugin = ObjectsAPIRegistration(PLUGIN_IDENTIFIER) - - with self.assertRaises(InvalidPluginConfiguration): - plugin.check_config() - @requests_mock.Mocker() def test_objects_service_misconfigured_connection_error(self, m): m.get( diff --git a/src/openforms/registrations/contrib/objects_api/tests/test_serializer.py b/src/openforms/registrations/contrib/objects_api/tests/test_serializer.py index 1d613f5e9b..9041c4666d 100644 --- a/src/openforms/registrations/contrib/objects_api/tests/test_serializer.py +++ b/src/openforms/registrations/contrib/objects_api/tests/test_serializer.py @@ -37,13 +37,6 @@ def setUpTestData(cls) -> None: for_test_docker_compose=True ) - # This group shouldn't be usable: - cls.invalid_objects_api_group = ObjectsAPIGroupConfigFactory.create( - objecttypes_service=None, - drc_service=None, - catalogi_service=None, - ) - def test_invalid_fields_v1(self): options = ObjectsAPIOptionsSerializer( data={ @@ -170,24 +163,6 @@ def test_unknown_objecttype_version(self): error = options.errors["objecttype_version"][0] self.assertEqual(error.code, "not-found") - def test_invalid_objects_api_group(self): - options = ObjectsAPIOptionsSerializer( - data={ - "objects_api_group": self.invalid_objects_api_group.pk, - "version": 2, - "objecttype": "8e46e0a5-b1b4-449b-b9e9-fa3cea655f48", - "objecttype_version": 1, - "informatieobjecttype_attachment": "http://localhost:8003/catalogi/api/v1/informatieobjecttypen/7a474713-0833-402a-8441-e467c08ac55b", - "informatieobjecttype_submission_report": "http://localhost:8003/catalogi/api/v1/informatieobjecttypen/b2d83b94-9b9b-4e80-a82f-73ff993c62f3", - "informatieobjecttype_submission_csv": "http://localhost:8003/catalogi/api/v1/informatieobjecttypen/531f6c1a-97f7-478c-85f0-67d2f23661c7", - }, - ) - - self.assertFalse(options.is_valid()) - self.assertIn("objects_api_group", options.errors) - error = options.errors["objects_api_group"][0] - self.assertEqual(error.code, "does_not_exist") - def test_auth_attribute_path_required_if_update_existing_object_is_true(self): options = ObjectsAPIOptionsSerializer( data={ diff --git a/src/openforms/registrations/contrib/zgw_apis/tests/test_migrations.py b/src/openforms/registrations/contrib/zgw_apis/tests/test_migrations.py index 9d94186cb7..d44b339e53 100644 --- a/src/openforms/registrations/contrib/zgw_apis/tests/test_migrations.py +++ b/src/openforms/registrations/contrib/zgw_apis/tests/test_migrations.py @@ -12,12 +12,25 @@ def setUpBeforeMigration(self, apps: StateApps): ObjectsAPIGroupConfig = apps.get_model("objects_api", "ObjectsAPIGroupConfig") Form = apps.get_model("forms", "Form") FormRegistrationBackend = apps.get_model("forms", "FormRegistrationBackend") + Service = apps.get_model("zgw_consumers", "Service") + + svc = Service.objects.create( + slug="dummy", api_type="orc", api_root="https://example.com" + ) form1 = Form.objects.create(name="form1") form2 = Form.objects.create(name="form2") self.objects_api_group = ObjectsAPIGroupConfig.objects.create( - identifier="group-1", name="Group 1" + identifier="group-1", + name="Group 1", + objects_service=svc, + objecttypes_service=svc, + ) + ObjectsAPIGroupConfig.objects.create( + identifier="group-2", + name="Group 2", + objects_service=svc, + objecttypes_service=svc, ) - ObjectsAPIGroupConfig.objects.create(identifier="group-2", name="Group 2") self.backend_without_api_group = FormRegistrationBackend.objects.create( form=form1, backend="zgw-create-zaak", options={} ) diff --git a/src/openforms/upgrades/upgrade_paths.py b/src/openforms/upgrades/upgrade_paths.py index 4d7d79c532..3f2f6f39b2 100644 --- a/src/openforms/upgrades/upgrade_paths.py +++ b/src/openforms/upgrades/upgrade_paths.py @@ -80,7 +80,7 @@ def run_checks(self) -> bool: valid_ranges={ VersionRange(minimum="2.8.0"), }, - scripts=["check_temporary_uploads"], + scripts=["check_temporary_uploads", "check_api_groups_null"], ), "2.8": UpgradeConstraint( valid_ranges={ From 3f27cb13015ed032eb3164105254cd1c6d6afebc Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Thu, 12 Dec 2024 23:50:41 +0100 Subject: [PATCH 2/2] :boom: [#3283] Make ZGW API group service FKs non-nullable Left-overs from a django-solo model too (see previous commit), these fields really cannot be empty to do anything useful. This properly sets up the required constraints at the database level and removes confusion in the application code. --- bin/check_api_groups_null.py | 32 +++++++++++-- .../registrations/contrib/zgw_apis/checks.py | 13 +---- .../registrations/contrib/zgw_apis/client.py | 16 +++---- ..._zgwapigroupconfig_drc_service_and_more.py | 48 +++++++++++++++++++ .../registrations/contrib/zgw_apis/models.py | 6 +-- .../contrib/zgw_apis/tests/test_models.py | 10 ---- .../zgw_apis/tests/test_zgw_api_config.py | 30 ------------ 7 files changed, 86 insertions(+), 69 deletions(-) create mode 100644 src/openforms/registrations/contrib/zgw_apis/migrations/0018_alter_zgwapigroupconfig_drc_service_and_more.py diff --git a/bin/check_api_groups_null.py b/bin/check_api_groups_null.py index 36df0ad59c..3b638e6f4c 100755 --- a/bin/check_api_groups_null.py +++ b/bin/check_api_groups_null.py @@ -12,11 +12,13 @@ def check_for_null_services_in_api_groups(): from openforms.contrib.objects_api.models import ObjectsAPIGroupConfig + from openforms.registrations.contrib.zgw_apis.models import ZGWApiGroupConfig problems: list[tuple[str, int, str, str]] = [] objects_groups = ObjectsAPIGroupConfig.objects.exclude( - objects_service__isnull=False, objecttypes_service__isnull=False + objects_service__isnull=False, + objecttypes_service__isnull=False, ).values_list("id", "name", "objects_service_id", "objecttypes_service_id") for pk, name, objects_service_id, objecttypes_service_id in objects_groups: @@ -26,6 +28,26 @@ def check_for_null_services_in_api_groups(): if objecttypes_service_id is None: problems.append((*problem, "No object types service configured")) + zgw_groups = ZGWApiGroupConfig.objects.exclude( + zrc_service__isnull=False, + drc_service__isnull=False, + ztc_service__isnull=False, + ).values_list( + "id", + "name", + "zrc_service_id", + "drc_service_id", + "ztc_service_id", + ) + for pk, name, zrc_service_id, drc_service_id, ztc_service_id in zgw_groups: + problem = ("ZGW APIs", pk, name) + if zrc_service_id is None: + problems.append((*problem, "No Zaken API service configured")) + if drc_service_id is None: + problems.append((*problem, "No Documenten API service configured")) + if ztc_service_id is None: + problems.append((*problem, "No Catalogi API service configured")) + if not problems: return False @@ -35,9 +57,11 @@ def check_for_null_services_in_api_groups(): print( "Go into the admin to fix their configuration, and then try to upgrade again." ) - tabulate( - problems, - headers=("API group type", "ID", "Name", "Problem"), + print( + tabulate( + problems, + headers=("API group type", "ID", "Name", "Problem"), + ) ) return True diff --git a/src/openforms/registrations/contrib/zgw_apis/checks.py b/src/openforms/registrations/contrib/zgw_apis/checks.py index ec6c9a048d..a34e30dc30 100644 --- a/src/openforms/registrations/contrib/zgw_apis/checks.py +++ b/src/openforms/registrations/contrib/zgw_apis/checks.py @@ -4,12 +4,7 @@ from openforms.plugins.exceptions import InvalidPluginConfiguration -from .client import ( - NoServiceConfigured, - get_catalogi_client, - get_documents_client, - get_zaken_client, -) +from .client import get_catalogi_client, get_documents_client, get_zaken_client from .models import ZGWApiGroupConfig @@ -43,12 +38,6 @@ def check_config(): try: check_function(config) - except NoServiceConfigured as exc: - raise InvalidPluginConfiguration( - _( - "{api_name} endpoint is not configured for ZGW API set {zgw_api_set}." - ).format(api_name=api_name, zgw_api_set=config.name) - ) from exc except requests.RequestException as exc: raise InvalidPluginConfiguration( _( diff --git a/src/openforms/registrations/contrib/zgw_apis/client.py b/src/openforms/registrations/contrib/zgw_apis/client.py index f486cfdaf8..644a5aca50 100644 --- a/src/openforms/registrations/contrib/zgw_apis/client.py +++ b/src/openforms/registrations/contrib/zgw_apis/client.py @@ -16,23 +16,19 @@ from .models import ZGWApiGroupConfig -class NoServiceConfigured(RuntimeError): - pass - - def get_zaken_client(config: ZGWApiGroupConfig) -> ZakenClient: - if not (service := config.zrc_service): - raise NoServiceConfigured("No Zaken API service configured!") + service = config.zrc_service + assert service is not None return build_client(service, client_factory=ZakenClient) def get_documents_client(config: ZGWApiGroupConfig) -> DocumentenClient: - if not (service := config.drc_service): - raise NoServiceConfigured("No Documents API service configured!") + service = config.drc_service + assert service is not None return build_client(service, client_factory=DocumentenClient) def get_catalogi_client(config: ZGWApiGroupConfig) -> CatalogiClient: - if not (service := config.ztc_service): - raise NoServiceConfigured("No Catalogi API service configured!") + service = config.ztc_service + assert service is not None return build_client(service, client_factory=CatalogiClient) diff --git a/src/openforms/registrations/contrib/zgw_apis/migrations/0018_alter_zgwapigroupconfig_drc_service_and_more.py b/src/openforms/registrations/contrib/zgw_apis/migrations/0018_alter_zgwapigroupconfig_drc_service_and_more.py new file mode 100644 index 0000000000..37768a9422 --- /dev/null +++ b/src/openforms/registrations/contrib/zgw_apis/migrations/0018_alter_zgwapigroupconfig_drc_service_and_more.py @@ -0,0 +1,48 @@ +# Generated by Django 4.2.17 on 2024-12-12 22:49 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("zgw_consumers", "0022_set_default_service_slug"), + ("zgw_apis", "0017_alter_zgwapigroupconfig_identifier"), + ] + + operations = [ + migrations.AlterField( + model_name="zgwapigroupconfig", + name="drc_service", + field=models.ForeignKey( + limit_choices_to={"api_type": "drc"}, + on_delete=django.db.models.deletion.PROTECT, + related_name="zgwset_drc_config", + to="zgw_consumers.service", + verbose_name="Documenten API", + ), + ), + migrations.AlterField( + model_name="zgwapigroupconfig", + name="zrc_service", + field=models.ForeignKey( + limit_choices_to={"api_type": "zrc"}, + on_delete=django.db.models.deletion.PROTECT, + related_name="zgwset_zrc_config", + to="zgw_consumers.service", + verbose_name="Zaken API", + ), + ), + migrations.AlterField( + model_name="zgwapigroupconfig", + name="ztc_service", + field=models.ForeignKey( + limit_choices_to={"api_type": "ztc"}, + on_delete=django.db.models.deletion.PROTECT, + related_name="zgwset_ztc_config", + to="zgw_consumers.service", + verbose_name="Catalogi API", + ), + ), + ] diff --git a/src/openforms/registrations/contrib/zgw_apis/models.py b/src/openforms/registrations/contrib/zgw_apis/models.py index c911a4978e..aa9f6f8f6d 100644 --- a/src/openforms/registrations/contrib/zgw_apis/models.py +++ b/src/openforms/registrations/contrib/zgw_apis/models.py @@ -67,7 +67,7 @@ class ZGWApiGroupConfig(models.Model): on_delete=models.PROTECT, limit_choices_to={"api_type": APITypes.zrc}, related_name="zgwset_zrc_config", - null=True, + null=False, ) drc_service = models.ForeignKey( "zgw_consumers.Service", @@ -75,7 +75,7 @@ class ZGWApiGroupConfig(models.Model): on_delete=models.PROTECT, limit_choices_to={"api_type": APITypes.drc}, related_name="zgwset_drc_config", - null=True, + null=False, ) ztc_service = models.ForeignKey( "zgw_consumers.Service", @@ -83,7 +83,7 @@ class ZGWApiGroupConfig(models.Model): on_delete=models.PROTECT, limit_choices_to={"api_type": APITypes.ztc}, related_name="zgwset_ztc_config", - null=True, + null=False, ) # diff --git a/src/openforms/registrations/contrib/zgw_apis/tests/test_models.py b/src/openforms/registrations/contrib/zgw_apis/tests/test_models.py index 28287f6154..6a87d688fe 100644 --- a/src/openforms/registrations/contrib/zgw_apis/tests/test_models.py +++ b/src/openforms/registrations/contrib/zgw_apis/tests/test_models.py @@ -69,16 +69,6 @@ def test_validate_no_catalogue_specified(self): except ValidationError as exc: raise self.failureException("Not specifying a catalogue is valid.") from exc - def test_catalogue_specified_but_ztc_service_is_missing(self): - config = ZGWApiGroupConfigFactory.create( - ztc_service=None, catalogue_domain="TEST", catalogue_rsin="000000000" - ) - - with self.assertRaises(ValidationError) as exc_context: - config.full_clean() - - self.assertIn("ztc_service", exc_context.exception.error_dict) - def test_validate_catalogue_exists(self): # validates against the fixtures in docker/open-zaak config = ZGWApiGroupConfigFactory.create( diff --git a/src/openforms/registrations/contrib/zgw_apis/tests/test_zgw_api_config.py b/src/openforms/registrations/contrib/zgw_apis/tests/test_zgw_api_config.py index f5826f26ae..d8e7774545 100644 --- a/src/openforms/registrations/contrib/zgw_apis/tests/test_zgw_api_config.py +++ b/src/openforms/registrations/contrib/zgw_apis/tests/test_zgw_api_config.py @@ -536,36 +536,6 @@ def test_check_config(self, m): self.assertEqual(list_documenten_2.hostname, "documenten-2.nl") self.assertEqual(list_zaaktypen_2.hostname, "catalogi-2.nl") - def test_check_config_no_zrc_service(self, m): - self.install_mocks(m) - self.zgw_group1.zrc_service = None - self.zgw_group1.save() - - plugin = ZGWRegistration("zgw") - - with self.assertRaises(InvalidPluginConfiguration): - plugin.check_config() - - def test_check_config_no_drc_service(self, m): - self.install_mocks(m) - self.zgw_group1.drc_service = None - self.zgw_group1.save() - - plugin = ZGWRegistration("zgw") - - with self.assertRaises(InvalidPluginConfiguration): - plugin.check_config() - - def test_check_config_no_ztc_service(self, m): - self.install_mocks(m) - self.zgw_group1.ztc_service = None - self.zgw_group1.save() - - plugin = ZGWRegistration("zgw") - - with self.assertRaises(InvalidPluginConfiguration): - plugin.check_config() - def test_check_config_http_error(self, m): self.install_mocks(m) m.get("https://zaken-1.nl/api/v1/zaken", exc=HTTPError)