Skip to content

Commit

Permalink
[#4396] Added basic structure of the Objects API prefill plugin
Browse files Browse the repository at this point in the history
This commit contains only the basic structure of the plugin, the methods
will be implemented in the next PR. This has the endpoints and views
needed for the new prefill modal when we select the ObjectsAPI.
  • Loading branch information
vaszig committed Aug 28, 2024
1 parent 262d84e commit 70f0382
Show file tree
Hide file tree
Showing 15 changed files with 566 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/configuration/prefill/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ Prefill plugins
kvk
stuf_bg
suwinet
objects_api
42 changes: 42 additions & 0 deletions docs/configuration/prefill/objects_api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.. _configuration_prefill_objects_api:

===========
Objects API
===========

`Objects API`_ can store objects which are defined (their schema and properties) in the `Objecttypes API`_.
With this prefill plugin we can have components/form fields which have pre-filled the values taken from the Objects API.

.. note::

This service contains sensitive data and requires a connection to a specific
client system. The forms which make use of this prefill plugin require DigiD/Eherkenning authentication
of the user.

.. _`Objects API`: https://objects-and-objecttypes-api.readthedocs.io/en/latest/
.. _`Objecttypes API`: https://objects-and-objecttypes-api.readthedocs.io/en/latest/


Configuration
=============

1. In Open Forms, navigate to: **Forms**
2. Click **Add form**
3. Define the necessary form details and add the desired components
4. Navigate to: **Variables** tab
5. Navigate to: **User defined** subtab
6. Click **Add variable** and fill in the data from the available options:

* **Plugin**: *Choose the Objects API plugin*
* **API Group**: *Choose the desired API Group *
(There must be at least one added-configured via **Miscellaneous** > **Objects API groups**)
* **Objecttype**: *Based on the selected API group above, you can choose the objecttype from the auto populated list*
* **Mappings**: *On the left we have the available form variables and on the right the available attributes which are
defined in the selected objecttype's schema properties. You can do the mappings accordingly*

7. Click **Save**
8. Save the form

The Objects API configuration is now complete.


3 changes: 3 additions & 0 deletions docs/developers/plugins/prefill_plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
117 changes: 117 additions & 0 deletions src/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3586,6 +3586,123 @@ paths:
$ref: '#/components/headers/X-Is-Form-Designer'
Content-Language:
$ref: '#/components/headers/Content-Language'
/api/v2/prefill/plugins/objects-api/objecttypes:
get:
operationId: prefill_plugins_objects_api_objecttypes_list
description: List the available prefill objecttypes for Objects API plugin.
summary: List available objecttypes for Objects API
parameters:
- in: query
name: objects_api_group
schema:
type: string
description: Which Objects API group to use.
tags:
- registration
security:
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Objecttype'
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'
/api/v2/prefill/plugins/objects-api/objecttypes/{objects_api_objecttype_uuid}/versions:
get:
operationId: prefill_plugins_objects_api_objecttypes_versions_list
description: List the available prefill objecttype versions for Objects API
plugin.
summary: List available objecttype versions for Objects API
parameters:
- in: query
name: objects_api_group
schema:
type: string
description: Which Objects API group to use.
- in: path
name: objects_api_objecttype_uuid
schema:
type: string
format: uuid
required: true
tags:
- registration
security:
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/ObjecttypeVersion'
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'
? /api/v2/prefill/plugins/objects-api/objecttypes/{objects_api_objecttype_uuid}/versions/{objects_api_objecttype_version}/attributes
: get:
operationId: prefill_plugins_objects_api_objecttypes_versions_attributes_list
description: List the available attributes for Objects API plugin.
summary: List available attributes for Objects API
parameters:
- in: query
name: objects_api_group
schema:
type: string
description: Which Objects API group to use.
- in: path
name: objects_api_objecttype_uuid
schema:
type: string
format: uuid
required: true
- in: path
name: objects_api_objecttype_version
schema:
type: integer
required: true
tags:
- prefill
security:
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/PrefillAttribute'
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'
/api/v2/products:
get:
operationId: products_list
Expand Down
1 change: 1 addition & 0 deletions src/openforms/conf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
23 changes: 22 additions & 1 deletion src/openforms/prefill/api/urls.py
Original file line number Diff line number Diff line change
@@ -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/<uuid:objects_api_objecttype_uuid>/versions",
PluginObjectsAPIObjecttypeVersionListView.as_view(),
name="prefill-objects-api-objecttype-version-list",
),
path(
"plugins/objects-api/objecttypes/<uuid:objects_api_objecttype_uuid>/versions/<int:objects_api_objecttype_version>/attributes",
PluginObjectsAPIAttributesListView.as_view(),
name="prefill-objects-api-objecttype-attribute-list",
),
path("plugins", PluginListView.as_view(), name="prefill-plugin-list"),
path(
"plugins/<slug:plugin>/attributes",
Expand Down
79 changes: 79 additions & 0 deletions src/openforms/prefill/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@
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.api.views import (
OBJECTS_API_GROUP_QUERY_PARAMETER,
ObjecttypesListView,
ObjecttypeVersionsListView,
)
from openforms.registrations.contrib.objects_api.client import get_objecttypes_client

from ..registry import register
from .serializers import (
Expand Down Expand Up @@ -67,3 +76,73 @@ def get_objects(self):
choices = plugin.get_available_attributes()

return [ChoiceWrapper(choice) for choice in choices]


@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(
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(
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 = PrefillAttributeSerializer

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 [ChoiceWrapper(choice) for choice in choices]
7 changes: 6 additions & 1 deletion src/openforms/prefill/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down
3 changes: 3 additions & 0 deletions src/openforms/prefill/contrib/objects_api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
Objects API prefill plugin.
"""
12 changes: 12 additions & 0 deletions src/openforms/prefill/contrib/objects_api/apps.py
Original file line number Diff line number Diff line change
@@ -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
43 changes: 43 additions & 0 deletions src/openforms/prefill/contrib/objects_api/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
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
Empty file.
Loading

0 comments on commit 70f0382

Please sign in to comment.