From 3613f9d7af6ff107ebdba94648322bda140e8aa3 Mon Sep 17 00:00:00 2001 From: Bai Date: Sat, 9 May 2026 16:21:13 +0800 Subject: [PATCH] fix: prevent cycles and hierarchy breaks in node add-children API --- apps/assets/api/node.py | 4 ++++ apps/assets/models/node.py | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index 6203e86a6..fb8e3aa92 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -94,6 +94,10 @@ class NodeAddChildrenApi(generics.UpdateAPIView): node_ids = request.data.get("nodes") children = Node.objects.filter(id__in=node_ids) for node in children: + if node.is_ancestor(instance): + # 如果 node 是 instance 的祖先节点,则不能添加为 instance 的子节点,否则会形成环,出现断层 + error = _("Node {} is an ancestor of node {}, can't be added as its child".format(node.value, instance.value)) + return Response(data={'error': error}, status=status.HTTP_400_BAD_REQUEST) node.parent = instance update_nodes_assets_amount.delay(ttl=5, node_ids=(instance.id,)) return Response("OK") diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index f2475cdc1..9ecdac54e 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -94,6 +94,10 @@ class FamilyMixin: def is_children(self, other): children_pattern = other.get_children_key_pattern(with_self=False) return re.match(children_pattern, self.key) + + def is_descendant(self, other): + all_children_pattern = other.get_all_children_pattern(with_self=False) + return re.match(all_children_pattern, self.key) def get_children(self, with_self=False): q = Q(parent_key=self.key) @@ -204,6 +208,9 @@ class FamilyMixin: def is_parent(self, other): return other.is_children(self) + def is_ancestor(self, other): + return other.is_descendant(self) + @property def parent(self): if self.is_org_root():