mirror of
https://github.com/pretix/pretix.git
synced 2026-09-28 18:44:42 +00:00
filter unknown keys from choices due to django-formsets
This commit is contained in:
@@ -643,7 +643,40 @@ class OrganizerSettingsSerializer(SettingsSerializer):
|
||||
return 'pub/' + fname
|
||||
|
||||
|
||||
class KeyLabelObjectListField(serializers.Field):
|
||||
|
||||
def to_representation(self, value):
|
||||
# django added unneccessary keys DELETE, ORDER through formsets, filter them here for backwards compat
|
||||
def strip_unknown_keys(v):
|
||||
return {k: v[k] for k in v.keys() if k in ("key", "label")}
|
||||
return [strip_unknown_keys(v) for v in value]
|
||||
|
||||
def to_internal_value(self, data):
|
||||
if data is None:
|
||||
return data
|
||||
if not isinstance(data, list):
|
||||
raise ValidationError("Choices need to be a list or null.")
|
||||
if not data:
|
||||
# empty list
|
||||
return None
|
||||
|
||||
if any([not isinstance(choice, dict) for choice in data]):
|
||||
raise ValidationError("Choices need to contain only objects.")
|
||||
|
||||
required_keys = {"key"}
|
||||
allowed_keys = {"key", "label"}
|
||||
if not all([required_keys <= set(choice.keys()) <= allowed_keys for choice in data]):
|
||||
raise ValidationError("Each choice must contain a key and optionally a label.")
|
||||
|
||||
choice_keys = [choice.get("key") for choice in data]
|
||||
if len(set(choice_keys)) < len(choice_keys):
|
||||
raise ValidationError("Each choice must have a unique key.")
|
||||
return data
|
||||
|
||||
|
||||
class EventMetaPropertiesSerializer(I18nAwareModelSerializer):
|
||||
choices = KeyLabelObjectListField(allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = EventMetaProperty
|
||||
fields = (
|
||||
@@ -657,26 +690,13 @@ class EventMetaPropertiesSerializer(I18nAwareModelSerializer):
|
||||
full_data.update(data)
|
||||
|
||||
choices = full_data.get("choices")
|
||||
if "choices" in data and data["choices"] is not None:
|
||||
if not isinstance(choices, list):
|
||||
raise ValidationError("Choices need to be a list or null.")
|
||||
if any([not isinstance(c, dict) for c in choices]):
|
||||
raise ValidationError("Choices need to contain only objects.")
|
||||
required_keys = {"key"}
|
||||
allowed_keys = {"key", "label"}
|
||||
if not all([required_keys <= set(c.keys()) <= allowed_keys for c in choices]):
|
||||
raise ValidationError("Each choice must contain a key and optionally a label.")
|
||||
|
||||
if choices:
|
||||
default = full_data.get("default")
|
||||
if choices and default:
|
||||
choice_keys = [c.get("key") for c in choices]
|
||||
if len(set(choice_keys)) < len(choice_keys):
|
||||
raise ValidationError("Each choice must have a unique key.")
|
||||
|
||||
default = full_data.get("default")
|
||||
if default and default not in choice_keys:
|
||||
if default not in choice_keys:
|
||||
raise ValidationError("You cannot set a default value that is not a valid value.")
|
||||
|
||||
if not choices and "choices" in data:
|
||||
# normalize empty dict to None
|
||||
# normalize empty dict to None
|
||||
data["choices"] = None
|
||||
return data
|
||||
|
||||
@@ -29,7 +29,14 @@ def event_meta_property(organizer):
|
||||
name="Color",
|
||||
default="Red",
|
||||
required=False,
|
||||
choices=None,
|
||||
choices=[
|
||||
{
|
||||
"key": "Red",
|
||||
"label": "Rot",
|
||||
"DELETE": False,
|
||||
"ORDER": 1,
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -37,7 +44,7 @@ TEST_TYPE_RES = {
|
||||
"name": "Color",
|
||||
"default": "Red",
|
||||
"required": False,
|
||||
"choices": None,
|
||||
"choices": [{"key": "Red", "label": "Rot"}],
|
||||
'filter_allowed': True,
|
||||
'filter_public': False,
|
||||
'protected': False,
|
||||
@@ -141,6 +148,18 @@ def test_meta_property_patch(token_client, organizer, event_meta_property):
|
||||
}
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/event_meta_properties/{}/'
|
||||
.format(organizer.slug, event_meta_property.pk),
|
||||
format='json',
|
||||
data={
|
||||
"choices": [],
|
||||
}
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
event_meta_property.refresh_from_db()
|
||||
assert event_meta_property.choices is None
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/event_meta_properties/{}/'
|
||||
.format(organizer.slug, event_meta_property.pk),
|
||||
@@ -156,8 +175,6 @@ def test_meta_property_patch(token_client, organizer, event_meta_property):
|
||||
assert event_meta_property.choices is None
|
||||
|
||||
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_meta_property_delete(token_client, organizer, event_meta_property):
|
||||
resp = token_client.delete(
|
||||
|
||||
Reference in New Issue
Block a user