Handle parent tag removal in backend

This commit is contained in:
shamoon
2025-09-13 07:38:08 -07:00
parent 09f535f89a
commit 69143c5e0e
2 changed files with 31 additions and 16 deletions

View File

@@ -1088,22 +1088,27 @@ class DocumentSerializer(
doc_id, doc_id,
) )
if "tags" in validated_data: if "tags" in validated_data:
# add all parent tags # Respect tag hierarchy on updates:
all_ancestor_tags = set(validated_data["tags"]) # - Adding a child adds its ancestors
for tag in validated_data["tags"]: # - Removing a parent removes all its descendants
all_ancestor_tags.update(tag.get_ancestors()) prev_tags = set(instance.tags.all())
validated_data["tags"] = list(all_ancestor_tags) requested_tags = set(validated_data["tags"])
# remove any children for parents that are being removed
tag_parents_being_removed = [ # Tags being removed in this update and all descendants
tag removed_tags = prev_tags - requested_tags
for tag in instance.tags.all() blocked_tags = set(removed_tags)
if tag not in validated_data["tags"] and tag.get_children_count() > 0 for t in removed_tags:
] blocked_tags.update(t.get_descendants())
validated_data["tags"] = [
tag # Add all parent tags
for tag in validated_data["tags"] final_tags = set(requested_tags)
if tag not in tag_parents_being_removed for t in requested_tags:
] final_tags.update(t.get_ancestors())
# Drop removed parents and their descendants
final_tags.difference_update(blocked_tags)
validated_data["tags"] = list(final_tags)
if validated_data.get("remove_inbox_tags"): if validated_data.get("remove_inbox_tags"):
tag_ids_being_added = ( tag_ids_being_added = (
[ [

View File

@@ -51,6 +51,16 @@ class TestTagHierarchy(APITestCase):
tags = set(self.document.tags.values_list("pk", flat=True)) tags = set(self.document.tags.values_list("pk", flat=True))
assert tags == {self.parent.pk, self.child.pk} assert tags == {self.parent.pk, self.child.pk}
def test_document_api_remove_parent_removes_children(self):
self.document.add_nested_tags([self.parent, self.child])
self.client.patch(
f"/api/documents/{self.document.pk}/",
{"tags": [self.child.pk]},
format="json",
)
self.document.refresh_from_db()
assert self.document.tags.count() == 0
def test_document_api_remove_parent_removes_child(self): def test_document_api_remove_parent_removes_child(self):
self.document.add_nested_tags([self.child]) self.document.add_nested_tags([self.child])
self.client.patch( self.client.patch(