Skip to content

Commit 36c9585

Browse files
authored
fix: allow tag renames that only change capitalization (#555)
1 parent d0dc9cd commit 36c9585

2 files changed

Lines changed: 44 additions & 5 deletions

File tree

src/openedx_tagging/rest_api/v1/serializers.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,15 +218,25 @@ class ObjectTagUpdateBodySerializer(serializers.Serializer): # pylint: disable=
218218
tagsData = serializers.ListField(child=ObjectTagUpdateByTaxonomySerializer(), required=True)
219219

220220

221-
def validate_tag_value(value, context):
221+
def validate_tag_value(value, context, original_value=None):
222222
"""
223-
Validate this tag value is unique within the current taxonomy context and
224-
does not contain forbidden characters.
223+
Validates the incoming request early:
224+
- This tag is unique, not a duplicate. (The model only validates this if you call `full_clean()`.)
225+
- There are no forbidden / reserved characters present. There is an additional
226+
model-side validation for this as well, but we are keeping this so we can validate
227+
the incoming request immediately.
225228
"""
226229
taxonomy_id = context.get("taxonomy_id")
230+
original_tag = Tag.objects.filter(taxonomy_id=taxonomy_id, value=original_value).first() if original_value else None
231+
tag_id = original_tag.pk if original_tag else None
227232
if taxonomy_id is not None:
228-
# Check if tag value already exists within this taxonomy. If so, raise a validation error.
229233
queryset = Tag.objects.filter(taxonomy_id=taxonomy_id, value=value)
234+
235+
# Don't compare tag against itself when validating its updated value.
236+
if tag_id:
237+
queryset = queryset.exclude(pk=tag_id)
238+
239+
# Check if tag value already exists within this taxonomy. If so, raise a validation error.
230240
if queryset.exists():
231241
raise serializers.ValidationError(
232242
f'Tag value "{value}" already exists in this taxonomy.', code='unique'
@@ -350,7 +360,7 @@ def validate_updated_tag_value(self, value):
350360
"""
351361
Run validations for the updated tag value.
352362
"""
353-
return validate_tag_value(value, self.context)
363+
return validate_tag_value(value, self.context, original_value=self.initial_data.get("tag"))
354364

355365

356366
class TaxonomyTagDeleteBodySerializer(serializers.Serializer): # pylint: disable=abstract-method

tests/openedx_tagging/test_views.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,6 +2211,35 @@ def test_update_tag_with_duplicate_value(self):
22112211
# Check that the error message indicates the duplicate value issue
22122212
assert "Tag value \"Updated Tag\" already exists in this taxonomy" in str(response.data)
22132213

2214+
def test_update_tag_change_capitalization(self):
2215+
"""
2216+
Test that renaming a tag by only changing its capitalization is allowed.
2217+
"""
2218+
self.client.force_authenticate(user=self.staff)
2219+
existing_tag = self.small_taxonomy.tag_set.filter(parent=None).first()
2220+
2221+
# Avoiding false positives
2222+
assert existing_tag.value is not existing_tag.value.upper()
2223+
2224+
update_data = {
2225+
"tag": existing_tag.value,
2226+
"updated_tag_value": existing_tag.value.upper()
2227+
}
2228+
2229+
response = self.client.put(
2230+
self.small_taxonomy_url, update_data, format="json"
2231+
)
2232+
2233+
assert response.status_code == status.HTTP_200_OK
2234+
2235+
data = response.data
2236+
2237+
# Check that Tag value got updated with the new capitalization
2238+
self.assertEqual(data.get("_id"), existing_tag.id)
2239+
self.assertEqual(data.get("value"), existing_tag.value.upper())
2240+
self.assertEqual(data.get("parent_value"), existing_tag.parent)
2241+
self.assertEqual(data.get("external_id"), existing_tag.external_id)
2242+
22142243
def test_should_handle_unexpected_errors_gracefully(self):
22152244
"""
22162245
Test that if any unexpected error occurs during the processing of the request,

0 commit comments

Comments
 (0)