fix: keep folder parent references acyclic (#28748)

Moving a folder under one of its own subfolders was accepted. A folder in a parent loop is never a root, so it and everything under it silently disappeared from the sidebar, and there was no way to get it back from the UI.

The move is now rejected with a 400, folders whose parent chain loops are put back at the root on the next folder list, and the folder tree traversals skip ids they have already visited so existing data in that state stays workable.
This commit is contained in:
Classic298
2026-08-24 17:06:19 -04:00
committed by GitHub
parent 18edfff2d6
commit 23b3a69bc2
3 changed files with 51 additions and 21 deletions
+14 -4
View File
@@ -202,10 +202,14 @@ class FolderTable:
try:
async with get_async_db_context(db) as db:
folders = []
seen_ids = {id}
async def get_children(folder):
children = await self.get_folders_by_parent_id_and_user_id(folder.id, user_id, db=db)
for child in children:
if child.id in seen_ids:
continue
seen_ids.add(child.id)
await get_children(child)
folders.append(child)
@@ -267,15 +271,17 @@ class FolderTable:
if not folder:
return []
folder_ids = [folder.id]
folder_ids = {folder.id}
folders = [FolderModel.model_validate(folder)]
while folders:
current_folder = folders.pop()
children = await self.get_folders_by_parent_id_and_user_id(current_folder.id, user_id, db=db)
folder_ids.extend(child.id for child in children)
folders.extend(children)
for child in children:
if child.id not in folder_ids:
folder_ids.add(child.id)
folders.append(child)
return folder_ids
return list(folder_ids)
async def update_folder_parent_id_by_id_and_user_id(
self,
@@ -385,11 +391,15 @@ class FolderTable:
return folder_ids
folder_ids.append(folder.id)
seen_ids = {folder.id}
# Delete all children folders
async def delete_children(folder):
folder_children = await self.get_folders_by_parent_id_and_user_id(folder.id, user_id, db=db)
for folder_child in folder_children:
if folder_child.id in seen_ids:
continue
seen_ids.add(folder_child.id)
await delete_children(folder_child)
folder_ids.append(folder_child.id)