Skip to content

Commit 659d72d

Browse files
authored
Refactor Subproject validation to use it for Forms and API (#6285)
Refactor Subproject validation to use it for Forms and API
2 parents 652e2f4 + 829878c commit 659d72d

File tree

4 files changed

+52
-33
lines changed

4 files changed

+52
-33
lines changed

readthedocs/api/v3/serializers.py

+6-22
Original file line numberDiff line numberDiff line change
@@ -557,17 +557,9 @@ def validate_child(self, value):
557557
_('You do not have permissions on the child project'),
558558
)
559559

560-
# Check the child project is not a subproject already
561-
if value.superprojects.exists():
562-
raise serializers.ValidationError(
563-
_('Child is already a subproject of another project'),
564-
)
565-
566-
# Check the child project is already a superproject
567-
if value.subprojects.exists():
568-
raise serializers.ValidationError(
569-
_('Child is already a superproject'),
570-
)
560+
value.is_valid_as_subproject(
561+
self.parent_project, serializers.ValidationError
562+
)
571563
return value
572564

573565
def validate_alias(self, value):
@@ -581,17 +573,9 @@ def validate_alias(self, value):
581573

582574
# pylint: disable=arguments-differ
583575
def validate(self, data):
584-
# Check the parent and child are not the same project
585-
if data['child'].slug == self.parent_project.slug:
586-
raise serializers.ValidationError(
587-
_('Project can not be subproject of itself'),
588-
)
589-
590-
# Check the parent project is not a subproject already
591-
if self.parent_project.superprojects.exists():
592-
raise serializers.ValidationError(
593-
_('Subproject nesting is not supported'),
594-
)
576+
self.parent_project.is_valid_as_superproject(
577+
serializers.ValidationError
578+
)
595579
return data
596580

597581

readthedocs/api/v3/tests/test_subprojects.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def test_projects_subprojects_list_post_with_subproject_of_itself(self):
108108
self.assertEqual(response.status_code, 400)
109109
self.assertIn(
110110
'Project can not be subproject of itself',
111-
response.json()['non_field_errors'],
111+
response.json()['child'],
112112
)
113113
self.assertEqual(newproject.subprojects.count(), 0)
114114

readthedocs/projects/forms.py

+7-10
Original file line numberDiff line numberDiff line change
@@ -360,20 +360,17 @@ def __init__(self, *args, **kwargs):
360360
self.fields['child'].queryset = self.get_subproject_queryset()
361361

362362
def clean_parent(self):
363-
if self.project.superprojects.exists():
364-
# This validation error is mostly for testing, users shouldn't see
365-
# this in normal circumstances
366-
raise forms.ValidationError(
367-
_('Subproject nesting is not supported'),
368-
)
363+
self.project.is_valid_as_superproject(
364+
forms.ValidationError
365+
)
369366
return self.project
370367

371368
def clean_child(self):
372369
child = self.cleaned_data['child']
373-
if child == self.project:
374-
raise forms.ValidationError(
375-
_('A project can not be a subproject of itself'),
376-
)
370+
371+
child.is_valid_as_subproject(
372+
self.project, forms.ValidationError
373+
)
377374
return child
378375

379376
def clean_alias(self):

readthedocs/projects/models.py

+38
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,44 @@ def environment_variables(self):
11591159
for variable in self.environmentvariable_set.all()
11601160
}
11611161

1162+
def is_valid_as_superproject(self, error_class):
1163+
"""
1164+
Checks if the project can be a superproject.
1165+
1166+
This is used to handle form and serializer validations
1167+
if check fails returns ValidationError using to the error_class passed
1168+
"""
1169+
# Check the parent project is not a subproject already
1170+
if self.superprojects.exists():
1171+
raise error_class(
1172+
_('Subproject nesting is not supported'),
1173+
)
1174+
1175+
def is_valid_as_subproject(self, parent, error_class):
1176+
"""
1177+
Checks if the project can be a subproject.
1178+
1179+
This is used to handle form and serializer validations
1180+
if check fails returns ValidationError using to the error_class passed
1181+
"""
1182+
# Check the child project is not a subproject already
1183+
if self.superprojects.exists():
1184+
raise error_class(
1185+
_('Child is already a subproject of another project'),
1186+
)
1187+
1188+
# Check the child project is already a superproject
1189+
if self.subprojects.exists():
1190+
raise error_class(
1191+
_('Child is already a superproject'),
1192+
)
1193+
1194+
# Check the parent and child are not the same project
1195+
if parent.slug == self.slug:
1196+
raise error_class(
1197+
_('Project can not be subproject of itself'),
1198+
)
1199+
11621200

11631201
class APIProject(Project):
11641202

0 commit comments

Comments
 (0)