|
6 | 6 | use OCA\Bookmarks\Exception\AlreadyExistsError; |
7 | 7 | use OCA\Bookmarks\Exception\UrlParseError; |
8 | 8 | use OCA\Bookmarks\Exception\UserLimitExceededError; |
| 9 | +use OCA\Bookmarks\Service\FolderService; |
9 | 10 | use OCP\AppFramework\Db\DoesNotExistException; |
10 | 11 | use OCP\AppFramework\Db\Entity; |
11 | 12 | use OCP\AppFramework\Db\MultipleObjectsReturnedException; |
12 | 13 | use OCP\IUserManager; |
| 14 | +use OCP\Share\IShare; |
13 | 15 |
|
14 | 16 | class BookmarkMapperTest extends TestCase { |
15 | 17 | /** |
@@ -124,6 +126,93 @@ public function testDelete(Entity $bookmark) { |
124 | 126 | $this->bookmarkMapper->find($foundEntity->getId()); |
125 | 127 | } |
126 | 128 |
|
| 129 | + /** |
| 130 | + * Regression test: countDuplicated() must count a bookmark that is duplicated |
| 131 | + * across two subfolders of a *shared* folder, for the sharee. The previous |
| 132 | + * implementation queried the raw bookmarks_tree table (owner's bookmarks + |
| 133 | + * bookmarks directly inside a shared folder) and therefore under-counted: it |
| 134 | + * never saw duplicates living in subfolders of shared folders. The count must |
| 135 | + * match what the "Duplicated" list (findAll + setDuplicated) actually shows. |
| 136 | + * |
| 137 | + * @throws \OCA\Bookmarks\Exception\AlreadyExistsError |
| 138 | + * @throws \OCA\Bookmarks\Exception\UserLimitExceededError |
| 139 | + * @throws UrlParseError |
| 140 | + * @throws MultipleObjectsReturnedException |
| 141 | + */ |
| 142 | + public function testCountDuplicatedInSubfolderOfSharedFolder() { |
| 143 | + $owner = 'dup_share_owner'; |
| 144 | + $recipient = 'dup_share_recipient'; |
| 145 | + if (!$this->userManager->userExists($owner)) { |
| 146 | + $this->userManager->createUser($owner, 'password'); |
| 147 | + } |
| 148 | + if (!$this->userManager->userExists($recipient)) { |
| 149 | + $this->userManager->createUser($recipient, 'password'); |
| 150 | + } |
| 151 | + $ownerId = $this->userManager->get($owner)->getUID(); |
| 152 | + $recipientId = $this->userManager->get($recipient)->getUID(); |
| 153 | + |
| 154 | + /** @var FolderService $folderService */ |
| 155 | + $folderService = \OCP\Server::get(FolderService::class); |
| 156 | + |
| 157 | + // Owner creates a folder that will be shared... |
| 158 | + $sharedFolder = new Db\Folder(); |
| 159 | + $sharedFolder->setTitle('shared-root'); |
| 160 | + $sharedFolder->setUserId($ownerId); |
| 161 | + $this->folderMapper->insert($sharedFolder); |
| 162 | + $this->treeMapper->move( |
| 163 | + Db\TreeMapper::TYPE_FOLDER, |
| 164 | + $sharedFolder->getId(), |
| 165 | + $this->folderMapper->findRootFolder($ownerId)->getId(), |
| 166 | + ); |
| 167 | + |
| 168 | + // ...with two subfolders inside it. |
| 169 | + $subFolderA = new Db\Folder(); |
| 170 | + $subFolderA->setTitle('sub-a'); |
| 171 | + $subFolderA->setUserId($ownerId); |
| 172 | + $this->folderMapper->insert($subFolderA); |
| 173 | + $this->treeMapper->move(Db\TreeMapper::TYPE_FOLDER, $subFolderA->getId(), $sharedFolder->getId()); |
| 174 | + |
| 175 | + $subFolderB = new Db\Folder(); |
| 176 | + $subFolderB->setTitle('sub-b'); |
| 177 | + $subFolderB->setUserId($ownerId); |
| 178 | + $this->folderMapper->insert($subFolderB); |
| 179 | + $this->treeMapper->move(Db\TreeMapper::TYPE_FOLDER, $subFolderB->getId(), $sharedFolder->getId()); |
| 180 | + |
| 181 | + // A single bookmark placed in BOTH subfolders -> it is duplicated. |
| 182 | + $bookmark = Db\Bookmark::fromArray([ |
| 183 | + 'userId' => $ownerId, |
| 184 | + 'url' => 'https://example.org/duplicated-in-shared-subfolders', |
| 185 | + 'title' => 'Nested duplicate', |
| 186 | + 'description' => '', |
| 187 | + ]); |
| 188 | + $bookmark = $this->bookmarkMapper->insertOrUpdate($bookmark); |
| 189 | + $this->treeMapper->addToFolders( |
| 190 | + Db\TreeMapper::TYPE_BOOKMARK, |
| 191 | + $bookmark->getId(), |
| 192 | + [$subFolderA->getId(), $subFolderB->getId()], |
| 193 | + ); |
| 194 | + |
| 195 | + $folderService->createShare( |
| 196 | + $sharedFolder->getId(), |
| 197 | + $recipient, |
| 198 | + IShare::TYPE_USER, |
| 199 | + true, |
| 200 | + false, |
| 201 | + ); |
| 202 | + |
| 203 | + // The owner reaches both subfolders directly -> sees 1 duplicate. |
| 204 | + $this->assertSame(1, $this->bookmarkMapper->countDuplicated($ownerId)); |
| 205 | + |
| 206 | + // The sharee reaches both subfolders through the share -> must also see 1 |
| 207 | + // duplicate. This is the case the old implementation missed (returned 0). |
| 208 | + $this->assertSame(1, $this->bookmarkMapper->countDuplicated($recipientId)); |
| 209 | + |
| 210 | + // And the count must agree with the actual "Duplicated" list. |
| 211 | + $params = new \OCA\Bookmarks\QueryParameters(); |
| 212 | + $duplicatedList = $this->bookmarkMapper->findAll($recipientId, $params->setDuplicated(true)); |
| 213 | + $this->assertCount(1, $duplicatedList); |
| 214 | + } |
| 215 | + |
127 | 216 | /** |
128 | 217 | * @return array |
129 | 218 | */ |
|
0 commit comments