Skip to content

Commit 7f8ffac

Browse files
committed
fix(TrashBin): Trashed shared folders should not show up for sharees
fixes #2419 Assisted-by: ClaudeCode:claude-opus-4-7 Signed-off-by: Marcel Klehr <mklehr@gmx.net>
1 parent 2c7fa6b commit 7f8ffac

2 files changed

Lines changed: 30 additions & 2 deletions

File tree

lib/Db/BookmarkMapper.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,10 @@ public function generateCTE(int $folderId, bool $withSoftDeleted) : array {
311311
->from('*PREFIX*bookmarks_tree', 'tr')
312312
->join('tr', $this->getDbType() === 'mysql'? 'folder_tree' : 'inner_folder_tree', 'e', 'e.item_id = tr.parent_folder AND e.type = ' . $recursiveCase->createPositionalParameter(TreeMapper::TYPE_FOLDER) . (!$withSoftDeleted ? ' AND e.soft_deleted_at is NULL' : ''));
313313

314-
// The second recursive case lists all children of shared folders we've already found
314+
// The second recursive case lists all children of shared folders we've already found.
315+
// We also require the share's underlying original folder to not be soft-deleted by its
316+
// owner: when the sharer trashes the original folder, sharees must not see anything
317+
// inside it — not even in their own trash bin.
315318
$recursiveCaseShares = $this->db->getQueryBuilder();
316319
$recursiveCaseShares->automaticTablePrefix(false);
317320
$recursiveCaseShares
@@ -321,7 +324,8 @@ public function generateCTE(int $folderId, bool $withSoftDeleted) : array {
321324
->selectAlias('e.idx', 'idx')
322325
->selectAlias('e.soft_deleted_at', 'soft_deleted_at')
323326
->from(($this->getDbType() === 'mysql'? 'folder_tree' : 'second_folder_tree'), 'e')
324-
->join('e', '*PREFIX*bookmarks_shared_folders', 's', 's.id = e.item_id AND e.type = ' . $recursiveCaseShares->createPositionalParameter(TreeMapper::TYPE_SHARE) . (!$withSoftDeleted ? ' AND e.soft_deleted_at is NULL' : ''));
327+
->join('e', '*PREFIX*bookmarks_shared_folders', 's', 's.id = e.item_id AND e.type = ' . $recursiveCaseShares->createPositionalParameter(TreeMapper::TYPE_SHARE) . (!$withSoftDeleted ? ' AND e.soft_deleted_at is NULL' : ''))
328+
->join('s', '*PREFIX*bookmarks_tree', 'sof', 'sof.id = s.folder_id AND sof.type = ' . $recursiveCaseShares->createPositionalParameter(TreeMapper::TYPE_FOLDER) . ' AND sof.soft_deleted_at is NULL');
325329

326330
if ($this->getDbType() === 'mysql') {
327331
// For mysql we can just throw these three queries together in a CTE

lib/Db/TreeMapper.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,9 @@ protected function getFindChildrenQuery(string $type): IQueryBuilder {
238238
->andWhere($qb->expr()->eq('t.type', $qb->createNamedParameter($type)))
239239
->andWhere($qb->expr()->isNull('t.soft_deleted_at'))
240240
->orderBy('t.index', 'ASC');
241+
if ($type === TreeMapper::TYPE_SHARE) {
242+
$this->joinOriginalFolderNotSoftDeleted($qb);
243+
}
241244
return $qb;
242245
}
243246

@@ -249,9 +252,27 @@ protected function getFindSoftDeletedChildrenQuery(string $type): IQueryBuilder
249252
->andWhere($qb->expr()->eq('t.type', $qb->createNamedParameter($type)))
250253
->andWhere($qb->expr()->isNotNull('t.soft_deleted_at'))
251254
->orderBy('t.index', 'ASC');
255+
if ($type === TreeMapper::TYPE_SHARE) {
256+
$this->joinOriginalFolderNotSoftDeleted($qb);
257+
}
252258
return $qb;
253259
}
254260

261+
/**
262+
* Restricts a TYPE_SHARE query to shared folders whose underlying original
263+
* folder has not been soft-deleted by its owner. When the sharer trashes the
264+
* original folder, the share must disappear for sharees entirely — including
265+
* from their trash bin, since they cannot restore someone else's folder.
266+
*/
267+
private function joinOriginalFolderNotSoftDeleted(IQueryBuilder $qb): void {
268+
$qb
269+
->innerJoin('i', 'bookmarks_tree', 'ot', $qb->expr()->andX(
270+
$qb->expr()->eq('ot.id', 'i.folder_id'),
271+
$qb->expr()->eq('ot.type', $qb->createNamedParameter(TreeMapper::TYPE_FOLDER))
272+
))
273+
->andWhere($qb->expr()->isNull('ot.soft_deleted_at'));
274+
}
275+
255276
/**
256277
* @param string $type
257278
* @psalm-param T $type
@@ -1006,6 +1027,9 @@ public function getSoftDeletedRootItems(string $userId, string $type): array {
10061027
$qb->expr()->isNull('t2.soft_deleted_at'),
10071028
$qb->expr()->isNotNull('r.folder_id'),
10081029
));
1030+
if ($type === TreeMapper::TYPE_SHARE) {
1031+
$this->joinOriginalFolderNotSoftDeleted($qb);
1032+
}
10091033
return $this->findEntitiesWithType($qb, $type);
10101034
}
10111035
if ($type === TreeMapper::TYPE_BOOKMARK) {

0 commit comments

Comments
 (0)