Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add logic for the new registration (static) variables #3984

Merged
merged 11 commits into from
Mar 14, 2024
47 changes: 45 additions & 2 deletions src/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5619,11 +5619,54 @@ paths:
$ref: '#/components/headers/X-Is-Form-Designer'
Content-Language:
$ref: '#/components/headers/Content-Language'
/api/v2/variables/registration:
get:
operationId: variables_registration_list
description: List the registration static variables that will be associated
with every form
summary: Get registration static variables
tags:
- variables
security:
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/FormVariable'
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'
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/Exception'
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/variables/static:
get:
operationId: variables_static_list
description: List the static data that will be associated with every form
summary: Get static data
description: List the static variables that will be associated with every form
summary: Get static variables
tags:
- variables
security:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ def test_static_variable_in_trigger(self):

self.client.force_authenticate(user=user)
url = reverse("api:form-logic-rules", kwargs={"uuid_or_slug": form.uuid})
with patch("openforms.variables.service.register", new=register):
with patch(
"openforms.variables.service.static_variables_registry", new=register
):
response = self.client.put(url, data=form_logic_data)

self.assertEqual(status.HTTP_200_OK, response.status_code)
18 changes: 13 additions & 5 deletions src/openforms/registrations/base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import TYPE_CHECKING
Expand All @@ -8,8 +10,10 @@
from openforms.utils.mixins import JsonSchemaSerializerMixin

if TYPE_CHECKING:
from openforms.forms.models import FormVariable
from openforms.submissions.models import Submission


SerializerCls = type[serializers.Serializer]


Expand Down Expand Up @@ -42,16 +46,14 @@ class BasePlugin(ABC, AbstractBasePlugin):
"""

@abstractmethod
def register_submission(
self, submission: "Submission", options: dict
) -> dict | None:
def register_submission(self, submission: Submission, options: dict) -> dict | None:
raise NotImplementedError()

def update_payment_status(self, submission: "Submission", options: dict):
def update_payment_status(self, submission: Submission, options: dict):
raise NotImplementedError()

def pre_register_submission(
self, submission: "Submission", options: dict
self, submission: Submission, options: dict
) -> PreRegistrationResult:
"""Perform any tasks before registering the submission

Expand All @@ -65,3 +67,9 @@ def get_custom_templatetags_libraries(self) -> list[str]:
Return a list of custom templatetags libraries that will be added to the 'sandboxed' Django templates backend.
"""
return []

def get_variables(self) -> list[FormVariable]:
"""
Return the static variables for this registration plugin.
"""
return []
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Generated by Django 4.2.10 on 2024-03-13 10:39

import django.contrib.postgres.fields
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("submissions", "0004_auto_20231128_1536"),
("registrations_objects_api", "0012_fill_required_fields"),
]

operations = [
migrations.CreateModel(
name="ObjectsAPIRegistrationData",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"pdf_url",
models.URLField(
blank=True,
help_text="The PDF URL of the document on the Documents API.",
verbose_name="pdf url",
),
),
(
"csv_url",
models.URLField(
blank=True,
help_text="The CSV URL of the document on the Documents API.",
verbose_name="csv url",
),
),
(
"attachment_urls",
django.contrib.postgres.fields.ArrayField(
base_field=models.URLField(
help_text="The attachment URL on the Documents API.",
verbose_name="attachment url",
),
blank=True,
default=list,
help_text="The list of attachment URLs on the Documents API.",
size=None,
verbose_name="attachment urls",
),
),
(
"submission",
models.OneToOneField(
help_text="The submission linked to the registration data.",
on_delete=django.db.models.deletion.CASCADE,
related_name="objects_api_registration_data",
to="submissions.submission",
verbose_name="submission",
),
),
],
),
]
36 changes: 36 additions & 0 deletions src/openforms/registrations/contrib/objects_api/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.contrib.postgres.fields import ArrayField
from django.core.exceptions import ValidationError
from django.db import models
from django.template.loader import render_to_string
Expand Down Expand Up @@ -195,3 +196,38 @@ def apply_defaults_to(self, options):
options["payment_status_update_json"] = self.payment_status_update_json

options.setdefault("auteur", "Aanvrager")


class ObjectsAPIRegistrationData(models.Model):
"""Holds the temporary data available when registering a submission to the Objects API.

When starting the submission registration, this model is first populated. The Objects API
registration variables can then safely make use of this model to provide their data.
"""

submission = models.OneToOneField(
"submissions.Submission",
on_delete=models.CASCADE,
verbose_name=_("submission"),
help_text=_("The submission linked to the registration data."),
related_name="objects_api_registration_data",
)
pdf_url = models.URLField(
_("pdf url"),
help_text=_("The PDF URL of the document on the Documents API."),
blank=True,
)
csv_url = models.URLField(
_("csv url"),
help_text=_("The CSV URL of the document on the Documents API."),
blank=True,
)
attachment_urls = ArrayField(
models.URLField(
_("attachment url"), help_text=_("The attachment URL on the Documents API.")
),
verbose_name=_("attachment urls"),
help_text=_("The list of attachment URLs on the Documents API."),
blank=True,
default=list,
)
Comment on lines +225 to +233
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is too naive, you lose the information of which file/component the Document URL belongs too.

I'd still prefer to have the variable of a file upload explicitly mapped into the schema, e.g. something like:

type: object
properties:
  proofOfEmployment:
    type: string
    format: uri
  bankStatements:
    type: array
    items:
        type: string
        format: uri

so that you can make the (single) file upload "proof of employment" to /proofOfEmployment and the multi-file upload "bank statements" to /bankStatements

Possibly we do this in a separate PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering this requires thinking and probably some work, it will probably be part of the next PR

18 changes: 16 additions & 2 deletions src/openforms/registrations/contrib/objects_api/plugin.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
from __future__ import annotations

import logging
from functools import partial
from typing import Any
from typing import TYPE_CHECKING, Any

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

from typing_extensions import override

from openforms.registrations.utils import execute_unless_result_exists
from openforms.submissions.models import Submission
from openforms.utils.date import get_today
from openforms.variables.service import get_static_variables

from ...base import BasePlugin
from ...registry import register
from .checks import check_config
from .client import get_objects_client
from .config import ObjectsAPIOptionsSerializer
from .models import ObjectsAPIConfig
from .registration_variables import register as variables_registry
from .submission_registration import HANDLER_MAPPING
from .typing import RegistrationOptions

if TYPE_CHECKING:
from openforms.forms.models import FormVariable
from openforms.submissions.models import Submission


PLUGIN_IDENTIFIER = "objects_api"

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -58,6 +66,8 @@ def register_submission(

handler = HANDLER_MAPPING[options["version"]]

handler.save_registration_data(submission, options)

object_data = handler.get_object_data(
submission=submission,
options=options,
Expand Down Expand Up @@ -129,3 +139,7 @@ def update_payment_status(
headers={"Content-Crs": "EPSG:4326"},
)
response.raise_for_status()

@override
def get_variables(self) -> list[FormVariable]:
return get_static_variables(variables_registry=variables_registry)
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from django.utils.translation import gettext_lazy as _

from openforms.plugins.registry import BaseRegistry
from openforms.variables.base import BaseStaticVariable
from openforms.variables.constants import FormVariableDataTypes

if TYPE_CHECKING:
from openforms.submissions.models import Submission


class Registry(BaseRegistry[BaseStaticVariable]):
"""
A registry for the Objects API registration variables.
"""

module = "objects_api"


register = Registry()
"""The Objects API registration variables registry."""


@register("pdf_url")
class PdfUrl(BaseStaticVariable):
name = _("PDF Url")
data_type = FormVariableDataTypes.string

def get_initial_value(self, submission: Submission | None = None):
if submission is None:
return None
return submission.objects_api_registration_data.pdf_url


@register("csv_url")
class CsvUrl(BaseStaticVariable):
name = _("CSV Url")
data_type = FormVariableDataTypes.string

def get_initial_value(self, submission: Submission | None = None):
if submission is None:
return None
return submission.objects_api_registration_data.csv_url


@register("attachment_urls")
class AttachmentUrls(BaseStaticVariable):
name = _("Attachment Urls")
data_type = FormVariableDataTypes.array

def get_initial_value(self, submission: Submission | None = None):
if submission is None:
return None
return submission.objects_api_registration_data.attachment_urls


@register("payment_completed")
class PaymentCompleted(BaseStaticVariable):
name = _("Payment completed")
data_type = FormVariableDataTypes.boolean

def get_initial_value(self, submission: Submission | None = None):
if submission is None:
return None
return submission.payment_user_has_paid


@register("payment_amount")
class PaymentAmount(BaseStaticVariable):
name = _("Payment amount")
data_type = FormVariableDataTypes.string

def get_initial_value(self, submission: Submission | None = None):
if submission is None:
return None
return str(submission.payments.sum_amount())


@register("payment_public_order_ids")
class PaymentPublicOrderIds(BaseStaticVariable):
name = _("Payment public order IDs")
data_type = FormVariableDataTypes.array

def get_initial_value(self, submission: Submission | None = None):
if submission is None:
return None
return submission.payments.get_completed_public_order_ids()
Loading
Loading