Skip to content

Commit 055644f

Browse files
fix: metadata-feature-changes-erases-existing-value (#5362)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent c5a514d commit 055644f

6 files changed

Lines changed: 104 additions & 10 deletions

File tree

api/environments/serializers.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import typing
2+
from typing import cast
23

34
from common.metadata.serializers import (
45
MetadataSerializer,
56
SerializerWithMetadata,
67
)
8+
from django.db import models
79
from rest_framework import serializers
810

911
from environments.models import Environment, EnvironmentAPIKey, Webhook
@@ -97,6 +99,15 @@ def get_project(
9799
"Unable to retrieve project for metadata validation."
98100
)
99101

102+
def update(
103+
self, instance: models.Model, validated_data: dict[str, typing.Any]
104+
) -> Environment:
105+
metadata_items = validated_data.pop("metadata", [])
106+
environment = cast(Environment, super().update(instance, validated_data))
107+
self.update_metadata(environment, metadata_items)
108+
environment.refresh_from_db()
109+
return environment
110+
100111

101112
class EnvironmentRetrieveSerializerWithMetadata(EnvironmentSerializerWithMetadata):
102113
total_segment_overrides = serializers.IntegerField()

api/features/serializers.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
MetadataSerializer,
1414
SerializerWithMetadata,
1515
)
16+
from django.db import models
1617
from drf_writable_nested import ( # type: ignore[attr-defined]
1718
WritableNestedModelSerializer,
1819
)
@@ -344,6 +345,15 @@ def get_project(
344345
"Unable to retrieve project for metadata validation."
345346
)
346347

348+
def update(
349+
self, instance: models.Model, validated_data: dict[str, typing.Any]
350+
) -> Feature:
351+
metadata_items = validated_data.pop("metadata", [])
352+
feature = typing.cast(Feature, super().update(instance, validated_data))
353+
self.update_metadata(feature, metadata_items)
354+
feature.refresh_from_db()
355+
return feature
356+
347357

348358
class UpdateFeatureSerializerWithMetadata(FeatureSerializerWithMetadata):
349359
"""prevent users from changing certain values after creation"""

api/poetry.lock

Lines changed: 13 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ pygithub = "2.1.1"
160160
hubspot-api-client = "^8.2.1"
161161
djangorestframework-dataclasses = "^1.3.1"
162162
pyotp = "^2.9.0"
163-
flagsmith-common = "^1.12.0"
163+
flagsmith-common = "^1.12.1"
164164
django-stubs = "^5.1.3"
165165
tzdata = "^2024.1"
166166
djangorestframework-simplejwt = "^5.3.1"

api/tests/unit/segments/test_unit_segments_views.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,69 @@ def test_update_segment_delete_existing_rule(project, client, segment, segment_r
11061106
assert segment_rule.conditions.count() == 0
11071107

11081108

1109+
@pytest.mark.parametrize(
1110+
"client",
1111+
[lazy_fixture("admin_master_api_key_client"), lazy_fixture("admin_client")],
1112+
)
1113+
def test_update_segment_metadata_create_correct_number_of_metadata(
1114+
project: Project,
1115+
client: APIClient,
1116+
required_a_segment_metadata_field: MetadataModelField,
1117+
) -> None:
1118+
# Given
1119+
url = reverse("api-v1:projects:project-segments-list", args=[project.id])
1120+
description = "This is the description"
1121+
field_value = 10
1122+
first_segment_data = {
1123+
"name": "Test Segment",
1124+
"description": description,
1125+
"project": project.id,
1126+
"rules": [{"type": "ALL", "rules": [], "conditions": []}],
1127+
"metadata": [
1128+
{
1129+
"model_field": required_a_segment_metadata_field.id,
1130+
"field_value": field_value,
1131+
},
1132+
],
1133+
}
1134+
second_segment_data = {
1135+
"name": "Test Segment",
1136+
"description": description,
1137+
"project": project.id,
1138+
"rules": [{"type": "ALL", "rules": [], "conditions": []}],
1139+
"metadata": [
1140+
{
1141+
"model_field": required_a_segment_metadata_field.id,
1142+
"field_value": field_value,
1143+
},
1144+
],
1145+
}
1146+
1147+
# When
1148+
response_first = client.post(
1149+
url, data=json.dumps(first_segment_data), content_type="application/json"
1150+
)
1151+
response_second = client.post(
1152+
url, data=json.dumps(second_segment_data), content_type="application/json"
1153+
)
1154+
# Then
1155+
assert response_first.status_code == status.HTTP_201_CREATED
1156+
assert response_second.status_code == status.HTTP_201_CREATED
1157+
assert (
1158+
response_first.json()["metadata"][0]["model_field"]
1159+
== required_a_segment_metadata_field.id
1160+
)
1161+
assert (
1162+
response_second.json()["metadata"][0]["model_field"]
1163+
== required_a_segment_metadata_field.id
1164+
)
1165+
1166+
metadata = Metadata.objects.filter(
1167+
model_field=required_a_segment_metadata_field.id
1168+
).all()
1169+
assert metadata.count() == 2
1170+
1171+
11091172
@pytest.mark.parametrize(
11101173
"client",
11111174
[lazy_fixture("admin_master_api_key_client"), lazy_fixture("admin_client")],

api/util/drf_writable_nested/serializers.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from typing import Any
2+
3+
from django.db import models
14
from drf_writable_nested import ( # type: ignore[attr-defined]
25
NestedCreateMixin,
36
NestedUpdateMixin,
@@ -10,7 +13,9 @@ class NestedUpdateMixinDeleteBeforeUpdate(NestedUpdateMixin):
1013
ref: https://github.com/beda-software/drf-writable-nested/issues/158
1114
"""
1215

13-
def update(self, instance, validated_data): # type: ignore[no-untyped-def]
16+
def update(
17+
self, instance: models.Model, validated_data: dict[str, Any]
18+
) -> models.Model:
1419
relations, reverse_relations = self._extract_relations(validated_data) # type: ignore[no-untyped-call]
1520

1621
# Create or update direct relations (foreign key, one-to-one)

0 commit comments

Comments
 (0)