Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#2940] Add OpenKlant2 configuration model #1529

Merged
merged 1 commit into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions src/open_inwoner/accounts/signals.py
Original file line number Diff line number Diff line change
@@ -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 _
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 0 additions & 4 deletions src/open_inwoner/accounts/tests/test_profile_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from django import forms
from django.conf import settings
from django.contrib.auth import signals
from django.template.defaultfilters import date as django_date
from django.test import TestCase, override_settings, tag
from django.urls import reverse, reverse_lazy
Expand All @@ -16,7 +15,6 @@
from webtest import Upload

from open_inwoner.accounts.choices import NotificationChannelChoice, StatusChoices
from open_inwoner.accounts.signals import update_user_from_klant_on_login
from open_inwoner.cms.profile.cms_appconfig import ProfileConfig
from open_inwoner.configurations.models import SiteConfiguration
from open_inwoner.haalcentraal.tests.mixins import HaalCentraalMixin
Expand Down Expand Up @@ -318,8 +316,6 @@ def test_messages_enabled_disabled(self):
)
class EditProfileTests(AssertTimelineLogMixin, WebTest):
def setUp(self):
signals.user_logged_in.disconnect(receiver=update_user_from_klant_on_login)

self.url = reverse("profile:edit")
self.return_url = reverse("profile:detail")
self.user = UserFactory()
Expand Down
47 changes: 21 additions & 26 deletions src/open_inwoner/accounts/views/signals.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import logging

from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver

from open_inwoner.accounts.models import User
from open_inwoner.openklant.models import OpenKlant2Config
from open_inwoner.openklant.services import OpenKlant2Service, eSuiteKlantenService

logger = logging.getLogger(__name__)
Expand All @@ -23,37 +21,34 @@ 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()):
try:
service = OpenKlant2Service(config=openklant2_config)
except RuntimeError:
logger.error("OpenKlant2 service failed to build")
return

if not (
fetch_params := service.get_fetch_parameters(
user=user, use_vestigingsnummer=True
)
):
return
try:
service = OpenKlant2Service()
except Exception:
logger.error("OpenKlant2 service failed to build")
return

partij, created = service.get_or_create_partij_for_user(
fetch_params=fetch_params, user=user
if not (
fetch_params := service.get_fetch_parameters(
user=user, use_vestigingsnummer=True
)
if not partij:
logger.error("Failed to create partij for new user %s", user)
return
elif not created:
service.update_user_from_partij(partij_uuid=partij["uuid"], user=user)
):
return

partij, created = service.get_or_create_partij_for_user(
fetch_params=fetch_params, user=user
)
if not partij:
logger.error("Failed to create partij for new user %s", user)
return
elif not created:
service.update_user_from_partij(partij_uuid=partij["uuid"], user=user)

logger.info("Created partij %s for new user %s", partij, user)
logger.info("Created partij %s for new user %s", partij, user)

# eSuite
try:
service = eSuiteKlantenService()
except RuntimeError:
except Exception:
logger.error("eSuiteKlantenService failed to build")
return

Expand Down
2 changes: 1 addition & 1 deletion src/open_inwoner/cms/cases/tests/test_contactform.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class CasesContactFormTestCase(AssertMockMatchersMixin, ClearCachesMixin, WebTes
def setUp(self):
super().setUp()

self.user = DigidUserFactory(bsn="900222086")
self.user = DigidUserFactory(bsn="900222086", email="foo@example.com")

# services
self.api_group = ZGWApiGroupConfigFactory(
Expand Down
14 changes: 4 additions & 10 deletions src/open_inwoner/cms/cases/views/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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):
Expand Down
75 changes: 75 additions & 0 deletions src/open_inwoner/openklant/migrations/0015_openklant2config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Generated by Django 4.2.16 on 2024-12-18 13:21

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"
),
),
(
"service",
models.OneToOneField(
on_delete=django.db.models.deletion.PROTECT,
related_name="+",
to="zgw_consumers.service",
verbose_name="Klanten API",
),
),
],
options={
"verbose_name": "OpenKlant2 configuration",
},
),
]
85 changes: 45 additions & 40 deletions src/open_inwoner/openklant/models.py
Original file line number Diff line number Diff line change
@@ -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 _

Expand Down Expand Up @@ -138,6 +132,51 @@ 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")


class OpenKlant2Config(models.Model):
service = models.OneToOneField(
"zgw_consumers.Service",
verbose_name=_("Klanten API"),
on_delete=models.PROTECT,
related_name="+",
)

# 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 = _("OpenKlant2 configuration")


class ContactFormSubject(OrderedModel):
subject = models.CharField(
verbose_name=_("Onderwerp"),
Expand Down Expand Up @@ -190,37 +229,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
17 changes: 9 additions & 8 deletions src/open_inwoner/openklant/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -823,16 +823,17 @@ class OpenKlant2Service(KlantenService):
client: OpenKlant2Client

def __init__(self, config: OpenKlant2Config | None = None):
self.config = config or OpenKlant2Config.from_django_settings()
if not self.config:
raise ImproperlyConfigured(
"Please set OPENKLANT2_CONFIG in your settings to configure OpenKlant2"
)
try:
self.config = config or OpenKlant2Config.objects.get()
except OpenKlant2Config.DoesNotExist:
raise ImproperlyConfigured("OpenKlant2Config not configured")
except OpenKlant2Config.MultipleObjectsReturned:
raise ImproperlyConfigured("Found multiple instances of OpenKlant2Config")

self.client = OpenKlant2Client(
base_url=self.config.api_url,
base_url=self.config.service.api_root,
request_kwargs={
"headers": {"Authorization": f"Token {self.config.api_token}"}
"headers": {"Authorization": f"Token {self.config.service.secret}"}
},
)

Expand Down Expand Up @@ -1133,7 +1134,7 @@ def create_question(
if len(question.rstrip()) == 0:
raise ValueError("You must provide a question")

if self.config.mijn_vragen_actor is None:
if not self.config.mijn_vragen_actor:
raise RuntimeError(
"You must define an actor to whom the question will be assigned. "
"Initialize the service with a value for `mijn_vragen_actor`."
Expand Down
1 change: 1 addition & 0 deletions src/open_inwoner/openklant/tests/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from open_inwoner.utils.test import paginated_response

KLANTEN_ROOT = "https://klanten.nl/api/v1/"
OPENKLANT2_ROOT = "http://localhost:8338/klantinteracties/api/v1"
CONTACTMOMENTEN_ROOT = "https://contactmomenten.nl/api/v1/"


Expand Down
Loading
Loading