Skip to content

Commit 9974494

Browse files
Zaimwa9pre-commit-ci[bot]
Zaimwa9
andauthored
feat: MetadataModelRequirement can accept organization as content-type (#5325)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 9777dd1 commit 9974494

File tree

2 files changed

+152
-11
lines changed

2 files changed

+152
-11
lines changed

api/metadata/serializers.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
from typing import Any
2+
13
from django.contrib.contenttypes.models import ContentType
4+
from django.core.exceptions import ObjectDoesNotExist
25
from rest_framework import serializers
36

47
from util.drf_writable_nested.serializers import (
@@ -47,15 +50,28 @@ class Meta:
4750
model = MetadataModelField
4851
fields = ("id", "field", "content_type", "is_required_for")
4952

50-
def validate(self, data): # type: ignore[no-untyped-def]
53+
def validate(self, data: dict[str, Any]) -> dict[str, Any]:
5154
data = super().validate(data)
5255
for requirement in data.get("is_required_for", []):
53-
org_id = (
54-
requirement["content_type"]
55-
.model_class()
56-
.objects.get(id=requirement["object_id"])
57-
.organisation_id
58-
)
56+
model_type = requirement["content_type"].model
57+
if model_type == "organisation":
58+
org_id = requirement["object_id"]
59+
elif model_type == "project":
60+
try:
61+
org_id = (
62+
requirement["content_type"]
63+
.model_class()
64+
.objects.get(id=requirement["object_id"])
65+
.organisation_id
66+
)
67+
except ObjectDoesNotExist:
68+
raise serializers.ValidationError(
69+
"The requirement organisation does not match the field organisation"
70+
)
71+
else:
72+
raise serializers.ValidationError(
73+
"The requirement content type must be project or organisation"
74+
)
5975
if org_id != data["field"].organisation_id:
6076
raise serializers.ValidationError(
6177
"The requirement organisation does not match the field organisation"

api/tests/unit/metadata/test_serializers.py

Lines changed: 129 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
1+
from typing import Any, Callable, Dict
2+
13
import pytest
24
from common.metadata.serializers import (
35
MetadataSerializer,
46
)
7+
from django.contrib.contenttypes.models import ContentType
58

69
from metadata.models import (
710
FIELD_VALUE_MAX_LENGTH,
811
MetadataField,
912
MetadataModelField,
1013
)
14+
from metadata.serializers import MetaDataModelFieldSerializer
15+
from organisations.models import Organisation
16+
from projects.models import Project
1117

1218

1319
@pytest.mark.parametrize(
@@ -28,9 +34,13 @@
2834
("multiline_str", "a valid string", True),
2935
],
3036
)
31-
def test_metadata_serializer_validate_validates_field_value_type_correctly( # type: ignore[no-untyped-def]
32-
organisation, environment_content_type, field_type, field_value, expected_is_valid
33-
):
37+
def test_metadata_serializer_validate_validates_field_value_type_correctly(
38+
organisation: Organisation,
39+
environment_content_type: ContentType,
40+
field_type: str,
41+
field_value: str,
42+
expected_is_valid: bool,
43+
) -> None:
3444
# Given
3545
field = MetadataField.objects.create(
3646
name="b", type=field_type, organisation=organisation
@@ -40,9 +50,124 @@ def test_metadata_serializer_validate_validates_field_value_type_correctly( # t
4050
field=field, content_type=environment_content_type
4151
)
4252

43-
data = {"model_field": model_field.id, "field_value": field_value}
53+
data: Dict[str, Any] = {"model_field": model_field.id, "field_value": field_value}
4454

4555
serializer = MetadataSerializer(data=data)
4656

4757
# When/ Then
4858
assert serializer.is_valid() is expected_is_valid
59+
60+
61+
@pytest.mark.parametrize(
62+
"content_type_target,expected_is_valid,error_message,get_object_id",
63+
[
64+
(
65+
"organisation",
66+
True,
67+
None,
68+
lambda **kwargs: kwargs["metadata_field"].organisation.id,
69+
),
70+
("project", True, None, lambda **kwargs: kwargs["project"].id),
71+
(
72+
"project",
73+
False,
74+
"The requirement organisation does not match the field organisation",
75+
lambda **kwargs: kwargs["metadata_field"].organisation.id,
76+
),
77+
(
78+
"organisation",
79+
False,
80+
"The requirement organisation does not match the field organisation",
81+
lambda **kwargs: kwargs["project"].id,
82+
),
83+
],
84+
)
85+
def test_metadata_model_field_serializer_validation(
86+
a_metadata_field: MetadataField,
87+
feature_content_type: ContentType,
88+
project: Project,
89+
content_type_target: str,
90+
organisation_content_type: ContentType,
91+
project_content_type: ContentType,
92+
expected_is_valid: bool,
93+
error_message: str | None,
94+
get_object_id: Callable[..., int],
95+
) -> None:
96+
content_type = (
97+
organisation_content_type
98+
if content_type_target == "organisation"
99+
else project_content_type
100+
)
101+
object_id = get_object_id(project=project, metadata_field=a_metadata_field)
102+
103+
# Given
104+
data: Dict[str, Any] = {
105+
"field": a_metadata_field.id,
106+
"content_type": feature_content_type.id,
107+
"is_required_for": [
108+
{
109+
"content_type": content_type.id,
110+
"object_id": object_id,
111+
}
112+
],
113+
}
114+
115+
# When
116+
serializer = MetaDataModelFieldSerializer(data=data)
117+
result = serializer.is_valid()
118+
119+
# Then
120+
assert result is expected_is_valid
121+
if not expected_is_valid:
122+
assert "non_field_errors" in serializer.errors
123+
assert serializer.errors["non_field_errors"][0] == error_message
124+
125+
126+
def test_metadata_model_field_serializer_with_empty_is_required_for(
127+
a_metadata_field: MetadataField,
128+
feature_content_type: ContentType,
129+
) -> None:
130+
# Given
131+
data: Dict[str, Any] = {
132+
"field": a_metadata_field.id,
133+
"content_type": feature_content_type.id,
134+
"is_required_for": [],
135+
}
136+
# When
137+
serializer = MetaDataModelFieldSerializer(data=data)
138+
result: bool = serializer.is_valid()
139+
# Then
140+
assert result is True
141+
142+
143+
def test_metadata_model_field_serializer_validation_invalid_content_type(
144+
a_metadata_field: MetadataField,
145+
feature_content_type: ContentType,
146+
project: Project,
147+
segment_content_type: ContentType,
148+
) -> None:
149+
object_id = project.id
150+
151+
# Given
152+
data: Dict[str, Any] = {
153+
"field": a_metadata_field.id,
154+
"content_type": feature_content_type.id,
155+
"is_required_for": [
156+
{
157+
"content_type": segment_content_type.id,
158+
"object_id": object_id,
159+
}
160+
],
161+
}
162+
163+
# When
164+
serializer = MetaDataModelFieldSerializer(data=data)
165+
result = serializer.is_valid()
166+
167+
# Then
168+
assert result is False
169+
assert "non_field_errors" in serializer.errors
170+
assert (
171+
serializer.errors["non_field_errors"][0]
172+
== "The requirement content type must be project or organisation"
173+
)

0 commit comments

Comments
 (0)