Skip to content

Commit

Permalink
[#4396] Added prefill_options field to the form variable
Browse files Browse the repository at this point in the history
  • Loading branch information
vaszig committed Oct 24, 2024
1 parent 683efe7 commit 10cbf77
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8564,6 +8564,7 @@ components:
* `main` - Main
* `authorizee` - Authorizee
prefillOptions: {}
dataType:
allOf:
- $ref: '#/components/schemas/DataTypeEnum'
Expand Down
2 changes: 2 additions & 0 deletions src/openforms/forms/admin/form_variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class FormVariableAdmin(admin.ModelAdmin):
"prefill_plugin",
"prefill_attribute",
"prefill_identifier_role",
"prefill_options",
"data_type",
"is_sensitive_data",
"initial_value",
Expand All @@ -31,6 +32,7 @@ class FormVariableAdmin(admin.ModelAdmin):
"prefill_plugin",
"prefill_attribute",
"prefill_identifier_role",
"prefill_options",
"data_type",
"data_format",
"is_sensitive_data",
Expand Down
37 changes: 36 additions & 1 deletion src/openforms/forms/api/serializers/form_variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from openforms.api.fields import RelatedFieldFromContext
from openforms.api.serializers import ListWithChildSerializer
from openforms.prefill.registry import register
from openforms.variables.api.serializers import ServiceFetchConfigurationSerializer
from openforms.variables.constants import FormVariableSources
from openforms.variables.models import ServiceFetchConfiguration
Expand Down Expand Up @@ -110,6 +111,7 @@ class FormVariableSerializer(serializers.HyperlinkedModelSerializer):
service_fetch_configuration = ServiceFetchConfigurationSerializer(
required=False, allow_null=True
)
prefill_options = serializers.JSONField(required=False)

class Meta:
model = FormVariable
Expand All @@ -124,6 +126,7 @@ class Meta:
"prefill_plugin",
"prefill_attribute",
"prefill_identifier_role",
"prefill_options",
"data_type",
"data_format",
"is_sensitive_data",
Expand Down Expand Up @@ -177,9 +180,31 @@ def validate(self, attrs):
}
)

# prefill plugin and attribute must both or both not be set
# Check the combination of the provided prefill-attributes (see the model constraints)
source = attrs.get("source") or ""
prefill_plugin = attrs.get("prefill_plugin") or ""
prefill_attribute = attrs.get("prefill_attribute") or ""
prefill_options = attrs.get("prefill_options")

if prefill_plugin and prefill_options and prefill_attribute:
raise ValidationError(
{
"prefill_attribute": _(
"Prefill plugin, attribute and options can not be specified at the same time."
),
}
)

if prefill_options:
if source == FormVariableSources.component:
raise ValidationError(
{
"prefill_options": _(
"Prefill options should not be specified for component variables."
),
}
)

if (prefill_plugin and not prefill_attribute) or (
not prefill_plugin and prefill_attribute
):
Expand All @@ -191,4 +216,14 @@ def validate(self, attrs):
}
)

# check the specific validation options of the prefill plugin
if prefill_plugin and prefill_options:
plugin = register[prefill_plugin]
serializer = plugin.options(data=prefill_options)
try:
serializer.is_valid(raise_exception=True)
except serializers.ValidationError as e:
detail = {"prefill_options": e.detail}
raise serializers.ValidationError(detail) from e

return attrs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Generated by Django 4.2.16 on 2024-10-23 11:50

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("forms", "0102_merge_20241022_1143"),
]

operations = [
migrations.RemoveConstraint(
model_name="formvariable",
name="prefill_config_empty_or_complete",
),
migrations.AddField(
model_name="formvariable",
name="prefill_options",
field=models.JSONField(
blank=True, default=dict, verbose_name="prefill options"
),
),
migrations.AddConstraint(
model_name="formvariable",
constraint=models.CheckConstraint(
check=models.Q(
models.Q(
models.Q(
("prefill_plugin", ""),
("prefill_attribute", ""),
("prefill_options", {}),
),
models.Q(
models.Q(("prefill_plugin", ""), _negated=True),
("prefill_attribute", ""),
models.Q(("prefill_options", {}), _negated=True),
("source", "user_defined"),
),
models.Q(
models.Q(("prefill_plugin", ""), _negated=True),
models.Q(("prefill_attribute", ""), _negated=True),
("prefill_options", {}),
),
_connector="OR",
)
),
name="prefill_config_component_or_user_defined",
),
),
]
31 changes: 28 additions & 3 deletions src/openforms/forms/models/form_variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
from .form_step import FormStep


EMPTY_PREFILL_PLUGIN = Q(prefill_plugin="")
EMPTY_PREFILL_ATTRIBUTE = Q(prefill_attribute="")
EMPTY_PREFILL_OPTIONS = Q(prefill_options={})
USER_DEFINED = Q(source=FormVariableSources.user_defined)


class FormVariableManager(models.Manager):
use_in_migrations = True

Expand Down Expand Up @@ -161,6 +167,11 @@ class FormVariable(models.Model):
default=IdentifierRoles.main,
max_length=100,
)
prefill_options = models.JSONField(
_("prefill options"),
default=dict,
blank=True,
)
data_type = models.CharField(
verbose_name=_("data type"),
help_text=_("The type of the value that will be associated with this variable"),
Expand Down Expand Up @@ -197,10 +208,24 @@ class Meta:
constraints = [
CheckConstraint(
check=Q(
(Q(prefill_plugin="") & Q(prefill_attribute=""))
| (~Q(prefill_plugin="") & ~Q(prefill_attribute=""))
(
EMPTY_PREFILL_PLUGIN
& EMPTY_PREFILL_ATTRIBUTE
& EMPTY_PREFILL_OPTIONS
)
| (
~EMPTY_PREFILL_PLUGIN
& EMPTY_PREFILL_ATTRIBUTE
& ~EMPTY_PREFILL_OPTIONS
& USER_DEFINED
)
| (
~EMPTY_PREFILL_PLUGIN
& ~EMPTY_PREFILL_ATTRIBUTE
& EMPTY_PREFILL_OPTIONS
)
),
name="prefill_config_empty_or_complete",
name="prefill_config_component_or_user_defined",
),
CheckConstraint(
check=~Q(
Expand Down
78 changes: 73 additions & 5 deletions src/openforms/forms/tests/variables/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,85 @@
from openforms.variables.constants import FormVariableDataTypes, FormVariableSources
from openforms.variables.tests.factories import ServiceFetchConfigurationFactory

from ..factories import FormFactory, FormVariableFactory
from ..factories import FormFactory, FormStepFactory, FormVariableFactory


class FormVariableModelTests(TestCase):
def test_prefill_plugin_empty_prefill_attribute_filled(self):
# valid cases (constraint: prefill_config_component_or_user_defined)
def test_prefill_plugin_prefill_attribute_prefill_options_empty(self):
# user defined
FormVariableFactory.create(
prefill_plugin="",
prefill_attribute="",
prefill_options={},
)
# component
FormStepFactory.create(
form_definition__configuration={
"components": [
{
"type": "textfield",
"key": "test-key",
"label": "Test label",
"prefill": {"plugin": "", "attribute": ""},
}
]
}
)

def test_prefill_options_empty(self):
FormVariableFactory.create(
prefill_plugin="demo",
prefill_attribute="demo",
prefill_options={},
)

def test_prefill_attribute_empty(self):
FormVariableFactory.create(
prefill_plugin="demo",
prefill_attribute="",
prefill_options={"variables_mapping": [{"variable_key": "data"}]},
)

# invalid cases (constraint: prefill_config_component_or_user_defined)
def test_prefill_plugin_prefill_attribute_empty(self):
with self.assertRaises(IntegrityError):
FormVariableFactory.create(prefill_plugin="", prefill_attribute="demo")
FormVariableFactory.create(
prefill_plugin="",
prefill_attribute="",
prefill_options={"variables_mapping": [{"variable_key": "data"}]},
)

def test_prefill_plugin_filled_prefill_attribute_empty(self):
def test_prefill_plugin_prefill_options_empty(self):
with self.assertRaises(IntegrityError):
FormVariableFactory.create(prefill_plugin="demo", prefill_attribute="")
FormVariableFactory.create(
prefill_plugin="",
prefill_attribute="demo",
prefill_options={},
)

def test_prefill_plugin_prefill_attribute_prefill_options_not_empty(self):
with self.assertRaises(IntegrityError):
FormVariableFactory.create(
prefill_plugin="demo",
prefill_attribute="demo",
prefill_options={"variables_mapping": [{"variable_key": "data"}]},
)

def test_prefill_attribute_prefill_options_empty(self):
with self.assertRaises(IntegrityError):
FormStepFactory.create(
form_definition__configuration={
"components": [
{
"type": "textfield",
"key": "test-key",
"label": "Test label",
"prefill": {"plugin": "demo", "attribute": ""},
}
]
}
)

def test_valid_prefill_plugin_config(self):
try:
Expand Down

0 comments on commit 10cbf77

Please sign in to comment.