diff --git a/docs/configuration/prefill/index.rst b/docs/configuration/prefill/index.rst index a090bbf023..410ec0edd1 100644 --- a/docs/configuration/prefill/index.rst +++ b/docs/configuration/prefill/index.rst @@ -12,3 +12,4 @@ Prefill plugins kvk stuf_bg suwinet + objects_api diff --git a/docs/developers/plugins/prefill_plugins.rst b/docs/developers/plugins/prefill_plugins.rst index e906ef3f5d..004929714e 100644 --- a/docs/developers/plugins/prefill_plugins.rst +++ b/docs/developers/plugins/prefill_plugins.rst @@ -25,6 +25,9 @@ You can find an example implementation in :mod:`openforms.prefill.contrib.demo`. Implementation -------------- +Plugins must be added to the INSTALLED_APPS :mod:`openforms.conf.base`. See the demo app as an example +("openforms.prefill.contrib.demo.apps.DemoApp") + Plugins must implement the interface from :class:`openforms.prefill.base.BasePlugin`. It's safe to use this as a base class. diff --git a/src/openforms/conf/base.py b/src/openforms/conf/base.py index e6411494aa..53c8847e0c 100644 --- a/src/openforms/conf/base.py +++ b/src/openforms/conf/base.py @@ -228,6 +228,7 @@ "openforms.prefill.contrib.stufbg.apps.StufBgApp", "openforms.prefill.contrib.haalcentraal_brp.apps.HaalCentraalBRPApp", "openforms.prefill.contrib.suwinet.apps.SuwinetApp", + "openforms.prefill.contrib.objects_api.apps.ObjectsApiApp", "openforms.authentication", "openforms.authentication.contrib.demo.apps.DemoApp", "openforms.authentication.contrib.outage.apps.DemoOutageApp", diff --git a/src/openforms/prefill/api/serializers.py b/src/openforms/prefill/api/serializers.py index a5f902ca43..c7c28729e1 100644 --- a/src/openforms/prefill/api/serializers.py +++ b/src/openforms/prefill/api/serializers.py @@ -64,3 +64,14 @@ class PrefillAttributeSerializer(serializers.Serializer): label=_("Label"), help_text=_("The human-readable name for an attribute."), ) + + +class PrefillObjectsAPIAttributeSerializer(serializers.Serializer): + id = serializers.CharField( + label=_("ID"), + help_text=_("The unique attribute identifier"), + ) + label = serializers.CharField( + label=_("Label"), + help_text=_("The human-readable name for an attribute."), + ) diff --git a/src/openforms/prefill/api/urls.py b/src/openforms/prefill/api/urls.py index a43ea07f59..eb695f69f4 100644 --- a/src/openforms/prefill/api/urls.py +++ b/src/openforms/prefill/api/urls.py @@ -1,8 +1,29 @@ from django.urls import path -from .views import PluginAttributesListView, PluginListView +from .views import ( + PluginAttributesListView, + PluginListView, + PluginObjectsAPIAttributesListView, + PluginObjectsAPIObjecttypeListView, + PluginObjectsAPIObjecttypeVersionListView, +) urlpatterns = [ + path( + "plugins/objects-api/objecttypes", + PluginObjectsAPIObjecttypeListView.as_view(), + name="prefill-objects-api-objecttype-list", + ), + path( + "plugins/objects-api/objecttypes//versions", + PluginObjectsAPIObjecttypeVersionListView.as_view(), + name="prefill-objects-api-objecttype-version-list", + ), + path( + "plugins/objects-api/objecttypes//versions//attributes", + PluginObjectsAPIAttributesListView.as_view(), + name="prefill-objects-api-objecttype-attribute-list", + ), path("plugins", PluginListView.as_view(), name="prefill-plugin-list"), path( "plugins//attributes", diff --git a/src/openforms/prefill/api/views.py b/src/openforms/prefill/api/views.py index b0ecba2f6b..171d95ad5e 100644 --- a/src/openforms/prefill/api/views.py +++ b/src/openforms/prefill/api/views.py @@ -1,19 +1,41 @@ +from typing import Any + from django.utils.translation import gettext_lazy as _ -from drf_spectacular.utils import extend_schema, extend_schema_view +from drf_spectacular.types import OpenApiTypes +from drf_spectacular.utils import OpenApiParameter, extend_schema, extend_schema_view from rest_framework import authentication, permissions from rest_framework.exceptions import NotFound from rest_framework.views import APIView from openforms.api.views import ListMixin +from openforms.registrations.contrib.objects_api.api.serializers import ( + ObjectsAPIGroupInputSerializer, +) +from openforms.registrations.contrib.objects_api.client import get_objecttypes_client from ..registry import register from .serializers import ( ChoiceWrapper, PrefillAttributeSerializer, + PrefillObjectsAPIAttributeSerializer, PrefillPluginQueryParameterSerializer, PrefillPluginSerializer, ) +from openforms.registrations.contrib.objects_api.api.views import ( + ObjecttypesListView, + ObjecttypeVersionsListView, +) +from openforms.registrations.contrib.objects_api.api.serializers import ( + ObjecttypeVersionSerializer, +) + +OBJECTS_API_GROUP_QUERY_PARAMETER = OpenApiParameter( + name="objects_api_group", + type=OpenApiTypes.STR, + location=OpenApiParameter.QUERY, + description=_("Which Objects API group to use."), +) @extend_schema_view( @@ -67,3 +89,73 @@ def get_objects(self): choices = plugin.get_available_attributes() return [ChoiceWrapper(choice) for choice in choices] + + +@extend_schema_view( + get=extend_schema(summary=_("List available objecttypes for Objects API")), + parameters=[OBJECTS_API_GROUP_QUERY_PARAMETER], +) +class PluginObjectsAPIObjecttypeListView(ObjecttypesListView): + """ + List the available prefill objecttypes for Objects API plugin. + """ + + pass + + +@extend_schema_view( + get=extend_schema(summary=_("List available objecttype versions for Objects API")), + parameters=[OBJECTS_API_GROUP_QUERY_PARAMETER], +) +class PluginObjectsAPIObjecttypeVersionListView(ObjecttypeVersionsListView): + """ + List the available prefill objecttype versions for Objects API plugin. + """ + + def get_objects(self): + input_serializer = ObjectsAPIGroupInputSerializer( + data=self.request.query_params + ) + input_serializer.is_valid(raise_exception=True) + + config_group = input_serializer.validated_data["objects_api_group"] + objecttype_uuid = self.kwargs["objects_api_objecttype_uuid"] + + with get_objecttypes_client(config_group) as client: + return client.list_objecttype_versions(objecttype_uuid) + + +@extend_schema_view( + get=extend_schema(summary=_("List available attributes for Objects API")), + parameters=[OBJECTS_API_GROUP_QUERY_PARAMETER], +) +class PluginObjectsAPIAttributesListView(ListMixin, APIView): + """ + List the available attributes for Objects API plugin. + """ + + authentication_classes = (authentication.SessionAuthentication,) + permission_classes = (permissions.IsAdminUser,) + serializer_class = PrefillObjectsAPIAttributeSerializer + + def get_objects(self): + plugin = register["objects_api"] + input_serializer = ObjectsAPIGroupInputSerializer( + data=self.request.query_params + ) + input_serializer.is_valid(raise_exception=True) + + config_group = input_serializer.validated_data["objects_api_group"] + choices = plugin.get_available_attributes( + reference={ + "objects_api_group": config_group, + "objects_api_objecttype_uuid": self.kwargs[ + "objects_api_objecttype_uuid" + ], + "objects_api_objecttype_version": self.kwargs[ + "objects_api_objecttype_version" + ], + } + ) + + return choices diff --git a/src/openforms/prefill/base.py b/src/openforms/prefill/base.py index 4d7eacda8c..0eb373770c 100644 --- a/src/openforms/prefill/base.py +++ b/src/openforms/prefill/base.py @@ -19,9 +19,14 @@ class BasePlugin(AbstractBasePlugin): for_components: Container[str] = AllComponentTypes() @staticmethod - def get_available_attributes() -> Iterable[tuple[str, str]]: + def get_available_attributes( + reference: dict[str, str] | None = None, + ) -> Iterable[tuple[str, str]]: """ Return a choice list of available attributes this plugin offers. + + :param reference: a dict based on which we retrieve the available attributes. + Can be used when we have dynamic lists of attributes. """ raise NotImplementedError( "You must implement the 'get_available_attributes' method." diff --git a/src/openforms/prefill/contrib/objects_api/__init__.py b/src/openforms/prefill/contrib/objects_api/__init__.py new file mode 100644 index 0000000000..7c438b5c34 --- /dev/null +++ b/src/openforms/prefill/contrib/objects_api/__init__.py @@ -0,0 +1,3 @@ +""" +Objects API prefill plugin. +""" diff --git a/src/openforms/prefill/contrib/objects_api/apps.py b/src/openforms/prefill/contrib/objects_api/apps.py new file mode 100644 index 0000000000..816875ae66 --- /dev/null +++ b/src/openforms/prefill/contrib/objects_api/apps.py @@ -0,0 +1,12 @@ +from django.apps import AppConfig +from django.utils.translation import gettext_lazy as _ + + +class ObjectsApiApp(AppConfig): + name = "openforms.prefill.contrib.objects_api" + label = "objects_api" + verbose_name = _("Objects API prefill plugin") + + def ready(self): + # register the plugin + from . import plugin # noqa diff --git a/src/openforms/prefill/contrib/objects_api/plugin.py b/src/openforms/prefill/contrib/objects_api/plugin.py new file mode 100644 index 0000000000..e2f11fead0 --- /dev/null +++ b/src/openforms/prefill/contrib/objects_api/plugin.py @@ -0,0 +1,44 @@ +import logging +from typing import Any, Iterable + +from django.utils.translation import gettext_lazy as _ + +from openforms.authentication.service import AuthAttribute + +from openforms.submissions.models import Submission +from openforms.typing import JSONEncodable + +from ...base import BasePlugin +from ...constants import IdentifierRoles +from ...registry import register + +logger = logging.getLogger(__name__) + +PLUGIN_IDENTIFIER = "objects_api" + + +@register(PLUGIN_IDENTIFIER) +class ObjectsAPIPrefill(BasePlugin): + verbose_name = _("Objects API") + requires_auth = AuthAttribute.bsn + + @staticmethod + def get_available_attributes( + reference: dict[str, Any] | None = None, + ) -> Iterable[tuple[str, str]]: + pass + + @classmethod + def get_prefill_values( + cls, + submission: Submission, + attributes: list[str], + identifier_role: IdentifierRoles = IdentifierRoles.main, + ) -> dict[str, JSONEncodable]: + pass + + @classmethod + def get_co_sign_values( + cls, submission: Submission, identifier: str + ) -> tuple[dict[str, Any], str]: + pass