diff --git a/api/poetry.lock b/api/poetry.lock index f531559897a8..1e742a5750b7 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1362,8 +1362,8 @@ flagsmith-flag-engine = "*" [package.source] type = "git" url = "https://github.com/Flagsmith/flagsmith-common" -reference = "v1.2.0" -resolved_reference = "ccb6c0603168c91cfb8f9f24bdfa21741eb5916e" +reference = "v1.3.0" +resolved_reference = "d36be973b6dd38c4b0d752c8c023478bbc57756c" [[package]] name = "flagsmith-flag-engine" @@ -4060,14 +4060,14 @@ develop = false [package.dependencies] djangorestframework = "*" djangorestframework-recursive = "*" -flagsmith-common = {git = "https://github.com/Flagsmith/flagsmith-common", tag = "v1.2.0"} +flagsmith-common = {git = "https://github.com/Flagsmith/flagsmith-common", tag = "v1.3.0"} flagsmith-flag-engine = "*" [package.source] type = "git" url = "https://github.com/flagsmith/flagsmith-workflows" -reference = "v2.7.0" -resolved_reference = "3bd546a451e7f2359aa9787ec8ffa5e4315d12cf" +reference = "v2.7.1" +resolved_reference = "83fec3e21752a1dadc2fde87bf9e11ddcda33ed9" [[package]] name = "wrapt" @@ -4186,4 +4186,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.11, <3.13" -content-hash = "487ea7b46f083a1be71662f027a0b170c60e5aa4e35d083224ad4cd4697ec7d1" +content-hash = "4c7b0065fcd2a98b5091c6b5546d8355b693b0b4a766bfe1beae4364bf223e85" diff --git a/api/pyproject.toml b/api/pyproject.toml index 28cff6880c0b..4a9cc6aa0850 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -170,7 +170,7 @@ hubspot-api-client = "^8.2.1" djangorestframework-dataclasses = "^1.3.1" pyotp = "^2.9.0" flagsmith-task-processor = { git = "https://github.com/Flagsmith/flagsmith-task-processor", tag = "v1.0.2" } -flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common", tag = "v1.2.0" } +flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common", tag = "v1.3.0" } tzdata = "^2024.1" djangorestframework-simplejwt = "^5.3.1" @@ -196,7 +196,7 @@ flagsmith-ldap = { git = "https://github.com/flagsmith/flagsmith-ldap", tag = "v optional = true [tool.poetry.group.workflows.dependencies] -workflows-logic = { git = "https://github.com/flagsmith/flagsmith-workflows", tag = "v2.7.0" } +workflows-logic = { git = "https://github.com/flagsmith/flagsmith-workflows", tag = "v2.7.1" } [tool.poetry.group.dev.dependencies] django-test-migrations = "~1.2.0" diff --git a/api/tests/unit/segments/test_unit_segments_views.py b/api/tests/unit/segments/test_unit_segments_views.py index 4e29c6d3f1e5..f84b4e706f61 100644 --- a/api/tests/unit/segments/test_unit_segments_views.py +++ b/api/tests/unit/segments/test_unit_segments_views.py @@ -670,6 +670,148 @@ def test_update_segment_add_new_condition( assert nested_rule.conditions.order_by("-id").first().value == new_condition_value +def test_update_mismatched_rule_and_segment( + project: Project, + admin_client_new: APIClient, + segment: Segment, + segment_rule: SegmentRule, +) -> None: + # Given + url = reverse( + "api-v1:projects:project-segments-detail", args=[project.id, segment.id] + ) + false_segment = Segment.objects.create(name="False segment", project=project) + segment_rule.segment = false_segment + segment_rule.save() + + nested_rule = SegmentRule.objects.create( + rule=segment_rule, type=SegmentRule.ANY_RULE + ) + existing_condition = Condition.objects.create( + rule=nested_rule, property="foo", operator=EQUAL, value="bar" + ) + + new_condition_property = "foo2" + new_condition_value = "bar" + data = { + "name": segment.name, + "project": project.id, + "rules": [ + { + "id": segment_rule.id, + "type": segment_rule.type, + "rules": [ + { + "id": nested_rule.id, + "type": nested_rule.type, + "rules": [], + "conditions": [ + # existing condition + { + "id": existing_condition.id, + "property": existing_condition.property, + "operator": existing_condition.operator, + "value": existing_condition.value, + }, + # new condition + { + "property": new_condition_property, + "operator": EQUAL, + "value": new_condition_value, + }, + ], + } + ], + "conditions": [], + } + ], + } + + # When + response = admin_client_new.put( + url, data=json.dumps(data), content_type="application/json" + ) + + # Then + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert response.json() == {"segment": "Mismatched segment is not allowed"} + segment_rule.refresh_from_db() + assert segment_rule.segment == false_segment + + +def test_update_mismatched_condition_and_segment( + project: Project, + admin_client_new: APIClient, + segment: Segment, + segment_rule: SegmentRule, +) -> None: + # Given + url = reverse( + "api-v1:projects:project-segments-detail", args=[project.id, segment.id] + ) + false_segment = Segment.objects.create(name="False segment", project=project) + false_segment_rule = SegmentRule.objects.create( + segment=false_segment, type=SegmentRule.ALL_RULE + ) + false_nested_rule = SegmentRule.objects.create( + rule=false_segment_rule, type=SegmentRule.ANY_RULE + ) + nested_rule = SegmentRule.objects.create( + rule=segment_rule, type=SegmentRule.ANY_RULE + ) + + existing_condition = Condition.objects.create( + rule=false_nested_rule, property="foo", operator=EQUAL, value="bar" + ) + + new_condition_property = "foo2" + new_condition_value = "bar" + data = { + "name": segment.name, + "project": project.id, + "rules": [ + { + "id": segment_rule.id, + "type": segment_rule.type, + "rules": [ + { + "id": nested_rule.id, + "type": nested_rule.type, + "rules": [], + "conditions": [ + # existing condition + { + "id": existing_condition.id, + "property": existing_condition.property, + "operator": existing_condition.operator, + "value": existing_condition.value, + }, + # new condition + { + "property": new_condition_property, + "operator": EQUAL, + "value": new_condition_value, + }, + ], + } + ], + "conditions": [], + } + ], + } + + # When + response = admin_client_new.put( + url, data=json.dumps(data), content_type="application/json" + ) + + # Then + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert response.json() == {"segment": "Mismatched segment is not allowed"} + existing_condition.refresh_from_db() + assert existing_condition._get_segment() != segment + + def test_update_segment_versioned_segment( project: Project, admin_client_new: APIClient,