Skip to content

Commit

Permalink
🚧 [#4993] Implement fetching select(boxes) options from Referentielij…
Browse files Browse the repository at this point in the history
…sten

this was previously possible with logic and service fetch, but this functionality provides a shortcut to more easily integrate with Referentielijsten API
  • Loading branch information
stevenbal committed Jan 13, 2025
1 parent e59012c commit dcfd7f8
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 17 deletions.
25 changes: 19 additions & 6 deletions src/openforms/formio/dynamic_config/dynamic_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from openforms.typing import DataMapping, JSONValue

from ..typing import Component
from .referentielijsten import fetch_options_from_referentielijsten


def normalise_option(option: JSONValue) -> JSONValue:
Expand Down Expand Up @@ -46,12 +47,24 @@ def add_options_to_config(
submission: Submission,
options_path: str = "values",
) -> None:
if glom(component, "openForms.dataSrc", default=None) != "variable":
return

items_expression = glom(component, "openForms.itemsExpression")
items_array = jsonLogic(items_expression, data)
if not items_array:
data_src = glom(component, "openForms.dataSrc", default=None)
# TODO make these constants/choices?
# TODO move the logic to a separate app?
if data_src == "referentielijsten":
items_expression = {
"map": [{"var": "results"}, [{"var": "code"}, {"var": "naam"}]]
}
items_array = fetch_options_from_referentielijsten(
component, data, submission, items_expression
)
if not items_array:
return
elif data_src == "variable":
items_expression = glom(component, "openForms.itemsExpression")
items_array = jsonLogic(items_expression, data)
if not items_array:
return
else:
return

if not isinstance(items_array, list):
Expand Down
86 changes: 86 additions & 0 deletions src/openforms/formio/dynamic_config/referentielijsten.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from django.utils.translation import gettext as _

from ape_pie import APIClient
from glom import glom
from json_logic import jsonLogic
from requests.exceptions import RequestException
from zgw_consumers.client import build_client
from zgw_consumers.models import Service

from openforms.logging import logevent
from openforms.submissions.models import Submission
from openforms.typing import DataMapping, JSONObject

from ..typing import Component


class ReferentielijstenClient(APIClient):
# TODO cache this
def get_items_for_tabel(self, code):
response = self.get("items", params={"tabel__code": code}, timeout=10)
response.raise_for_status()
return response.json()


def fetch_options_from_referentielijsten(
component: Component,
data: DataMapping,
submission: Submission,
items_expression: JSONObject,
):
service_slug = glom(component, "openForms.service", default=None)
code = glom(component, "openForms.code", default=None)
if not service_slug:
logevent.form_configuration_error(
submission.form,
component,
_(
"Cannot fetch from Referentielijsten API, because no `service` is configured."
),
)
return

if not code:
logevent.form_configuration_error(
submission.form,
component,
_(
"Cannot fetch from Referentielijsten API, because no `code` is configured."
),
)
return

# TODO also check if service is part of `referentielijsten_services`?
try:
service = Service.objects.get(slug=service_slug)
except Service.DoesNotExist:
logevent.form_configuration_error(
submission.form,
component,
_(
"Cannot fetch from Referentielijsten API, service with {service_slug} does not exist."
).format(service_slug=service_slug),
)
return

try:
with build_client(service, client_factory=ReferentielijstenClient) as client:
result = client.get_items_for_tabel(code)
except RequestException as e:
logevent.referentielijsten_failure_response(
submission.form,
component,
_(
"Exception occurred while fetching from Referentielijsten API: {exception}."
).format(exception=e),
)
return
else:
# TODO handle non success cases
if not (items_array := jsonLogic(items_expression, result)):
logevent.referentielijsten_failure_response(
submission.form,
component,
_("No results found from Referentielijsten API."),
)
return items_array
7 changes: 6 additions & 1 deletion src/openforms/submissions/logic/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,12 @@ def eval(
) -> DataMapping:
var = self.rule.form.formvariable_set.get(key=self.variable)
with log_errors({}, self.rule): # TODO proper error handling
result = perform_service_fetch(var, context, str(submission.uuid))
if not (fetch_config := var.service_fetch_configuration):
raise ValueError(
f"Can't perform service fetch on {var}. "
"It needs a service_fetch_configuration."
)
result = perform_service_fetch(fetch_config, context, str(submission.uuid))
return {var.key: result.value}


Expand Down
13 changes: 3 additions & 10 deletions src/openforms/submissions/logic/service_fetching.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from json_logic import jsonLogic
from zgw_consumers.client import build_client

from openforms.forms.models import FormVariable
from openforms.typing import DataMapping, JSONObject, JSONValue
from openforms.variables.models import DataMappingTypes, ServiceFetchConfiguration

Expand All @@ -24,7 +23,9 @@ class FetchResult:


def perform_service_fetch(
var: FormVariable, context: DataMapping, submission_uuid: str = ""
fetch_config: ServiceFetchConfiguration,
context: DataMapping,
submission_uuid: str = "",
) -> FetchResult:
"""Fetch a value from a http-service, perform a transformation on it and
return the result.
Expand All @@ -39,14 +40,6 @@ def perform_service_fetch(
The value returned by the request is cached using the submission UUID and the
arguments to the request (hashed to make a cache key).
"""

if not var.service_fetch_configuration:
raise ValueError(
f"Can't perform service fetch on {var}. "
"It needs a service_fetch_configuration."
)
fetch_config: ServiceFetchConfiguration = var.service_fetch_configuration

client = build_client(fetch_config.service)
request_args = fetch_config.request_arguments(context)

Expand Down

0 comments on commit dcfd7f8

Please sign in to comment.