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

[#3731] Add required headers for BRP clients #3736

Merged
merged 10 commits into from
Jan 22, 2024
34 changes: 30 additions & 4 deletions src/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,7 @@ paths:
- `displayMainWebsiteLink`
- `includeConfirmationPageContentInPdf`
- `translations`
- `brpPersonenRequestOptions`
summary: List forms
parameters:
- in: header
Expand Down Expand Up @@ -1316,6 +1317,7 @@ paths:
- `displayMainWebsiteLink`
- `includeConfirmationPageContentInPdf`
- `translations`
- `brpPersonenRequestOptions`
summary: Create form
parameters:
- in: header
Expand Down Expand Up @@ -1832,6 +1834,7 @@ paths:
- `displayMainWebsiteLink`
- `includeConfirmationPageContentInPdf`
- `translations`
- `brpPersonenRequestOptions`

Wanneer meertaligheid niet ingeschakeld is voor het formulier, dan wordt de standaardtaal (`settings.LANGUAGE_CODE`) geforceerd gezet in een language cookie. De actieve taal wordt gecommuniceerd in de Content-Language response header. De gebruikelijke HTTP Content Negotiation principes zijn van toepassing.
summary: Retrieve form details
Expand Down Expand Up @@ -1910,6 +1913,7 @@ paths:
- `displayMainWebsiteLink`
- `includeConfirmationPageContentInPdf`
- `translations`
- `brpPersonenRequestOptions`
summary: Update all details of a form
parameters:
- in: header
Expand Down Expand Up @@ -1992,6 +1996,7 @@ paths:
- `displayMainWebsiteLink`
- `includeConfirmationPageContentInPdf`
- `translations`
- `brpPersonenRequestOptions`
summary: Update given details of a form
parameters:
- in: header
Expand Down Expand Up @@ -6389,6 +6394,19 @@ components:
description: |-
* `nl` - Dutch
* `en` - English
BRPPersonenRequestOptions:
type: object
properties:
brpPersonenPurposeLimitationHeaderValue:
type: string
description: The purpose limitation ("doelbinding") for queries to the BRP
Persoon API.
maxLength: 255
brpPersonenProcessingHeaderValue:
type: string
description: The processing ("verwerking") for queries to the BRP Persoon
API.
maxLength: 242
BlankEnum:
enum:
- ''
Expand Down Expand Up @@ -6802,7 +6820,7 @@ components:

Note that this schema is used for both non-admin users filling out forms and
admin users designing forms. The fields that are only relevant for admin users are:
`internalName`, `registrationBackends`, `registrationBackend`, `registrationBackendOptions`, `authenticationBackendOptions`, `paymentBackend`, `paymentBackendOptions`, `product`, `category`, `theme`, `activateOn`, `deactivateOn`, `isDeleted`, `submissionConfirmationTemplate`, `askPrivacyConsent`, `askStatementOfTruth`, `submissionsRemovalOptions`, `confirmationEmailTemplate`, `sendConfirmationEmail`, `displayMainWebsiteLink`, `includeConfirmationPageContentInPdf`, `translations`.
`internalName`, `registrationBackends`, `registrationBackend`, `registrationBackendOptions`, `authenticationBackendOptions`, `paymentBackend`, `paymentBackendOptions`, `product`, `category`, `theme`, `activateOn`, `deactivateOn`, `isDeleted`, `submissionConfirmationTemplate`, `askPrivacyConsent`, `askStatementOfTruth`, `submissionsRemovalOptions`, `confirmationEmailTemplate`, `sendConfirmationEmail`, `displayMainWebsiteLink`, `includeConfirmationPageContentInPdf`, `translations`, `brpPersonenRequestOptions`.
properties:
uuid:
type: string
Expand Down Expand Up @@ -7022,6 +7040,10 @@ components:
submissionReportDownloadLinkTitle:
type: string
readOnly: true
brpPersonenRequestOptions:
allOf:
- $ref: '#/components/schemas/BRPPersonenRequestOptions'
nullable: true
required:
- cosignLoginInfo
- hideNonApplicableSteps
Expand Down Expand Up @@ -7266,7 +7288,7 @@ components:

Note that this schema is used for both non-admin users filling out forms and
admin users designing forms. The fields that are only relevant for admin users are:
`internalName`, `registrationBackends`, `registrationBackend`, `registrationBackendOptions`, `authenticationBackendOptions`, `paymentBackend`, `paymentBackendOptions`, `product`, `category`, `theme`, `activateOn`, `deactivateOn`, `isDeleted`, `submissionConfirmationTemplate`, `askPrivacyConsent`, `askStatementOfTruth`, `submissionsRemovalOptions`, `confirmationEmailTemplate`, `sendConfirmationEmail`, `displayMainWebsiteLink`, `includeConfirmationPageContentInPdf`, `translations`.
`internalName`, `registrationBackends`, `registrationBackend`, `registrationBackendOptions`, `authenticationBackendOptions`, `paymentBackend`, `paymentBackendOptions`, `product`, `category`, `theme`, `activateOn`, `deactivateOn`, `isDeleted`, `submissionConfirmationTemplate`, `askPrivacyConsent`, `askStatementOfTruth`, `submissionsRemovalOptions`, `confirmationEmailTemplate`, `sendConfirmationEmail`, `displayMainWebsiteLink`, `includeConfirmationPageContentInPdf`, `translations`, `brpPersonenRequestOptions`.
properties:
name:
type: string
Expand Down Expand Up @@ -7431,7 +7453,7 @@ components:

Note that this schema is used for both non-admin users filling out forms and
admin users designing forms. The fields that are only relevant for admin users are:
`internalName`, `registrationBackends`, `registrationBackend`, `registrationBackendOptions`, `authenticationBackendOptions`, `paymentBackend`, `paymentBackendOptions`, `product`, `category`, `theme`, `activateOn`, `deactivateOn`, `isDeleted`, `submissionConfirmationTemplate`, `askPrivacyConsent`, `askStatementOfTruth`, `submissionsRemovalOptions`, `confirmationEmailTemplate`, `sendConfirmationEmail`, `displayMainWebsiteLink`, `includeConfirmationPageContentInPdf`, `translations`.
`internalName`, `registrationBackends`, `registrationBackend`, `registrationBackendOptions`, `authenticationBackendOptions`, `paymentBackend`, `paymentBackendOptions`, `product`, `category`, `theme`, `activateOn`, `deactivateOn`, `isDeleted`, `submissionConfirmationTemplate`, `askPrivacyConsent`, `askStatementOfTruth`, `submissionsRemovalOptions`, `confirmationEmailTemplate`, `sendConfirmationEmail`, `displayMainWebsiteLink`, `includeConfirmationPageContentInPdf`, `translations`, `brpPersonenRequestOptions`.
properties:
name:
type: string
Expand Down Expand Up @@ -8335,7 +8357,7 @@ components:

Note that this schema is used for both non-admin users filling out forms and
admin users designing forms. The fields that are only relevant for admin users are:
`internalName`, `registrationBackends`, `registrationBackend`, `registrationBackendOptions`, `authenticationBackendOptions`, `paymentBackend`, `paymentBackendOptions`, `product`, `category`, `theme`, `activateOn`, `deactivateOn`, `isDeleted`, `submissionConfirmationTemplate`, `askPrivacyConsent`, `askStatementOfTruth`, `submissionsRemovalOptions`, `confirmationEmailTemplate`, `sendConfirmationEmail`, `displayMainWebsiteLink`, `includeConfirmationPageContentInPdf`, `translations`.
`internalName`, `registrationBackends`, `registrationBackend`, `registrationBackendOptions`, `authenticationBackendOptions`, `paymentBackend`, `paymentBackendOptions`, `product`, `category`, `theme`, `activateOn`, `deactivateOn`, `isDeleted`, `submissionConfirmationTemplate`, `askPrivacyConsent`, `askStatementOfTruth`, `submissionsRemovalOptions`, `confirmationEmailTemplate`, `sendConfirmationEmail`, `displayMainWebsiteLink`, `includeConfirmationPageContentInPdf`, `translations`, `brpPersonenRequestOptions`.
properties:
uuid:
type: string
Expand Down Expand Up @@ -8555,6 +8577,10 @@ components:
submissionReportDownloadLinkTitle:
type: string
readOnly: true
brpPersonenRequestOptions:
allOf:
- $ref: '#/components/schemas/BRPPersonenRequestOptions'
nullable: true
PatchedFormDefinition:
type: object
properties:
Expand Down
1 change: 1 addition & 0 deletions src/openforms/config/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class GlobalConfigurationAdmin(TranslationAdmin, SingletonModelAdmin):
"main_website",
"favicon",
"default_theme",
"organization_oin",
),
},
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 3.2.23 on 2024-01-15 14:28

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("config", "0067_alter_globalconfiguration_enable_react_formio_builder"),
]

operations = [
migrations.AddField(
model_name="globalconfiguration",
name="organization_oin",
field=models.CharField(
blank=True,
help_text="The OIN of the organization.",
max_length=20,
verbose_name="organization OIN",
),
),
]
8 changes: 8 additions & 0 deletions src/openforms/config/models/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,14 @@ class GlobalConfiguration(SingletonModel):
),
)

# See https://gitdocumentatie.logius.nl/publicatie/dk/oin/#samenstelling-oin
organization_oin = models.CharField(
_("organization OIN"),
max_length=20,
blank=True,
help_text=_("The OIN of the organization."),
)

# session timeouts

admin_session_timeout = models.PositiveIntegerField(
Expand Down
26 changes: 24 additions & 2 deletions src/openforms/contrib/haal_centraal/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,37 @@

from solo.admin import SingletonModelAdmin

from .models import HaalCentraalConfig
from .models import BRPPersonenRequestOptions, HaalCentraalConfig


@admin.register(HaalCentraalConfig)
class HaalCentraalConfigAdmin(SingletonModelAdmin):
fieldsets = (
(
_("BRP Personen Bevragen"),
{"fields": ("brp_personen_service", "brp_personen_version")},
{
"fields": (
"brp_personen_service",
"brp_personen_version",
"default_brp_personen_purpose_limitation_header_value",
"default_brp_personen_processing_header_value",
)
},
),
)
autocomplete_fields = ("brp_personen_service",)


@admin.register(BRPPersonenRequestOptions)
class BRPPersonenRequestOptionsAdmin(admin.ModelAdmin):
list_display = (
"form",
"brp_personen_purpose_limitation_header_value",
"brp_personen_processing_header_value",
)
list_filter = ("form",)
search_fields = (
"brp_personen_purpose_limitation_header_value",
"brp_personen_processing_header_value",
)
raw_id_fields = ("form",)
Empty file.
12 changes: 12 additions & 0 deletions src/openforms/contrib/haal_centraal/api/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from rest_framework import serializers

from ..models import BRPPersonenRequestOptions


class BRPPersonenRequestOptionsSerializer(serializers.ModelSerializer):
class Meta:
model = BRPPersonenRequestOptions
fields = (
"brp_personen_purpose_limitation_header_value",
"brp_personen_processing_header_value",
)
57 changes: 52 additions & 5 deletions src/openforms/contrib/haal_centraal/clients/__init__.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,72 @@
from zgw_consumers_ext.api_client import ServiceClientFactory
from typing import Any

from ..models import HaalCentraalConfig
from openforms.authentication.constants import AuthAttribute
from openforms.config.models import GlobalConfiguration
from openforms.submissions.models import Submission
from zgw_consumers_ext.api_client import build_client

from ..constants import DEFAULT_HC_BRP_PERSONEN_GEBRUIKER_HEADER
from ..models import BRPPersonenRequestOptions, HaalCentraalConfig
from .brp import CLIENT_CLS_FOR_VERSION as BRP_CLIENT_CLS_FOR_VERSION, BRPClient


class NoServiceConfigured(RuntimeError):
pass


def get_brp_client(**kwargs) -> BRPClient:
def get_brp_client(submission: Submission | None = None, **kwargs: Any) -> BRPClient:
"""Get an instance of a BRP client.

:param submission: the current submission in the context of the client usage.
This submission will be used to fetch headers overrides.
:param kwargs: additional kwargs to be passed to the client class.
"""

config = HaalCentraalConfig.get_solo()
global_config = GlobalConfiguration.get_solo()
assert isinstance(config, HaalCentraalConfig)
assert isinstance(global_config, GlobalConfiguration)
if not (service := config.brp_personen_service):
raise NoServiceConfigured("No BRP service configured!")

if submission is not None:
request_options = getattr(
submission.form, "brp_personen_request_options", BRPPersonenRequestOptions()
)
if (
submission.registrator
and submission.registrator.attribute is AuthAttribute.employee_id
):
gebruiker = submission.registrator.value
else:
gebruiker = DEFAULT_HC_BRP_PERSONEN_GEBRUIKER_HEADER
else:
gebruiker = DEFAULT_HC_BRP_PERSONEN_GEBRUIKER_HEADER
request_options = BRPPersonenRequestOptions()

origin_oin = global_config.organization_oin
doelbinding = (
request_options.brp_personen_purpose_limitation_header_value
or config.default_brp_personen_purpose_limitation_header_value
)
verwerking = (
request_options.brp_personen_processing_header_value
or config.default_brp_personen_processing_header_value
)

version = config.brp_personen_version
ClientCls = BRP_CLIENT_CLS_FOR_VERSION.get(version)
if ClientCls is None:
raise RuntimeError(
f"No suitable client class configured for API version {version}"
)

service_client_factory = ServiceClientFactory(service)
return ClientCls.configure_from(service_client_factory, **kwargs)
return build_client(
service,
client_factory=ClientCls,
origin_oin=origin_oin,
doelbinding=doelbinding,
verwerking=verwerking,
gebruiker=gebruiker,
**kwargs,
)
19 changes: 17 additions & 2 deletions src/openforms/contrib/haal_centraal/clients/brp.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,21 @@ class Person:


class BRPClient(PreRequestMixin, ABC, APIClient):
def __init__(
self,
*args,
origin_oin: str = "",
doelbinding: str = "",
verwerking: str = "",
gebruiker: str = "",
**kwargs,
) -> None:
super().__init__(*args, **kwargs)
self.headers["x-origin-oin"] = origin_oin
self.headers["x-doelbinding"] = doelbinding
self.headers["x-verwerking"] = verwerking
self.headers["x-gebruiker"] = gebruiker

@abstractmethod
def find_person(self, bsn: str, **kwargs) -> JSONObject | None:
...
Expand Down Expand Up @@ -98,7 +113,7 @@ def _get_children(self, bsn: str) -> list[Person]:
persons.append(person)
return persons

def _get_partner(self, bsn: str) -> list[Person]:
def _get_partners(self, bsn: str) -> list[Person]:
response = self.get(f"ingeschrevenpersonen/{bsn}/partners")
response.raise_for_status()
response_data = response.json()["_embedded"]
Expand Down Expand Up @@ -128,7 +143,7 @@ def get_family_members(
family_members += self._get_children(bsn)

if include_partner:
family_members += self._get_partner(bsn)
family_members += self._get_partners(bsn)

return family_members

Expand Down
2 changes: 2 additions & 0 deletions src/openforms/contrib/haal_centraal/constants.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from django.db import models

DEFAULT_HC_BRP_PERSONEN_GEBRUIKER_HEADER = "BurgerZelf"


class BRPVersions(models.TextChoices):
"""
Expand Down
Loading
Loading