diff --git a/src/eherkenning/tests/test_mock_views.py b/src/eherkenning/tests/test_mock_views.py index 00778fc6dc..08bdcbf8d0 100644 --- a/src/eherkenning/tests/test_mock_views.py +++ b/src/eherkenning/tests/test_mock_views.py @@ -1,12 +1,13 @@ from unittest.mock import patch from urllib.parse import urlencode -from django.contrib.auth import get_user_model +from django.contrib.auth import get_user_model, signals from django.test import TestCase, modify_settings, override_settings from django.urls import reverse from furl import furl +from open_inwoner.accounts.signals import update_user_from_klant_on_login from open_inwoner.kvk.branches import get_kvk_branch_number RETURN_URL = "/" @@ -88,6 +89,10 @@ def test_get_returns_valid_response(self): @override_settings(**OVERRIDE_SETTINGS) @modify_settings(**MODIFY_SETTINGS) class PasswordLoginViewTests(eHerkenningMockTestCase): + @classmethod + def setUpTestData(cls): + signals.user_logged_in.disconnect(update_user_from_klant_on_login) + def test_get_returns_http400_on_missing_params(self): url = reverse("eherkenning-mock:password") response = self.client.get(url) diff --git a/src/open_inwoner/accounts/signals.py b/src/open_inwoner/accounts/signals.py index ad82f577a9..19579fb100 100644 --- a/src/open_inwoner/accounts/signals.py +++ b/src/open_inwoner/accounts/signals.py @@ -1,7 +1,6 @@ import logging from django.contrib.auth.signals import user_logged_in, user_logged_out -from django.core.exceptions import ImproperlyConfigured from django.dispatch import receiver from django.urls import reverse from django.utils.translation import gettext as _ @@ -39,17 +38,15 @@ def update_user_from_klant_on_login(sender, user, request, *args, **kwargs): # OpenKlant2 try: service = OpenKlant2Service() - except ImproperlyConfigured: - logger.error("OpenKlant2 configuration missing") + except Exception: + logger.error("OpenKlant2 service failed to build") else: _update_user_from_openklant2(user=user, service=service, request=request) # eSuite try: service = eSuiteKlantenService() - except ImproperlyConfigured: - logger.error("eSuiteKlantenService missing configuration") - except RuntimeError: + except Exception: logger.error("eSuiteKlantenService failed to build") else: _update_user_from_esuite(user=user, service=service, request=request) diff --git a/src/open_inwoner/accounts/tests/test_auth.py b/src/open_inwoner/accounts/tests/test_auth.py index 5d4926b97c..dac8a0149c 100644 --- a/src/open_inwoner/accounts/tests/test_auth.py +++ b/src/open_inwoner/accounts/tests/test_auth.py @@ -12,6 +12,8 @@ from django_webtest import WebTest from furl import furl from pyquery import PyQuery as PQ +from zgw_consumers.constants import APITypes +from zgw_consumers.models import Service from open_inwoner.accounts.choices import NotificationChannelChoice from open_inwoner.accounts.signals import update_user_from_klant_on_login @@ -19,6 +21,7 @@ from open_inwoner.haalcentraal.tests.mixins import HaalCentraalMixin from open_inwoner.kvk.branches import get_kvk_branch_number from open_inwoner.kvk.tests.factories import CertificateFactory +from open_inwoner.openklant.models import OpenKlant2Config from open_inwoner.openklant.tests.data import MockAPIReadPatchData from open_inwoner.openzaak.models import OpenZaakConfig from open_inwoner.utils.tests.helpers import AssertTimelineLogMixin @@ -55,6 +58,26 @@ class DigiDRegistrationTest( def setUpTestData(cls): cls.homepage = cms_tools.create_homepage() + user_logged_in.disconnect(update_user_from_klant_on_login) + + zgw_service, _ = Service.objects.update_or_create( + api_root="http://localhost:8338/klantinteracties/api/v1", + defaults={ + "label": "Klanten API service", + "slug": "klanten-api-service", + "api_type": APITypes.kc, + "secret": "", + }, + ) + cls.openklant2_config = OpenKlant2Config.objects.create( + zgw_service=zgw_service, + mijn_vragen_kanaal="oip_mijn_vragen", + mijn_vragen_organisatie_naam="Open Inwoner Platform", + mijn_vragen_actor="ca0783a1-1d74-4e07-b3e0-185b1d2fccd4", + interne_taak_gevraagde_handeling="Beantwoorden vraag Mijn Omgeving", + interne_taak_toelichting="Beantwoorden vraag", + ) + @patch("open_inwoner.accounts.models.OpenIDDigiDConfig.get_solo") def test_registration_page_only_digid(self, mock_solo): for oidc_enabled in [True, False]: @@ -519,6 +542,26 @@ class eHerkenningRegistrationTest(AssertRedirectsMixin, WebTest): def setUpTestData(cls): cms_tools.create_homepage() + user_logged_in.disconnect(update_user_from_klant_on_login) + + zgw_service, _ = Service.objects.update_or_create( + api_root="http://localhost:8338/klantinteracties/api/v1", + defaults={ + "label": "Klanten API service", + "slug": "klanten-api-service", + "api_type": APITypes.kc, + "secret": "", + }, + ) + cls.openklant2_config = OpenKlant2Config.objects.create( + zgw_service=zgw_service, + mijn_vragen_kanaal="oip_mijn_vragen", + mijn_vragen_organisatie_naam="Open Inwoner Platform", + mijn_vragen_actor="ca0783a1-1d74-4e07-b3e0-185b1d2fccd4", + interne_taak_gevraagde_handeling="Beantwoorden vraag Mijn Omgeving", + interne_taak_toelichting="Beantwoorden vraag", + ) + @patch("open_inwoner.accounts.models.OpenIDEHerkenningConfig.get_solo") @patch("open_inwoner.configurations.models.SiteConfiguration.get_solo") def test_registration_page_eherkenning(self, mock_solo, mock_eherkenning_config): @@ -1104,6 +1147,27 @@ def setUpTestData(cls): cls.msg_dupes = _("This email is already taken.") cls.msg_inactive = _("This account has been deactivated") + def setUp(self): + user_logged_in.disconnect(update_user_from_klant_on_login) + + zgw_service, _ = Service.objects.update_or_create( + api_root="http://localhost:8338/klantinteracties/api/v1", + defaults={ + "label": "Klanten API service", + "slug": "klanten-api-service", + "api_type": APITypes.kc, + "secret": "", + }, + ) + self.openklant2_config = OpenKlant2Config.objects.create( + zgw_service=zgw_service, + mijn_vragen_kanaal="oip_mijn_vragen", + mijn_vragen_organisatie_naam="Open Inwoner Platform", + mijn_vragen_actor="ca0783a1-1d74-4e07-b3e0-185b1d2fccd4", + interne_taak_gevraagde_handeling="Beantwoorden vraag Mijn Omgeving", + interne_taak_toelichting="Beantwoorden vraag", + ) + def test_digid_user_success(self): """Assert that digid users can register with duplicate emails""" test_user = DigidUserFactory.create( @@ -1457,6 +1521,27 @@ def setUpTestData(cls): cms_tools.create_homepage() cms_tools.create_apphook_page(ProfileApphook) + def setUp(self): + user_logged_in.disconnect(update_user_from_klant_on_login) + + zgw_service, _ = Service.objects.update_or_create( + api_root="http://localhost:8338/klantinteracties/api/v1", + defaults={ + "label": "Klanten API service", + "slug": "klanten-api-service", + "api_type": APITypes.kc, + "secret": "", + }, + ) + self.openklant2_config = OpenKlant2Config.objects.create( + zgw_service=zgw_service, + mijn_vragen_kanaal="oip_mijn_vragen", + mijn_vragen_organisatie_naam="Open Inwoner Platform", + mijn_vragen_actor="ca0783a1-1d74-4e07-b3e0-185b1d2fccd4", + interne_taak_gevraagde_handeling="Beantwoorden vraag Mijn Omgeving", + interne_taak_toelichting="Beantwoorden vraag", + ) + def test_page_show_config_text(self): config = SiteConfiguration.get_solo() config.registration_text = "Hello registration text http://foo.bar/" @@ -1904,11 +1989,31 @@ def setUpTestData(cls): config.enable_notification_channel_choice = True config.save() + zgw_service, _ = Service.objects.update_or_create( + api_root="http://localhost:8338/klantinteracties/api/v1", + defaults={ + "label": "Klanten API service", + "slug": "klanten-api-service", + "api_type": APITypes.kc, + "secret": "", + }, + ) + cls.openklant2_config = OpenKlant2Config.objects.create( + zgw_service=zgw_service, + mijn_vragen_kanaal="oip_mijn_vragen", + mijn_vragen_organisatie_naam="Open Inwoner Platform", + mijn_vragen_actor="ca0783a1-1d74-4e07-b3e0-185b1d2fccd4", + interne_taak_gevraagde_handeling="Beantwoorden vraag Mijn Omgeving", + interne_taak_toelichting="Beantwoorden vraag", + ) + def test_update_hook_is_registered_on_login(self, m): + user_logged_in.connect(update_user_from_klant_on_login) connected_functions = [receiver[1]() for receiver in user_logged_in.receivers] self.assertIn(update_user_from_klant_on_login, connected_functions) def test_update_user_from_klant_hook_only_called_for_digid_and_eherkenning(self, m): + user_logged_in.disconnect(update_user_from_klant_on_login) self.data = MockAPIReadPatchData().install_mocks(m) request = RequestFactory().get("/foo") request.user = self.data.user @@ -1922,15 +2027,22 @@ def test_update_user_from_klant_hook_only_called_for_digid_and_eherkenning(self, with patch( "open_inwoner.openklant.services.eSuiteKlantenService.update_user_from_klant" ) as update_user_from_klant_mock: - update_user_from_klant_on_login( - self.__class__, - request.user, - request, - ) - if login_type in [ - LoginTypeChoices.digid, - LoginTypeChoices.eherkenning, - ]: - update_user_from_klant_mock.assert_called_once() - else: - update_user_from_klant_mock.assert_not_called() + with patch( + "open_inwoner.openklant.services.OpenKlant2Service.get_or_create_partij_for_user" + ) as openklant2_mock: + openklant2_mock.return_value = None, False + + update_user_from_klant_on_login( + self.__class__, + request.user, + request, + ) + if login_type in [ + LoginTypeChoices.digid, + LoginTypeChoices.eherkenning, + ]: + update_user_from_klant_mock.assert_called_once() + openklant2_mock.assert_called_once() + else: + update_user_from_klant_mock.assert_not_called() + openklant2_mock.assert_not_called() diff --git a/src/open_inwoner/accounts/tests/test_oidc_views.py b/src/open_inwoner/accounts/tests/test_oidc_views.py index ba4adfae22..cb10588659 100644 --- a/src/open_inwoner/accounts/tests/test_oidc_views.py +++ b/src/open_inwoner/accounts/tests/test_oidc_views.py @@ -4,7 +4,7 @@ from urllib.parse import urlencode from django.conf import settings -from django.contrib.auth import get_user_model +from django.contrib.auth import get_user_model, signals from django.core.exceptions import ValidationError from django.test import TestCase, modify_settings, override_settings from django.urls import reverse @@ -17,6 +17,7 @@ from mozilla_django_oidc_db.models import OpenIDConnectConfig from pyquery import PyQuery as PQ +from open_inwoner.accounts.signals import update_user_from_klant_on_login from open_inwoner.accounts.views.auth_oidc import ( GENERIC_DIGID_ERROR_MSG, GENERIC_EHERKENNING_ERROR_MSG, @@ -85,6 +86,7 @@ class OIDCFlowTests(TestCase): @classmethod def setUpClass(cls): super().setUpClass() + signals.user_logged_in.disconnect(update_user_from_klant_on_login) cms_tools.create_homepage() cms_tools.create_apphook_page(ProfileApphook) @@ -501,6 +503,7 @@ class DigiDOIDCFlowTests(WebTest): @classmethod def setUpClass(cls): super().setUpClass() + signals.user_logged_in.disconnect(update_user_from_klant_on_login) cms_tools.create_homepage() cms_tools.create_apphook_page(ProfileApphook) @@ -1058,6 +1061,7 @@ class eHerkenningOIDCFlowTests(WebTest): @classmethod def setUpClass(cls): super().setUpClass() + signals.user_logged_in.disconnect(update_user_from_klant_on_login) cms_tools.create_homepage() cms_tools.create_apphook_page(ProfileApphook) diff --git a/src/open_inwoner/accounts/tests/test_profile_views.py b/src/open_inwoner/accounts/tests/test_profile_views.py index a82f85ed87..0618277c7a 100644 --- a/src/open_inwoner/accounts/tests/test_profile_views.py +++ b/src/open_inwoner/accounts/tests/test_profile_views.py @@ -62,6 +62,8 @@ ) class ProfileViewTests(WebTest): def setUp(self): + signals.user_logged_in.disconnect(update_user_from_klant_on_login) + self.url = reverse("profile:detail") self.return_url = reverse("logout") self.user = UserFactory( @@ -750,6 +752,8 @@ class ProfileDeleteTest(WebTest): @classmethod def setUpTestData(cls): + signals.user_logged_in.disconnect(update_user_from_klant_on_login) + cls.url = reverse("profile:detail") def test_delete_regular_user_success(self): @@ -986,6 +990,10 @@ def test_preselected_values(self): @override_settings(ROOT_URLCONF="open_inwoner.cms.tests.urls") @patch("open_inwoner.cms.utils.page_display._is_published", return_value=True) class EditNotificationsTests(AssertTimelineLogMixin, WebTest): + @classmethod + def setUpTestData(cls): + signals.user_logged_in.disconnect(update_user_from_klant_on_login) + def setUp(self): self.config = SiteConfiguration.get_solo() self.config.notifications_messages_enabled = True @@ -1103,6 +1111,8 @@ class NotificationsDisplayTests(WebTest): @classmethod def setUpTestData(cls): + signals.user_logged_in.disconnect(update_user_from_klant_on_login) + cls.url = reverse("profile:notifications") cls.user = UserFactory() @@ -1188,6 +1198,8 @@ class NewsletterSubscriptionTests(ClearCachesMixin, WebTest): def setUp(self): super().setUp() + signals.user_logged_in.disconnect(update_user_from_klant_on_login) + self.profile_app = ProfileConfig.objects.create( namespace=ProfileApphook.app_name, newsletters=True ) @@ -1426,6 +1438,8 @@ class UserAppointmentsTests(ClearCachesMixin, WebTest): def setUp(self): super().setUp() + signals.user_logged_in.disconnect(update_user_from_klant_on_login) + self.data = QmaticMockData() self.assertTrue(self.data.user.has_verified_email()) diff --git a/src/open_inwoner/accounts/views/signals.py b/src/open_inwoner/accounts/views/signals.py index 0381d09d8b..0c605f0d01 100644 --- a/src/open_inwoner/accounts/views/signals.py +++ b/src/open_inwoner/accounts/views/signals.py @@ -1,6 +1,5 @@ import logging -from django.conf import settings from django.db.models.signals import post_save from django.dispatch import receiver @@ -23,12 +22,10 @@ def get_or_create_klant_for_new_user( user = instance # OpenKlant2 - # TODO: replace with proper config and refactor branching - use_ok2 = getattr(settings, "OPENKLANT2_CONFIG", None) - if use_ok2 and (openklant2_config := OpenKlant2Config.from_django_settings()): + if openklant2_config := OpenKlant2Config.get_solo(): try: service = OpenKlant2Service(config=openklant2_config) - except RuntimeError: + except Exception: logger.error("OpenKlant2 service failed to build") return @@ -53,7 +50,7 @@ def get_or_create_klant_for_new_user( # eSuite try: service = eSuiteKlantenService() - except RuntimeError: + except Exception: logger.error("eSuiteKlantenService failed to build") return diff --git a/src/open_inwoner/cms/cases/tests/test_contactform.py b/src/open_inwoner/cms/cases/tests/test_contactform.py index ef045769a5..cb0f5441b6 100644 --- a/src/open_inwoner/cms/cases/tests/test_contactform.py +++ b/src/open_inwoner/cms/cases/tests/test_contactform.py @@ -1,6 +1,7 @@ from unittest.mock import ANY, patch from django.conf import settings +from django.contrib.auth import signals from django.core import mail from django.test import override_settings from django.urls import reverse @@ -14,13 +15,15 @@ VertrouwelijkheidsAanduidingen, ) from zgw_consumers.constants import APITypes +from zgw_consumers.models import Service +from open_inwoner.accounts.signals import update_user_from_klant_on_login from open_inwoner.accounts.tests.factories import ( DigidUserFactory, eHerkenningUserFactory, ) from open_inwoner.openklant.constants import Status -from open_inwoner.openklant.models import OpenKlantConfig +from open_inwoner.openklant.models import OpenKlant2Config, OpenKlantConfig from open_inwoner.openklant.services import eSuiteVragenService from open_inwoner.openklant.tests.data import CONTACTMOMENTEN_ROOT, KLANTEN_ROOT from open_inwoner.openzaak.models import CatalogusConfig, OpenZaakConfig @@ -62,7 +65,27 @@ class CasesContactFormTestCase(AssertMockMatchersMixin, ClearCachesMixin, WebTes def setUp(self): super().setUp() - self.user = DigidUserFactory(bsn="900222086") + signals.user_logged_in.disconnect(update_user_from_klant_on_login) + + zgw_service, _ = Service.objects.update_or_create( + api_root="http://localhost:8338/klantinteracties/api/v1", + defaults={ + "label": "Klanten API service", + "slug": "klanten-api-service", + "api_type": APITypes.kc, + "secret": "", + }, + ) + self.openklant2_config = OpenKlant2Config.objects.get_or_create( + zgw_service=zgw_service, + mijn_vragen_kanaal="oip_mijn_vragen", + mijn_vragen_organisatie_naam="Open Inwoner Platform", + mijn_vragen_actor="ca0783a1-1d74-4e07-b3e0-185b1d2fccd4", + interne_taak_gevraagde_handeling="Beantwoorden vraag Mijn Omgeving", + interne_taak_toelichting="Beantwoorden vraag", + ) + + self.user = DigidUserFactory(bsn="900222086", email="foo@example.com") # services self.api_group = ZGWApiGroupConfigFactory( diff --git a/src/open_inwoner/cms/cases/views/status.py b/src/open_inwoner/cms/cases/views/status.py index 40963c6034..62748ae345 100644 --- a/src/open_inwoner/cms/cases/views/status.py +++ b/src/open_inwoner/cms/cases/views/status.py @@ -7,11 +7,7 @@ from django.conf import settings from django.contrib import messages -from django.core.exceptions import ( - ImproperlyConfigured, - ObjectDoesNotExist, - PermissionDenied, -) +from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.http import ( Http404, HttpRequest, @@ -130,14 +126,12 @@ def get_service(self, service_type: KlantenServiceType) -> VragenService | None: if service_type == KlantenServiceType.OPENKLANT2: try: return OpenKlant2Service() - except ImproperlyConfigured: - logger.error("OpenKlant2 configuration missing") + except Exception: + logger.error("Failed to build OpenKlant2 service") if service_type == KlantenServiceType.ESUITE: try: return eSuiteVragenService() - except ImproperlyConfigured: - logger.error("eSuiteVragenService configuration missing") - except RuntimeError: + except Exception: logger.error("Failed to build eSuiteVragenService") def store_statustype_mapping(self, zaaktype_identificatie): diff --git a/src/open_inwoner/openklant/migrations/0015_openklant2config.py b/src/open_inwoner/openklant/migrations/0015_openklant2config.py new file mode 100644 index 0000000000..5c30ef6927 --- /dev/null +++ b/src/open_inwoner/openklant/migrations/0015_openklant2config.py @@ -0,0 +1,78 @@ +# Generated by Django 4.2.16 on 2024-12-18 10:58 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("zgw_consumers", "0022_set_default_service_slug"), + ("openklant", "0014_contactformconfig"), + ] + + operations = [ + migrations.CreateModel( + name="OpenKlant2Config", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "mijn_vragen_kanaal", + models.CharField( + blank=True, default="", verbose_name="Mijn vragen kanaal" + ), + ), + ( + "mijn_vragen_organisatie_naam", + models.CharField( + blank=True, + default="", + verbose_name="Mijn vragen organisatie naam", + ), + ), + ( + "mijn_vragen_actor", + models.CharField( + blank=True, default="", verbose_name="Mijn vragen actor" + ), + ), + ( + "interne_taak_gevraagde_handeling", + models.CharField( + blank=True, + default="", + verbose_name="Interne taak gevraagde handeling", + ), + ), + ( + "interne_taak_toelichting", + models.CharField( + blank=True, default="", verbose_name="Interne taak toelichting" + ), + ), + ( + "zgw_service", + models.OneToOneField( + blank=True, + limit_choices_to={"api_type": "kc"}, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="+", + to="zgw_consumers.service", + verbose_name="Klanten API", + ), + ), + ], + options={ + "verbose_name": "Open Klant configuration", + }, + ), + ] diff --git a/src/open_inwoner/openklant/models.py b/src/open_inwoner/openklant/models.py index c1d0029910..46a94bfd41 100644 --- a/src/open_inwoner/openklant/models.py +++ b/src/open_inwoner/openklant/models.py @@ -1,9 +1,3 @@ -import uuid -from dataclasses import dataclass -from typing import Self -from urllib.parse import urljoin, urlparse, urlunparse - -from django.core.exceptions import ImproperlyConfigured from django.db import models from django.utils.translation import gettext_lazy as _ @@ -138,6 +132,54 @@ def has_api_configuration(self): return all(getattr(self, f, "") for f in self.register_api_required_fields) +class OpenKlant2ConfigManager(models.Manager): + def get_queryset(self): + qs = super().get_queryset() + return qs.select_related("service_config") + + +class OpenKlant2Config(SingletonModel): + zgw_service = models.OneToOneField( + "zgw_consumers.Service", + verbose_name=_("Klanten API"), + on_delete=models.PROTECT, + limit_choices_to={"api_type": APITypes.kc}, + related_name="+", + null=True, + blank=True, + ) + + # Vragen + mijn_vragen_kanaal = models.CharField( + verbose_name=_("Mijn vragen kanaal"), + default="", + blank=True, + ) + mijn_vragen_organisatie_naam = models.CharField( + verbose_name=_("Mijn vragen organisatie naam"), + default="", + blank=True, + ) + mijn_vragen_actor = models.CharField( + verbose_name=_("Mijn vragen actor"), + default="", + blank=True, + ) + interne_taak_gevraagde_handeling = models.CharField( + verbose_name=_("Interne taak gevraagde handeling"), + default="", + blank=True, + ) + interne_taak_toelichting = models.CharField( + verbose_name=_("Interne taak toelichting"), + default="", + blank=True, + ) + + class Meta: + verbose_name = _("Open Klant configuration") + + class ContactFormSubject(OrderedModel): subject = models.CharField( verbose_name=_("Onderwerp"), @@ -190,37 +232,3 @@ class Meta: verbose_name = _("KlantContactMoment") verbose_name_plural = _("KlantContactMomenten") unique_together = [["user", "contactmoment_url"]] - - -@dataclass -class OpenKlant2Config: - api_root: str - api_path: str - api_token: str - - # Question/Answer settings - mijn_vragen_kanaal: str - mijn_vragen_organisatie_naam: str - mijn_vragen_actor: str | uuid.UUID | None - interne_taak_gevraagde_handeling: str - interne_taak_toelichting: str - - @property - def api_url(self): - joined = urljoin(self.api_root, self.api_path) - scheme, netloc, path, params, query, fragment = urlparse(joined) - path = path.replace("//", "/") - return urlunparse((scheme, netloc, path, params, query, fragment)) - - @classmethod - def from_django_settings(cls) -> Self: - from django.conf import settings - - if not (config := getattr(settings, "OPENKLANT2_CONFIG", None)): - raise ImproperlyConfigured( - "Please set OPENKLANT2_CONFIG in your settings to configure OpenKlant2" - ) - - return cls(**config) - - # TODO: add from_openklant_config_model or similar diff --git a/src/open_inwoner/openklant/services.py b/src/open_inwoner/openklant/services.py index d2dae1caa8..2ece5e03e9 100644 --- a/src/open_inwoner/openklant/services.py +++ b/src/open_inwoner/openklant/services.py @@ -823,16 +823,16 @@ class OpenKlant2Service(KlantenService): client: OpenKlant2Client def __init__(self, config: OpenKlant2Config | None = None): - self.config = config or OpenKlant2Config.from_django_settings() + self.config = config or OpenKlant2Config.get_solo() if not self.config: raise ImproperlyConfigured( "Please set OPENKLANT2_CONFIG in your settings to configure OpenKlant2" ) self.client = OpenKlant2Client( - base_url=self.config.api_url, + base_url=self.config.zgw_service.api_root, request_kwargs={ - "headers": {"Authorization": f"Token {self.config.api_token}"} + "headers": {"Authorization": f"Token {self.config.zgw_service.secret}"} }, ) diff --git a/src/open_inwoner/openklant/tests/test_openklant2_service.py b/src/open_inwoner/openklant/tests/test_openklant2_service.py index f9b8177a1e..80974759a1 100644 --- a/src/open_inwoner/openklant/tests/test_openklant2_service.py +++ b/src/open_inwoner/openklant/tests/test_openklant2_service.py @@ -3,6 +3,8 @@ from django.test import tag import freezegun +from zgw_consumers.constants import APITypes +from zgw_consumers.models import Service from open_inwoner.accounts.models import User from open_inwoner.accounts.tests.factories import UserFactory @@ -17,10 +19,18 @@ class PartijGetOrCreateTestCase(Openklant2ServiceTestCase): def setUp(self): super().setUp() + + zgw_service, _ = Service.objects.update_or_create( + api_root="http://localhost:8338/klantinteracties/api/v1", + defaults={ + "label": "Klanten API service", + "slug": "klanten-api-service", + "api_type": APITypes.kc, + "secret": "", + }, + ) self.openklant2_config = OpenKlant2Config( - api_root=self.openklant2_api_root, - api_path=self.openklant2_api_path, - api_token=self.openklant2_api_token, + zgw_service=zgw_service, mijn_vragen_kanaal="oip_mijn_vragen", mijn_vragen_organisatie_naam="Open Inwoner Platform", mijn_vragen_actor="ca0783a1-1d74-4e07-b3e0-185b1d2fccd4", @@ -220,10 +230,18 @@ def test_get_or_create_organisatie_with_vestiging(self): class Openklant2ServiceTest(Openklant2ServiceTestCase): def setUp(self): super().setUp() + + zgw_service, _ = Service.objects.update_or_create( + api_root="http://localhost:8338/klantinteracties/api/v1", + defaults={ + "label": "Klanten API service", + "slug": "klanten-api-service", + "api_type": APITypes.kc, + "secret": "", + }, + ) self.openklant2_config = OpenKlant2Config( - api_root=self.openklant2_api_root, - api_path=self.openklant2_api_path, - api_token=self.openklant2_api_token, + zgw_service=zgw_service, mijn_vragen_kanaal="oip_mijn_vragen", mijn_vragen_organisatie_naam="Open Inwoner Platform", mijn_vragen_actor="ca0783a1-1d74-4e07-b3e0-185b1d2fccd4", @@ -360,10 +378,17 @@ def setUp(self): } ) + zgw_service, _ = Service.objects.update_or_create( + api_root="http://localhost:8338/klantinteracties/api/v1", + defaults={ + "label": "Klanten API service", + "slug": "klanten-api-service", + "api_type": APITypes.kc, + "secret": "", + }, + ) self.openklant2_config = OpenKlant2Config( - api_root=self.openklant2_api_root, - api_path=self.openklant2_api_path, - api_token=self.openklant2_api_token, + zgw_service=zgw_service, mijn_vragen_kanaal="oip_mijn_vragen", mijn_vragen_organisatie_naam="Open Inwoner Platform", mijn_vragen_actor=self.designated_actor["uuid"], diff --git a/src/open_inwoner/openzaak/tests/test_case_detail.py b/src/open_inwoner/openzaak/tests/test_case_detail.py index f1edaec850..a012d5f622 100644 --- a/src/open_inwoner/openzaak/tests/test_case_detail.py +++ b/src/open_inwoner/openzaak/tests/test_case_detail.py @@ -3,6 +3,7 @@ from django.conf import settings from django.contrib.auth.models import AnonymousUser +from django.contrib.auth.signals import user_logged_in from django.test import RequestFactory from django.test.utils import override_settings from django.urls import reverse @@ -23,8 +24,10 @@ VertrouwelijkheidsAanduidingen, ) from zgw_consumers.constants import APITypes +from zgw_consumers.models import Service from open_inwoner.accounts.choices import LoginTypeChoices +from open_inwoner.accounts.signals import update_user_from_klant_on_login from open_inwoner.accounts.tests.factories import UserFactory, eHerkenningUserFactory from open_inwoner.cms.cases.views.status import InnerCaseDetailView, SimpleFile from open_inwoner.openklant.api_models import ObjectContactMoment @@ -32,10 +35,9 @@ KlantenServiceType, Status as ContactMomentStatus, ) -from open_inwoner.openklant.models import OpenKlantConfig +from open_inwoner.openklant.models import OpenKlant2Config, OpenKlantConfig from open_inwoner.openklant.services import eSuiteVragenService from open_inwoner.openklant.tests.factories import make_question_from_contactmoment -from open_inwoner.openklant.tests.mocks import MockOpenKlant2Service from open_inwoner.openzaak.constants import StatusIndicators from open_inwoner.openzaak.tests.factories import ( ZaakTypeConfigFactory, @@ -88,6 +90,8 @@ class TestCaseDetailView( def setUp(self): super().setUp() + user_logged_in.disconnect(update_user_from_klant_on_login) + self.user = UserFactory( login_type=LoginTypeChoices.digid, bsn="900222086", email="johm@smith.nl" ) @@ -128,6 +132,24 @@ def setUp(self): self.openklant_config.contactmomenten_service = self.contactmoment_service self.openklant_config.save() + zgw_service, _ = Service.objects.update_or_create( + api_root="http://localhost:8338/klantinteracties/api/v1", + defaults={ + "label": "Klanten API service", + "slug": "klanten-api-service", + "api_type": APITypes.kc, + "secret": "", + }, + ) + self.openklant2_config, _ = OpenKlant2Config.objects.get_or_create( + zgw_service=zgw_service, + mijn_vragen_kanaal="oip_mijn_vragen", + mijn_vragen_organisatie_naam="Open Inwoner Platform", + mijn_vragen_actor="ca0783a1-1d74-4e07-b3e0-185b1d2fccd4", + interne_taak_gevraagde_handeling="Beantwoorden vraag Mijn Omgeving", + interne_taak_toelichting="Beantwoorden vraag", + ) + self.case_detail_url = reverse( "cases:case_detail_content", kwargs={ @@ -905,10 +927,6 @@ def _setUpAdditionalMocks(self, m): ) @freeze_time("2021-01-12 17:00:00") - @patch( - "open_inwoner.cms.cases.views.status.OpenKlant2Service", - return_value=MockOpenKlant2Service(), - ) @patch("open_inwoner.userfeed.hooks.case_status_seen", autospec=True) @patch("open_inwoner.userfeed.hooks.case_documents_seen", autospec=True) def test_status_is_retrieved_when_user_logged_in_via_digid( @@ -916,7 +934,6 @@ def test_status_is_retrieved_when_user_logged_in_via_digid( m, mock_hook_status: Mock, mock_hook_documents: Mock, - mock_openklant2_service, ): self.maxDiff = None @@ -1014,7 +1031,6 @@ def test_status_is_retrieved_when_user_logged_in_via_digid( self.contactmoment_new, new_answer_available=True, ), - MockOpenKlant2Service().retrieve_question()[0], make_question_from_contactmoment(self.contactmoment_old), ], }, @@ -1028,7 +1044,7 @@ def test_status_is_retrieved_when_user_logged_in_via_digid( doc = PyQuery(response.text) links = doc.find(".contactmomenten__link") - self.assertEqual(len(links), 3) + self.assertEqual(len(links), 2) for link, question in zip(links, case["questions"]): self.assertEqual( link.attrib["href"], @@ -1045,13 +1061,7 @@ def test_status_is_retrieved_when_user_logged_in_via_digid( self.assertEqual(len(new_answer_headers), 1) self.assertEqual(new_answer_headers[0].text, _("Nieuw antwoord beschikbaar")) - @patch( - "open_inwoner.cms.cases.views.status.OpenKlant2Service", - return_value=MockOpenKlant2Service(), - ) - def test_pass_endstatus_type_data_if_endstatus_not_reached( - self, m, mock_openklant2_service - ): + def test_pass_endstatus_type_data_if_endstatus_not_reached(self, m): self.maxDiff = None ZaakTypeStatusTypeConfigFactory.create( @@ -1139,7 +1149,6 @@ def test_pass_endstatus_type_data_if_endstatus_not_reached( "questions": [ make_question_from_contactmoment(self.contactmoment_new), make_question_from_contactmoment(self.contactmoment_balie), - MockOpenKlant2Service().retrieve_question()[0], make_question_from_contactmoment(self.contactmoment_old), ], }, @@ -1149,7 +1158,7 @@ def test_pass_endstatus_type_data_if_endstatus_not_reached( doc = PyQuery(response.text) links = doc.find(".contactmomenten__link") - self.assertEqual(len(links), 4) + self.assertEqual(len(links), 3) for link, question in zip(links, case["questions"]): self.assertEqual( diff --git a/src/open_inwoner/openzaak/tests/test_cases.py b/src/open_inwoner/openzaak/tests/test_cases.py index 95335739c5..da01e7d58a 100644 --- a/src/open_inwoner/openzaak/tests/test_cases.py +++ b/src/open_inwoner/openzaak/tests/test_cases.py @@ -7,6 +7,7 @@ from django.conf import settings from django.contrib.auth.models import AnonymousUser +from django.contrib.auth.signals import user_logged_in from django.test import TransactionTestCase from django.test.utils import override_settings from django.urls import reverse_lazy @@ -19,6 +20,7 @@ from zgw_consumers.api_models.constants import VertrouwelijkheidsAanduidingen from open_inwoner.accounts.choices import LoginTypeChoices +from open_inwoner.accounts.signals import update_user_from_klant_on_login from open_inwoner.accounts.tests.factories import UserFactory, eHerkenningUserFactory from open_inwoner.cms.cases.views.cases import CaseFilterFormOption, InnerCaseListView from open_inwoner.utils.test import ( @@ -89,6 +91,8 @@ class CaseListAccessTests(AssertRedirectsMixin, ClearCachesMixin, TransactionWeb def setUp(self): super().setUp() + user_logged_in.disconnect(update_user_from_klant_on_login) + # services ZGWApiGroupConfigFactory( ztc_service__api_root=CATALOGI_ROOT, diff --git a/src/openklant2/_resources/actor.py b/src/openklant2/_resources/actor.py index f48de99bfa..33b897ca94 100644 --- a/src/openklant2/_resources/actor.py +++ b/src/openklant2/_resources/actor.py @@ -10,7 +10,7 @@ class ActorResource(ResourceMixin): http_client: APIClient - base_path: str = "/actoren" + base_path: str = "actoren" def create( self, diff --git a/src/openklant2/_resources/betrokkene.py b/src/openklant2/_resources/betrokkene.py index bb1f7f066d..0dc97feea3 100644 --- a/src/openklant2/_resources/betrokkene.py +++ b/src/openklant2/_resources/betrokkene.py @@ -10,7 +10,7 @@ class BetrokkeneResource(ResourceMixin): http_client: APIClient - base_path: str = "/betrokkenen" + base_path: str = "betrokkenen" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/src/openklant2/_resources/digitaal_adres.py b/src/openklant2/_resources/digitaal_adres.py index 5bd78d0d71..ba87ce4f59 100644 --- a/src/openklant2/_resources/digitaal_adres.py +++ b/src/openklant2/_resources/digitaal_adres.py @@ -14,7 +14,7 @@ class DigitaalAdresResource(ResourceMixin): http_client: APIClient - base_path: str = "/digitaleadressen" + base_path: str = "digitaleadressen" def list( self, *, params: ListDigitaalAdresParams | None = None diff --git a/src/openklant2/_resources/interne_taak.py b/src/openklant2/_resources/interne_taak.py index efa92a274a..5c605a617c 100644 --- a/src/openklant2/_resources/interne_taak.py +++ b/src/openklant2/_resources/interne_taak.py @@ -10,7 +10,7 @@ class InterneTaakResource(ResourceMixin): http_client: APIClient - base_path: str = "/internetaken" + base_path: str = "internetaken" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/src/openklant2/_resources/klant_contact.py b/src/openklant2/_resources/klant_contact.py index cc99e93ffa..cb2a61fe12 100644 --- a/src/openklant2/_resources/klant_contact.py +++ b/src/openklant2/_resources/klant_contact.py @@ -15,7 +15,7 @@ class KlantContactResource(ResourceMixin): http_client: APIClient - base_path: str = "/klantcontacten" + base_path: str = "klantcontacten" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/src/openklant2/_resources/onderwerp_object.py b/src/openklant2/_resources/onderwerp_object.py index 4299db360b..e7ae95296d 100644 --- a/src/openklant2/_resources/onderwerp_object.py +++ b/src/openklant2/_resources/onderwerp_object.py @@ -14,7 +14,7 @@ class OnderwerpObjectResource(ResourceMixin): http_client: APIClient - base_path: str = "/onderwerpobjecten" + base_path: str = "onderwerpobjecten" def create( self, diff --git a/src/openklant2/_resources/partij.py b/src/openklant2/_resources/partij.py index c97cbe74e8..4016635211 100644 --- a/src/openklant2/_resources/partij.py +++ b/src/openklant2/_resources/partij.py @@ -17,7 +17,7 @@ class PartijResource(ResourceMixin): http_client: APIClient - base_path: str = "/partijen" + base_path: str = "partijen" def list( self, *, params: PartijListParams | None = None diff --git a/src/openklant2/_resources/partij_identificator.py b/src/openklant2/_resources/partij_identificator.py index 39f095b9b6..58d77e3755 100644 --- a/src/openklant2/_resources/partij_identificator.py +++ b/src/openklant2/_resources/partij_identificator.py @@ -14,7 +14,7 @@ class PartijIdentificatorResource(ResourceMixin): http_client: APIClient - base_path: str = "/partij-identificatoren" + base_path: str = "partij-identificatoren" def list( self, *, params: ListPartijIdentificatorenParams | None = None