Skip to content

Commit

Permalink
Merge pull request #3594 from open-formulieren/feature/3573-as-json
Browse files Browse the repository at this point in the history
✨ [#3573] Add a new template tag `as_json`
  • Loading branch information
sergei-maertens authored Nov 17, 2023
2 parents 718fbfc + da584b9 commit 141529b
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 6 deletions.
115 changes: 115 additions & 0 deletions docs/manual/forms/examples/form_with_geometry.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
.. _example_form_with_geometry:

================================================
Kaartmateriaal en registratie in de Objecten API
================================================

In dit formulier maken we gebruik van de "Kaart"-component om coördinaten van een
locatie uit te vragen en te registreren. Het formulier wordt gekoppeld met de
`Objecten API`_ voor het registreren van de inzendingsgegevens.

We gaan er van uit dat de koppeling met de Objecten API
:ref:`geconfigureerd <configuration_registration_objects>` is, en gebruiken als
objecttype-URL ``https://objecttype-example.nl/api/v2/objecttype/123``.

Formulier maken
===============

We bouwen een formulier met twee kaarten - één kaart wordt gebruikt voor "dé" geometrie
van het hele Object in de Objecten API en de andere kaart wordt als extra/vrije-vorm
attribuut meegestuurd.

#. Maak een formulier aan met de volgende gegevens:

* **Naam**: Kaartgegevens registreren in de Objecten API

#. Klik op het tabblad **Stappen en velden**.
#. Klik aan de linkerkant op **Stap toevoegen** en selecteer **Maak een nieuwe
formulierdefinitie**.
#. Onder de sectie **(Herbruikbare) stapgegevens** vul het volgende in:

* **Naam**: Kaarten

#. Scrol naar beneden en klik de sectie **Speciale velden** aan.
#. Sleep een **Kaart** component op het witte vlak en vul de volgende
gegevens in:

* **Label**: Hoofdgeometrie

#. Klik vervolgens de **Registratie** tab aan en vul de volgende gegevens in:

* **Registratie-attribuut**: Locatie > Coördinaten

#. Druk daarna op **Opslaan**.

#. Sleep een tweede **Kaart** component op het witte vlak, vul de volgende
gegevens in en druk daarna op **Opslaan**:

* **Label**: Extra geometrie

#. Klik op het tabblad **Registratie**.
#. Klik op **Registratiepluginoptie toevoegen** en vul de volgende gegevens in:

* **Naam**: Objecten API
* **Registratiemethode**: Objecten API registratie
* **Objecttype**: ``https://objecttype-example.nl/api/v2/objecttype/123``
* **JSON-inhoud sjabloon**:

.. code-block:: django
{
"extraGeometrie": {% as_geo_json variables.extraGeometrie %}
}
#. Druk daarna op **Opslaan en opnieuw bewerken**. Het formulier kan nu ingevuld en
ingestuurd worden.


.. note:: Het inrichten van het Objecttype en de Objecten API is geen onderdeel van
dit voorbeeld, maar wel essentieel om zonder fouten formulierinzendingen te kunnen
verwerken.


Toelichting
===========

De eerste kaart is ingesteld via de "Registratie" tab op het component. Dit zorgt ervoor
dat de Objecten API-registratieplugin dit veld gebruikt voor "de" geometrie van het object
in de Objecten API. Deze kent hiervoor namelijk één vast attribuut.

Echter, we kunnen extra geometrieën alsnog meesturen (als het objecttype dit modelleert),
dit doen we door het als ``GeoJSON`` te formatteren met de ``{% as_geo_json ... %}``
sjablooncode.

.. note:: Het is niet de bedoeling dat meerdere kaarten via de "Registratie" tab gekoppeld
worden aan het Locatie-attribuut - als je dit wel doet, dan zal er slechts één component
meegestuurd worden.

Het resulterende object wat naar de Objecten API gestuurd wordt ziet er uit als:

.. code-block:: json
{
"type": "https://objecttype-example.nl/api/v2/objecttype/123",
"record": {
"typeVersion": "1",
"data": {
"extraGeometrie": {
"type": "Point",
"coordinates": [52.37403, 4.88969]
}
},
"startAt": "2023-01-01",
"geometry": {
"type": "Point",
"coordinates": [51.9225, 4.47917]
}
}
}
.. seealso::

De :ref:`sjabloondocumentatie <manual_templates>` heeft een referentie van beschikbare
template tags, met details voor de :ref:`objecten_api_registratie`.

.. _Objecten API: https://objects-and-objecttypes-api.readthedocs.io/
1 change: 1 addition & 0 deletions docs/manual/forms/examples/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Voorbeelden
dynamic_options_3
service_fetch
suwinet
form_with_geometry

======================
Verouderde voorbeelden
Expand Down
5 changes: 5 additions & 0 deletions docs/manual/templates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ Voorbeeld
Mede-ondertekend door: N. Doe (BSN: 123456789)
.. _objecten_api_registratie:

Objecten API registratie
========================
Expand All @@ -471,6 +472,9 @@ alle gegevens uit het formulier en de waarden ingevuld door de gebruiker.
``{{ voornaam }}``. Echter, in de sjablonen voor de Objecten API dient u deze als ``variables.<variabele>`` te refereren,
bijvoorbeeld ``{{ variables.voornaam }}``. Dit zal in de toekomst voor alle sjablonen gelden.
.. seealso ::
See :ref:`example_form_with_geometry` for a more detailed example.
**Speciale instructies**

Expand All @@ -489,6 +493,7 @@ Variabele Beschrijving
``{{ submission.csv_url }}`` De URL van het inzendingsrapport (in CSV formaat) in de documenten API. Dit document is mogelijk niet aangemaakt
``{% json_summary %}`` JSON met ``"<variabele-eigenschapsnaam>": "<waarde>"`` van alle formuliervelden.
``{% uploaded_attachment_urls %}`` Een lijst met de URLs van documenten toegevoegd door de inzender. De URLs verwijzen naar het geregistreerde document in de Documenten API.
``{% as_geo_json variables.map %}`` Sluit de gerefereerde variabele (`variables.map`) in als JSON.
===================================== ===========================================================================


Expand Down
1 change: 1 addition & 0 deletions src/openforms/forms/models/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class Form(models.Model):
product = models.ForeignKey(
"products.Product", null=True, blank=True, on_delete=models.CASCADE
)

category = models.ForeignKey(
"forms.Category", null=True, blank=True, on_delete=models.PROTECT
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,40 @@


@register.simple_tag(takes_context=True)
def uploaded_attachment_urls(context):
def uploaded_attachment_urls(context: template.Context) -> SafeString:
"""
Output a sequence of attachment URLs as a JSON-serialized list.
"""
# attachments is a list of URLs
attachments = context.get("submission", {}).get("uploaded_attachment_urls", [])
return SafeString(json.dumps(attachments))


@register.simple_tag(takes_context=True)
def json_summary(context):
def json_summary(context: template.Context) -> SafeString:
submission = context.get("_submission")
if not submission:
return {}

json_data = render_json(submission)
json_data = render_json(submission) if submission else {}

if settings.ESCAPE_REGISTRATION_OUTPUT:
json_data = html_escape_json(json_data)

return SafeString(json.dumps(json_data))


@register.simple_tag
def as_geo_json(value: list[float] | str) -> SafeString:
"""Output the ``value`` as a safe GeoJSON dumped string.
As of today, this only supports coordinates. This essentially does the same thing as
:func:`_transform_coordinates`, but for any map component.
"""
data = (
{
"type": "Point",
"coordinates": [value[0], value[1]],
}
if value
else {}
)

return SafeString(json.dumps(data))
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,29 @@ def test_render_json_summary_no_submission(self):
)

self.assertEqual(rendered, "{}")


class AsGeoJsonTests(TestCase):
def test_render_as_geo_json(self):
rendered = render_from_string(
"{% as_geo_json variables.0.value %}",
context={"variables": [{"value": [1.0, 2.0]}]},
backend=openforms_backend,
disable_autoescape=True,
)

expected = '{"type": "Point", "coordinates": [1.0, 2.0]}'

self.assertEqual(rendered, expected)

def test_render_as_geo_json_no_value(self):
rendered = render_from_string(
"{% as_geo_json variables.0.value %}",
context={"variables": [{"value": ""}]},
backend=openforms_backend,
disable_autoescape=True,
)

expected = "{}"

self.assertEqual(rendered, expected)

0 comments on commit 141529b

Please sign in to comment.