Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions src/openedx_tagging/rest_api/v1/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,15 +218,25 @@ class ObjectTagUpdateBodySerializer(serializers.Serializer): # pylint: disable=
tagsData = serializers.ListField(child=ObjectTagUpdateByTaxonomySerializer(), required=True)


def validate_tag_value(value, context):
def validate_tag_value(value, context, original_value=None):
"""
Validate this tag value is unique within the current taxonomy context and
does not contain forbidden characters.
Validates the incoming request early:
- This tag is unique, not a duplicate. (The model only validates this if you call `full_clean()`.)
- There are no forbidden / reserved characters present. There is an additional
model-side validation for this as well, but we are keeping this so we can validate
the incoming request immediately.
"""
taxonomy_id = context.get("taxonomy_id")
original_tag = Tag.objects.filter(taxonomy_id=taxonomy_id, value=original_value).first() if original_value else None
tag_id = original_tag.pk if original_tag else None
if taxonomy_id is not None:
# Check if tag value already exists within this taxonomy. If so, raise a validation error.
queryset = Tag.objects.filter(taxonomy_id=taxonomy_id, value=value)

# Don't compare tag against itself when validating its updated value.
if tag_id:
queryset = queryset.exclude(pk=tag_id)
Comment thread
bradenmacdonald marked this conversation as resolved.

# Check if tag value already exists within this taxonomy. If so, raise a validation error.
if queryset.exists():
raise serializers.ValidationError(
f'Tag value "{value}" already exists in this taxonomy.', code='unique'
Expand Down Expand Up @@ -350,7 +360,7 @@ def validate_updated_tag_value(self, value):
"""
Run validations for the updated tag value.
"""
return validate_tag_value(value, self.context)
return validate_tag_value(value, self.context, original_value=self.initial_data.get("tag"))


class TaxonomyTagDeleteBodySerializer(serializers.Serializer): # pylint: disable=abstract-method
Expand Down
29 changes: 29 additions & 0 deletions tests/openedx_tagging/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2211,6 +2211,35 @@ def test_update_tag_with_duplicate_value(self):
# Check that the error message indicates the duplicate value issue
assert "Tag value \"Updated Tag\" already exists in this taxonomy" in str(response.data)

def test_update_tag_change_capitalization(self):
"""
Test that renaming a tag by only changing its capitalization is allowed.
"""
self.client.force_authenticate(user=self.staff)
existing_tag = self.small_taxonomy.tag_set.filter(parent=None).first()
Comment thread
bradenmacdonald marked this conversation as resolved.

# Avoiding false positives
assert existing_tag.value is not existing_tag.value.upper()

update_data = {
"tag": existing_tag.value,
"updated_tag_value": existing_tag.value.upper()
}

response = self.client.put(
self.small_taxonomy_url, update_data, format="json"
)

assert response.status_code == status.HTTP_200_OK

data = response.data

# Check that Tag value got updated with the new capitalization
self.assertEqual(data.get("_id"), existing_tag.id)
self.assertEqual(data.get("value"), existing_tag.value.upper())
self.assertEqual(data.get("parent_value"), existing_tag.parent)
self.assertEqual(data.get("external_id"), existing_tag.external_id)

def test_should_handle_unexpected_errors_gracefully(self):
"""
Test that if any unexpected error occurs during the processing of the request,
Expand Down