Skip to content

Commit

Permalink
[#4396] First attempt to implement objects_api prefill plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
vaszig committed Jul 26, 2024
1 parent 08f946d commit 5ea6f6c
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 1 deletion.
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
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
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
2 changes: 1 addition & 1 deletion src/openforms/prefill/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def invoke_plugin(
plugin = register[plugin_id]
if not plugin.is_enabled:
raise PluginNotEnabled()

breakpoint()
try:
values = plugin.get_prefill_values(submission, fields, identifier_role)
except Exception as e:
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
19 changes: 19 additions & 0 deletions src/openforms/prefill/contrib/objects_api/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from django.db import models
from django.utils.translation import gettext_lazy as _


class ObjectsAPIAttributes(models.TextChoices):
url = "url", _("Url")
uuid = "uuid", _("UUID")
type = "type", _("Type")
record_index = "record.index", _("Record > Index")
record_typeVersion = "record.typeVersion", _("Record > Type version")

record_data_ = "", _("Record > Data")

record_geometry = "record.geometry", _("Record > Geometry")
record_startAt = "record.startAt", _("Record > Start at")
record_endAt = "record.endAt", _("Record > End at")
record_registrationAt = "record.registrationAt", _("Record > Registration at")
record_correctionFor = "record.correctionFor", _("Record > Correction for")
record_correctedBy = "record_correctedBy", _("Record > Corrected by")
108 changes: 108 additions & 0 deletions src/openforms/prefill/contrib/objects_api/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import logging
from typing import Any, Iterable

from click import option
from django.urls import reverse
from django.utils.translation import gettext_lazy as _

from glom import GlomError, glom

from openforms.authentication.service import AuthAttribute
from openforms.registrations.contrib.objects_api.client import (
get_objects_client,
get_objecttypes_client,
)
from openforms.registrations.contrib.objects_api.models import ObjectsAPIGroupConfig
from openforms.submissions.models import Submission
from openforms.typing import JSONEncodable
from ...base import BasePlugin
from ...constants import IdentifierRoles
from ...registry import register
from .constants import ObjectsAPIAttributes

logger = logging.getLogger(__name__)

PLUGIN_IDENTIFIER = "objects_api"


@register(PLUGIN_IDENTIFIER)
class ObjectsAPIPrefill(BasePlugin):
verbose_name = _("Objects API")
requires_auth = AuthAttribute.bsn

@classmethod
def parse_schema_properties(
cls, schema, parent_key: str = ""
) -> list[tuple[str, str]]:
properties = []

if schema["type"] == "object":
for prop, prop_schema in schema.get("properties", {}).items():
full_key = f"{parent_key}.{prop}" if parent_key else prop
prop_type = prop_schema.get("type", "unknown")
properties.append((full_key, prop_type))
if prop_type == "object" or (
prop_type == "array" and "items" in prop_schema
):
properties.extend(
cls.parse_schema_properties(prop_schema, full_key)
)
elif schema["type"] == "array":
items_schema = schema.get("items", {})
if isinstance(items_schema, dict):
properties.extend(
cls.parse_schema_properties(items_schema, f"{parent_key}[]")
)
elif isinstance(items_schema, list):
for i, item_schema in enumerate(items_schema):
properties.extend(
cls.parse_schema_properties(item_schema, f"{parent_key}[{i}]")
)
else:
properties.append((parent_key, schema["type"]))

return properties

@staticmethod
def get_available_attributes() -> Iterable[tuple[str, str]]:
# attrs = ObjectsAPIAttributes.choices
# attrs += dynamic_properties
pass

@classmethod
def get_prefill_values(
cls,
submission: Submission,
attributes: list[str],
identifier_role: IdentifierRoles = IdentifierRoles.main,
) -> dict[str, JSONEncodable]:
# for testing purposes, this will be defined in the modal by the user
# frontend is not ready yet
options = submission.registration_backend.options
config = ObjectsAPIGroupConfig.objects.get(pk=options["objects_api_group"])

if object_uuid := submission.initial_data_reference:
with get_objecttypes_client(config) as objecttypes_client:
objecttype = objecttypes_client.get_objecttype_version(
options["objecttype"], options["objecttype_version"]
)

if objecttype["status"] != "published":
logger.warning(
"object type '%s' is not published yet", objecttype["url"]
)
return {}

if json_schema := objecttype.get("jsonSchema"):
properties = cls.parse_schema_properties(json_schema)

return {}

@classmethod
def get_co_sign_values(
cls, submission: Submission, identifier: str
) -> tuple[dict[str, Any], str]:
pass

def check_config(self):
pass
6 changes: 6 additions & 0 deletions src/openforms/submissions/models/submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,12 @@ class Meta:
),
]

# for testing purposes-need the initial_data_reference
# should be removed
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.initial_data_reference = "ac1fa3f8-fb2a-4fcb-b715-d480aceeda10"

def __str__(self):
return _("{pk} - started on {started}").format(
pk=self.pk or _("(unsaved)"),
Expand Down

0 comments on commit 5ea6f6c

Please sign in to comment.