Skip to content

Commit 84707c3

Browse files
refactor: enhance db existence validation (#1350)
Some refactoring in validators. Some of them are not used anymore or they do check for the existence of the DB by fetching the record, which is inefficient. DRF validators are expected to raise `ValidationError` or return None. In case of the `organization_id` has been created a mixin to avoid code duplication. Refactored: - organization - rulebook - credential_type - awx_token Removed: - event_streams - extra_vars Technically, in most of the cases a PrimaryKey field would be better, but that would require a more extended refactor to keep 100% backward compatibility, since we would have to implement custom error messages among other changes. There are multiple fields candidate to be a PrimaryKeyField and such a conversion is not the scope of this PR. Here I only address the fields where we are duplicating DB queries, duplicating field definition and removing unused validators. Signed-off-by: Alex <[email protected]>
1 parent 637aa34 commit 84707c3

File tree

7 files changed

+51
-111
lines changed

7 files changed

+51
-111
lines changed

src/aap_eda/api/serializers/activation.py

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from aap_eda.api.serializers.event_stream import EventStreamOutSerializer
3636
from aap_eda.api.serializers.fields.basic_user import BasicUserFieldSerializer
3737
from aap_eda.api.serializers.fields.yaml import YAMLSerializerField
38+
from aap_eda.api.serializers.mixins import OrganizationIdFieldMixin
3839
from aap_eda.api.serializers.organization import OrganizationRefSerializer
3940
from aap_eda.api.serializers.project import (
4041
ANSIBLE_VAULT_STRING,
@@ -429,7 +430,9 @@ def to_representation(self, activation):
429430
}
430431

431432

432-
class ActivationCreateSerializer(serializers.ModelSerializer):
433+
class ActivationCreateSerializer(
434+
OrganizationIdFieldMixin, serializers.ModelSerializer
435+
):
433436
"""Serializer for creating the Activation."""
434437

435438
class Meta:
@@ -452,15 +455,6 @@ class Meta:
452455
"skip_audit_events",
453456
]
454457

455-
organization_id = serializers.IntegerField(
456-
required=True,
457-
allow_null=False,
458-
validators=[validators.check_if_organization_exists],
459-
error_messages={
460-
"null": "Organization is needed",
461-
"required": "Organization is required",
462-
},
463-
)
464458
rulebook_id = serializers.IntegerField(
465459
validators=[validators.check_if_rulebook_exists],
466460
error_messages={
@@ -597,7 +591,9 @@ def copy(self) -> dict:
597591
return super().create(copied_data)
598592

599593

600-
class ActivationUpdateSerializer(serializers.ModelSerializer):
594+
class ActivationUpdateSerializer(
595+
OrganizationIdFieldMixin, serializers.ModelSerializer
596+
):
601597
"""Serializer for updating the Activation."""
602598

603599
class Meta:
@@ -620,12 +616,6 @@ class Meta:
620616
"skip_audit_events",
621617
]
622618

623-
organization_id = serializers.IntegerField(
624-
required=False,
625-
allow_null=False,
626-
validators=[validators.check_if_organization_exists],
627-
error_messages={"null": "Organization is needed"},
628-
)
629619
rulebook_id = serializers.IntegerField(
630620
validators=[validators.check_if_rulebook_exists],
631621
error_messages={"null": "Rulebook is needed"},

src/aap_eda/api/serializers/decision_environment.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from aap_eda.api.serializers.eda_credential import EdaCredentialRefSerializer
1818
from aap_eda.api.serializers.fields.basic_user import BasicUserFieldSerializer
19+
from aap_eda.api.serializers.mixins import OrganizationIdFieldMixin
1920
from aap_eda.api.serializers.organization import OrganizationRefSerializer
2021
from aap_eda.api.serializers.user import BasicUserSerializer
2122
from aap_eda.core import models, validators
@@ -56,15 +57,11 @@ def to_representation(self, decision_environment):
5657
return result
5758

5859

59-
class DecisionEnvironmentCreateSerializer(serializers.ModelSerializer):
60+
class DecisionEnvironmentCreateSerializer(
61+
OrganizationIdFieldMixin, serializers.ModelSerializer
62+
):
6063
"""Serializer for creating the DecisionEnvironment."""
6164

62-
organization_id = serializers.IntegerField(
63-
required=True,
64-
allow_null=False,
65-
validators=[validators.check_if_organization_exists],
66-
error_messages={"null": "Organization is needed"},
67-
)
6865
eda_credential_id = serializers.IntegerField(
6966
required=False,
7067
allow_null=True,

src/aap_eda/api/serializers/eda_credential.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from aap_eda.api.serializers.credential_type import CredentialTypeRefSerializer
2020
from aap_eda.api.serializers.fields.basic_user import BasicUserFieldSerializer
21+
from aap_eda.api.serializers.mixins import OrganizationIdFieldMixin
2122
from aap_eda.api.serializers.organization import OrganizationRefSerializer
2223
from aap_eda.api.serializers.user import BasicUserSerializer
2324
from aap_eda.core import enums, models, validators
@@ -129,7 +130,9 @@ class Meta:
129130
]
130131

131132

132-
class EdaCredentialCreateSerializer(serializers.ModelSerializer):
133+
class EdaCredentialCreateSerializer(
134+
OrganizationIdFieldMixin, serializers.ModelSerializer
135+
):
133136
credential_type_id = serializers.IntegerField(
134137
required=True,
135138
allow_null=False,
@@ -139,16 +142,6 @@ class EdaCredentialCreateSerializer(serializers.ModelSerializer):
139142
"required": "Credential Type is required",
140143
},
141144
)
142-
organization_id = serializers.IntegerField(
143-
required=True,
144-
allow_null=False,
145-
validators=[validators.check_if_organization_exists],
146-
error_messages={
147-
"null": "Organization is needed",
148-
"required": "Organization is required",
149-
},
150-
)
151-
152145
inputs = serializers.JSONField()
153146

154147
def validate(self, data):
@@ -190,13 +183,9 @@ class Meta:
190183
]
191184

192185

193-
class EdaCredentialUpdateSerializer(serializers.ModelSerializer):
194-
organization_id = serializers.IntegerField(
195-
required=True,
196-
allow_null=False,
197-
validators=[validators.check_if_organization_exists],
198-
error_messages={"null": "Organization is needed"},
199-
)
186+
class EdaCredentialUpdateSerializer(
187+
OrganizationIdFieldMixin, serializers.ModelSerializer
188+
):
200189
inputs = serializers.JSONField()
201190

202191
def validate(self, data):

src/aap_eda/api/serializers/mixins.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
# limitations under the License.
1414

1515
from django.conf import settings
16+
from rest_framework import serializers
1617

1718
from aap_eda.api import exceptions as api_exc
19+
from aap_eda.core import validators
1820

1921

2022
class SharedResourceSerializerMixin:
@@ -35,3 +37,15 @@ def validate_shared_resource(self, data=None):
3537
raise api_exc.Forbidden(
3638
f"{action} should be done through the platform ingress"
3739
)
40+
41+
42+
class OrganizationIdFieldMixin(serializers.Serializer):
43+
organization_id = serializers.IntegerField(
44+
required=True,
45+
allow_null=False,
46+
validators=[validators.check_if_organization_exists],
47+
error_messages={
48+
"null": "Organization is needed",
49+
"required": "Organization is required",
50+
},
51+
)

src/aap_eda/api/serializers/project.py

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from aap_eda.api.serializers.eda_credential import EdaCredentialRefSerializer
2121
from aap_eda.api.serializers.fields.basic_user import BasicUserFieldSerializer
22+
from aap_eda.api.serializers.mixins import OrganizationIdFieldMixin
2223
from aap_eda.api.serializers.organization import OrganizationRefSerializer
2324
from aap_eda.api.serializers.user import BasicUserSerializer
2425
from aap_eda.core import models, validators
@@ -81,16 +82,9 @@ def to_representation(self, instance):
8182
return result
8283

8384

84-
class ProjectCreateRequestSerializer(serializers.ModelSerializer):
85-
organization_id = serializers.IntegerField(
86-
required=True,
87-
allow_null=False,
88-
validators=[validators.check_if_organization_exists],
89-
error_messages={
90-
"null": "Organization is needed",
91-
"required": "Organization is required",
92-
},
93-
)
85+
class ProjectCreateRequestSerializer(
86+
OrganizationIdFieldMixin, serializers.ModelSerializer
87+
):
9488
eda_credential_id = serializers.IntegerField(
9589
required=False,
9690
allow_null=True,
@@ -142,16 +136,9 @@ class Meta:
142136
]
143137

144138

145-
class ProjectUpdateRequestSerializer(serializers.ModelSerializer):
146-
organization_id = serializers.IntegerField(
147-
required=True,
148-
allow_null=False,
149-
validators=[validators.check_if_organization_exists],
150-
error_messages={
151-
"null": "Organization is needed",
152-
"required": "Organization is required",
153-
},
154-
)
139+
class ProjectUpdateRequestSerializer(
140+
OrganizationIdFieldMixin, serializers.ModelSerializer
141+
):
155142
name = serializers.CharField(
156143
required=False,
157144
allow_blank=False,

src/aap_eda/api/serializers/team.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
from rest_framework import serializers
1515
from rest_framework.validators import UniqueTogetherValidator
1616

17+
from aap_eda.api.serializers.mixins import OrganizationIdFieldMixin
1718
from aap_eda.api.serializers.organization import OrganizationRefSerializer
18-
from aap_eda.core import models, validators
19+
from aap_eda.core import models
1920

2021
from .fields.ansible_resource import AnsibleResourceFieldSerializer
2122
from .mixins import SharedResourceSerializerMixin
@@ -40,16 +41,10 @@ class Meta:
4041

4142

4243
class TeamCreateSerializer(
44+
OrganizationIdFieldMixin,
4345
serializers.ModelSerializer,
4446
SharedResourceSerializerMixin,
4547
):
46-
organization_id = serializers.IntegerField(
47-
required=True,
48-
allow_null=False,
49-
validators=[validators.check_if_organization_exists],
50-
error_messages={"null": "Organization is needed"},
51-
)
52-
5348
class Meta:
5449
model = models.Team
5550
fields = [

src/aap_eda/core/validators.py

Lines changed: 9 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,11 @@
4343
]
4444

4545

46-
def check_if_rulebook_exists(rulebook_id: int) -> int:
47-
try:
48-
models.Rulebook.objects.get(pk=rulebook_id)
49-
except models.Rulebook.DoesNotExist:
46+
def check_if_rulebook_exists(rulebook_id: int) -> None:
47+
if not models.Rulebook.objects.filter(pk=rulebook_id).exists():
5048
raise serializers.ValidationError(
5149
f"Rulebook with id {rulebook_id} does not exist"
5250
)
53-
return rulebook_id
5451

5552

5653
def check_if_de_exists(decision_environment_id: int) -> int:
@@ -239,14 +236,13 @@ def check_single_aap_credential(
239236
return eda_credential_ids
240237

241238

242-
def check_if_credential_type_exists(credential_type_id: int) -> int:
243-
try:
244-
models.CredentialType.objects.get(pk=credential_type_id)
245-
except models.CredentialType.DoesNotExist:
239+
def check_if_credential_type_exists(credential_type_id: int) -> None:
240+
if not models.CredentialType.objects.filter(
241+
pk=credential_type_id
242+
).exists():
246243
raise serializers.ValidationError(
247244
f"CredentialType with id {credential_type_id} does not exist"
248245
)
249-
return credential_type_id
250246

251247

252248
def check_if_credential_name_used(name: str) -> str:
@@ -260,33 +256,17 @@ def check_if_credential_name_used(name: str) -> str:
260256

261257

262258
def check_if_organization_exists(organization_id: int) -> int:
263-
try:
264-
models.Organization.objects.get(pk=organization_id)
265-
except models.Organization.DoesNotExist:
259+
if not models.Organization.objects.filter(pk=organization_id).exists():
266260
raise serializers.ValidationError(
267261
f"Organization with id {organization_id} does not exist"
268262
)
269-
return organization_id
270263

271264

272-
def check_if_extra_var_exists(extra_var_id: int) -> int:
273-
try:
274-
models.ExtraVar.objects.get(pk=extra_var_id)
275-
except models.ExtraVar.DoesNotExist:
276-
raise serializers.ValidationError(
277-
f"ExtraVar with id {extra_var_id} does not exist"
278-
)
279-
return extra_var_id
280-
281-
282-
def check_if_awx_token_exists(awx_token_id: int) -> int:
283-
try:
284-
models.AwxToken.objects.get(pk=awx_token_id)
285-
except models.AwxToken.DoesNotExist:
265+
def check_if_awx_token_exists(awx_token_id: int) -> None:
266+
if not models.AwxToken.objects.filter(pk=awx_token_id).exists():
286267
raise serializers.ValidationError(
287268
f"AwxToken with id {awx_token_id} does not exist"
288269
)
289-
return awx_token_id
290270

291271

292272
def check_rulesets_require_token(
@@ -436,18 +416,6 @@ def _validate_event_stream_settings(auth_type: str):
436416
)
437417

438418

439-
def check_if_event_streams_exists(event_stream_ids: list[int]) -> list[int]:
440-
"""Check a event stream exists."""
441-
for event_stream_id in event_stream_ids:
442-
try:
443-
models.EventStream.objects.get(pk=event_stream_id)
444-
except models.EventStream.DoesNotExist as exc:
445-
raise serializers.ValidationError(
446-
f"EventStream with id {event_stream_id} does not exist"
447-
) from exc
448-
return event_stream_ids
449-
450-
451419
def check_credential_types_for_event_stream(eda_credential_id: int) -> int:
452420
"""Check the credential types for a event stream."""
453421
credential = get_credential_if_exists(eda_credential_id)

0 commit comments

Comments
 (0)