Skip to content

Commit

Permalink
[#2940] Add OpenKlant2 configuration model
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Schilling committed Dec 16, 2024
1 parent 94fb79b commit 739211a
Show file tree
Hide file tree
Showing 13 changed files with 202 additions and 63 deletions.
4 changes: 1 addition & 3 deletions src/open_inwoner/accounts/views/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ 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:
Expand Down
70 changes: 70 additions & 0 deletions src/open_inwoner/openklant/migrations/0015_openklant2config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Generated by Django 4.2.16 on 2024-12-16 15:09

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, verbose_name="Mijn vragen kanaal"),
),
(
"mijn_vragen_organisatie_naam",
models.CharField(
blank=True, verbose_name="Mijn vragen organisatie naam"
),
),
(
"mijn_vragen_actor",
models.CharField(blank=True, verbose_name="Mijn vragen actor"),
),
(
"interne_taak_gevraagde_handeling",
models.CharField(
blank=True, verbose_name="Interne taak gevraagde handeling"
),
),
(
"interne_taak_toelichting",
models.CharField(
blank=True, verbose_name="Interne taak toelichting"
),
),
(
"service_config",
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",
},
),
]
88 changes: 48 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,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"),
Expand Down Expand Up @@ -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
6 changes: 3 additions & 3 deletions src/open_inwoner/openklant/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}"}
},
)

Expand Down
81 changes: 72 additions & 9 deletions src/open_inwoner/openklant/tests/test_openklant2_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from django.test import tag

import freezegun
from simple_certmanager.constants import CertificateTypes
from simple_certmanager.models import Certificate
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
Expand All @@ -17,10 +21,30 @@
class PartijGetOrCreateTestCase(Openklant2ServiceTestCase):
def setUp(self):
super().setUp()

server_certificate, _ = Certificate.objects.get_or_create(
label="test-server-cert",
defaults={
"type": CertificateTypes.cert_only,
},
)
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,
"oas": "",
"auth_type": "",
"client_id": "",
"secret": "",
"user_id": "",
"user_representation": "",
"server_certificate": server_certificate,
},
)
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",
Expand Down Expand Up @@ -220,10 +244,30 @@ def test_get_or_create_organisatie_with_vestiging(self):
class Openklant2ServiceTest(Openklant2ServiceTestCase):
def setUp(self):
super().setUp()

server_certificate, _ = Certificate.objects.get_or_create(
label="test-server-cert",
defaults={
"type": CertificateTypes.cert_only,
},
)
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,
"oas": "",
"auth_type": "",
"client_id": "",
"secret": "",
"user_id": "",
"user_representation": "",
"server_certificate": server_certificate,
},
)
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",
Expand Down Expand Up @@ -360,10 +404,29 @@ def setUp(self):
}
)

server_certificate, _ = Certificate.objects.get_or_create(
label="test-server-cert",
defaults={
"type": CertificateTypes.cert_only,
},
)
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,
"oas": "",
"auth_type": "",
"client_id": "",
"secret": "",
"user_id": "",
"user_representation": "",
"server_certificate": server_certificate,
},
)
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"],
Expand Down
2 changes: 1 addition & 1 deletion src/openklant2/_resources/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

class ActorResource(ResourceMixin):
http_client: APIClient
base_path: str = "/actoren"
base_path: str = "actoren"

def create(
self,
Expand Down
2 changes: 1 addition & 1 deletion src/openklant2/_resources/betrokkene.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/openklant2/_resources/digitaal_adres.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/openklant2/_resources/interne_taak.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/openklant2/_resources/klant_contact.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/openklant2/_resources/onderwerp_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

class OnderwerpObjectResource(ResourceMixin):
http_client: APIClient
base_path: str = "/onderwerpobjecten"
base_path: str = "onderwerpobjecten"

def create(
self,
Expand Down
2 changes: 1 addition & 1 deletion src/openklant2/_resources/partij.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/openklant2/_resources/partij_identificator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 739211a

Please sign in to comment.