From f7d91de53720bde70664be89d38bfbe405cf74ac Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Tue, 28 Jan 2025 16:16:26 +0100 Subject: [PATCH] :sparkles: [#5016] Add endpoint for referentielijst tabellen this endpoint is used by the formio builder to populate the select widget with tabellen to populate select/selectboxes/radio component options from --- src/openapi.yaml | 66 +++++++++++++++++++ src/openforms/api/urls.py | 10 +++ .../contrib/referentielijsten/api/__init__.py | 0 .../referentielijsten/api/serializers.py | 16 +++++ .../contrib/referentielijsten/api/viewsets.py | 55 ++++++++++++++++ .../contrib/referentielijsten/client.py | 21 ++++++ .../formio_builder/WebformBuilder.js | 3 +- .../formio_builder/referentielijsten.js | 5 ++ 8 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 src/openforms/contrib/referentielijsten/api/__init__.py create mode 100644 src/openforms/contrib/referentielijsten/api/serializers.py create mode 100644 src/openforms/contrib/referentielijsten/api/viewsets.py diff --git a/src/openapi.yaml b/src/openapi.yaml index 679fc52758..1556aa417a 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -3715,6 +3715,44 @@ paths: $ref: '#/components/headers/X-Is-Form-Designer' Content-Language: $ref: '#/components/headers/Content-Language' + /api/v2/referentielijst-tabellen/{service}: + get: + operationId: referentielijst_tabellen_list + description: |- + Return a list of available (JSON) tabellen in a given Referentielijsten service configured in the backend. + + Note that this endpoint is **EXPERIMENTAL**. + summary: List tabellen for a Referentielijsten service + parameters: + - in: path + name: service + schema: + type: string + pattern: ^[-a-zA-Z0-9_]+$ + required: true + tags: + - referentielijst-tabellen + security: + - cookieAuth: [] + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ReferentielijstTabellen' + description: '' + headers: + X-Session-Expires-In: + $ref: '#/components/headers/X-Session-Expires-In' + X-CSRFToken: + $ref: '#/components/headers/X-CSRFToken' + X-Is-Form-Designer: + $ref: '#/components/headers/X-Is-Form-Designer' + Content-Language: + $ref: '#/components/headers/Content-Language' + x-experimental: true /api/v2/registration/attributes: get: operationId: registration_attributes_list @@ -9651,6 +9689,24 @@ components: required: - name - slug + ReferentielijstTabellen: + type: object + properties: + code: + type: string + description: The unique code that identifies the table. + naam: + type: string + description: The name of the table. + einddatumGeldigheid: + type: string + format: date-time + description: The timestamp on which the tabel expires. + required: + - code + - einddatumGeldigheid + - naam + x-experimental: true RegistrationAttribute: type: object properties: @@ -9723,12 +9779,21 @@ components: type: string format: uri readOnly: true + slug: + type: string + title: Service slug + description: A unique, human-friendly slug to identify this service. Primarily + useful for cross-instance import/export. + maxLength: 255 + pattern: ^[-a-zA-Z0-9_]+$ label: type: string maxLength: 100 apiRoot: type: string title: Api root url + description: The root URL of the service that will be used to construct + the URLs when making requests. maxLength: 255 apiType: allOf: @@ -9738,6 +9803,7 @@ components: - apiRoot - apiType - label + - slug - url x-experimental: true ServiceFetchConfiguration: diff --git a/src/openforms/api/urls.py b/src/openforms/api/urls.py index 286d637ea8..9ba9b8337e 100644 --- a/src/openforms/api/urls.py +++ b/src/openforms/api/urls.py @@ -10,6 +10,9 @@ from rest_framework_nested.routers import NestedSimpleRouter from openforms.config.api.viewsets import ThemeViewSet +from openforms.contrib.referentielijsten.api.viewsets import ( + ReferentielijstenTabellenViewSet, +) from openforms.forms.api.public_api.viewsets import CategoryViewSet from openforms.forms.api.viewsets import ( FormDefinitionViewSet, @@ -60,6 +63,13 @@ # services router.register("services", ServiceViewSet) +# referentielijsten +router.register( + "referentielijst-tabellen", + ReferentielijstenTabellenViewSet, + basename="referentielijst-tabellen", +) + # service fetch configurations router.register("service-fetch-configurations", ServiceFetchConfigurationViewSet) diff --git a/src/openforms/contrib/referentielijsten/api/__init__.py b/src/openforms/contrib/referentielijsten/api/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/openforms/contrib/referentielijsten/api/serializers.py b/src/openforms/contrib/referentielijsten/api/serializers.py new file mode 100644 index 0000000000..bbe80a11ab --- /dev/null +++ b/src/openforms/contrib/referentielijsten/api/serializers.py @@ -0,0 +1,16 @@ +from django.utils.translation import gettext_lazy as _ + +from rest_framework import serializers + +from openforms.api.utils import mark_experimental + + +@mark_experimental +class ReferentielijstTabellenSerializer(serializers.Serializer): + code = serializers.CharField( + help_text=_("The unique code that identifies the table.") + ) + naam = serializers.CharField(help_text=_("The name of the table.")) + einddatumGeldigheid = serializers.DateTimeField( + help_text=_("The timestamp on which the tabel expires."), allow_null=True + ) diff --git a/src/openforms/contrib/referentielijsten/api/viewsets.py b/src/openforms/contrib/referentielijsten/api/viewsets.py new file mode 100644 index 0000000000..04b8dca7c2 --- /dev/null +++ b/src/openforms/contrib/referentielijsten/api/viewsets.py @@ -0,0 +1,55 @@ +from django.shortcuts import get_object_or_404 +from django.utils.translation import gettext_lazy as _ + +from drf_spectacular.utils import extend_schema, extend_schema_view +from requests.exceptions import RequestException +from rest_framework import authentication, permissions, serializers, status, viewsets +from rest_framework.decorators import action +from rest_framework.response import Response +from zgw_consumers.client import build_client +from zgw_consumers.models import Service + +from openforms.api.utils import mark_experimental + +from ..client import ReferentielijstenClient +from .serializers import ReferentielijstTabellenSerializer + + +@extend_schema_view( + get=extend_schema( + summary=_("List tabellen for a Referentielijsten service"), + description=_( + "Return a list of available (JSON) tabellen in a given Referentielijsten service configured " + "in the backend.\n\n" + "Note that this endpoint is **EXPERIMENTAL**." + ), + responses={ + 200: ReferentielijstTabellenSerializer(many=True), + }, + ) +) +@mark_experimental +class ReferentielijstenTabellenViewSet(viewsets.ViewSet): + """ + List tabellen for a given Referentielijst service + """ + + authentication_classes = (authentication.SessionAuthentication,) + permission_classes = (permissions.IsAdminUser,) + serializer_class = ReferentielijstTabellenSerializer + + @action(detail=False, methods=["get"], url_path="(?P[-a-zA-Z0-9_]+)") + def get(self, request, service: str | None = None): + service = get_object_or_404(Service, slug=service) + try: + with build_client( + service, client_factory=ReferentielijstenClient + ) as client: + result = client.get_tabellen() + except RequestException: + result = [] + + assert issubclass(self.serializer_class, serializers.Serializer) + serializer = self.serializer_class(data=result, many=True) + serializer.is_valid() + return Response(serializer.data, status=status.HTTP_200_OK) diff --git a/src/openforms/contrib/referentielijsten/client.py b/src/openforms/contrib/referentielijsten/client.py index edf492bc87..12b8bc6d51 100644 --- a/src/openforms/contrib/referentielijsten/client.py +++ b/src/openforms/contrib/referentielijsten/client.py @@ -17,7 +17,28 @@ class TabelItem(TypedDict): aanvullendeGegevens: Any +class Beheerder(TypedDict): + naam: str + email: str + afdeling: str + organisatie: str + + +class Tabel(TypedDict): + code: str + naam: str + beheerder: Beheerder + einddatumGeldigheid: str | None # ISO 8601 datetime string + + class ReferentielijstenClient(APIClient): + def get_tabellen(self) -> list[Tabel]: + response = self.get("tabellen", timeout=10) + response.raise_for_status() + data = response.json() + all_data = list(pagination_helper(self, data)) + return all_data + def get_items_for_tabel(self, code: str) -> list[TabelItem]: response = self.get("items", params={"tabel__code": code}, timeout=10) response.raise_for_status() diff --git a/src/openforms/js/components/formio_builder/WebformBuilder.js b/src/openforms/js/components/formio_builder/WebformBuilder.js index 0c290c1dbf..3cd1b1b55e 100644 --- a/src/openforms/js/components/formio_builder/WebformBuilder.js +++ b/src/openforms/js/components/formio_builder/WebformBuilder.js @@ -24,7 +24,7 @@ import { getRegistrationAttributes, getValidatorPlugins, } from './plugins'; -import {getServices} from './referentielijsten'; +import {getReferentielijstenTabellen, getServices} from './referentielijsten'; let _supportedLanguages = undefined; const getSupportedLanguages = () => { @@ -169,6 +169,7 @@ class WebformBuilder extends WebformBuilderFormio { getValidatorPlugins={getValidatorPlugins} getRegistrationAttributes={getRegistrationAttributes} getServices={getServices} + getReferentielijstenTabellen={getReferentielijstenTabellen} getPrefillPlugins={getPrefillPlugins} getPrefillAttributes={getPrefillAttributes} getFileTypes={async () => FILE_TYPES} diff --git a/src/openforms/js/components/formio_builder/referentielijsten.js b/src/openforms/js/components/formio_builder/referentielijsten.js index fecb76c251..b9a4bab578 100644 --- a/src/openforms/js/components/formio_builder/referentielijsten.js +++ b/src/openforms/js/components/formio_builder/referentielijsten.js @@ -4,3 +4,8 @@ export const getServices = async type => { const resp = await get(`/api/v2/services?type=${encodeURIComponent(type)}`); return resp.data; }; + +export const getReferentielijstenTabellen = async service => { + const resp = await get(`/api/v2/referentielijst-tabellen/${service}`); + return resp.data; +};