diff --git a/lib/Db/BookmarkMapper.php b/lib/Db/BookmarkMapper.php index 741065bc0..d309804ad 100644 --- a/lib/Db/BookmarkMapper.php +++ b/lib/Db/BookmarkMapper.php @@ -895,6 +895,10 @@ public function insert(Entity $entity): Bookmark { return $entity; } catch (Exception $e) { if ($e->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { + if ($this->db->inTransaction()) { + $this->db->commit(); + $this->db->beginTransaction(); + } throw new AlreadyExistsError('A bookmark with this URL already exists'); } throw $e; diff --git a/lib/Service/HtmlExporter.php b/lib/Service/HtmlExporter.php index 4e5cb2a4a..cd3f60036 100644 --- a/lib/Service/HtmlExporter.php +++ b/lib/Service/HtmlExporter.php @@ -70,7 +70,9 @@ public function exportFolder(string $userId, int $folderId): string { Bookmarks'; - $file .= $this->serializeFolder($userId, $folderId, true); + $file .= "

\n"; + $file .= $this->serializeFolder($userId, $folderId); + $file .= "

\n"; return $file; } @@ -84,14 +86,15 @@ public function exportFolder(string $userId, int $folderId): string { * @throws MultipleObjectsReturnedException * @throws UnauthorizedAccessError */ - protected function serializeFolder(string $userId, int $id, bool $onlyContent = false): string { - if ($onlyContent) { - $output = ''; - } else { - $folder = $this->folderMapper->find($id); - $output = '

' . htmlspecialchars($folder->getTitle()) . '

' . "\n" - . '

'; + protected function serializeFolder(string $userId, int $id, string $indent = ''): string { + $output = ''; + $nextIndent = $indent . ' '; + $childFolders = $this->treeMapper->findChildren(TreeMapper::TYPE_FOLDER, $id); + foreach ($childFolders as $childFolder) { + $output .= $indent . '

' . htmlspecialchars($childFolder->getTitle()) . '

' . "\n"; + $output .= $indent . '

' . "\n" . $this->serializeFolder($userId, $childFolder->getId(), $nextIndent) . '

' . "\n"; } + $childBookmarks = $this->treeMapper->findChildren(TreeMapper::TYPE_BOOKMARK, $id); foreach ($childBookmarks as $bookmark) { // discards records with no URL. This should not happen but @@ -105,25 +108,15 @@ protected function serializeFolder(string $userId, int $id, bool $onlyContent = $tags = Util::sanitizeHTML(implode(',', $tags)); $title = trim($bookmark->getTitle()); $url = Util::sanitizeHTML($bookmark->getUrl()); - if ($title === '') { - $title = $url; - } $title = Util::sanitizeHTML($title); $description = Util::sanitizeHTML($bookmark->getDescription()); - $output .= '

' . $title . '' . "\n"; + $output .= $indent . '
' . $title . '' . "\n"; if ($description !== '') { $output .= '
' . $description . '
'; } $output .= "\n"; } - - $childFolders = $this->treeMapper->findChildren(TreeMapper::TYPE_FOLDER, $id); - foreach ($childFolders as $childFolder) { - $output .= $this->serializeFolder($userId, $childFolder->getId()); - } - - $output .= '

'; return $output; } } diff --git a/tests/HtmlImportExportTest.php b/tests/HtmlImportExportTest.php index a011307a6..156f0ed72 100644 --- a/tests/HtmlImportExportTest.php +++ b/tests/HtmlImportExportTest.php @@ -131,7 +131,7 @@ public function testExport(...$bookmarks): void { // Set up database for ($i = 0; $i < 4; $i++) { $f = new Db\Folder(); - $f->setTitle($i); + $f->setTitle(md5($i)); $f->setUserId($this->userId); $f = $this->folderMapper->insert($f); $this->treeMapper->move(Db\TreeMapper::TYPE_FOLDER, $f->getId(), $rootFolder->getId()); @@ -143,13 +143,32 @@ public function testExport(...$bookmarks): void { $exported = $this->htmlExporter->exportFolder($this->userId, $rootFolder->getId()); - $rootFolders = $this->treeMapper->findChildren(Db\TreeMapper::TYPE_FOLDER, $rootFolder->getId()); - $this->assertCount(4, $rootFolders); - foreach ($rootFolders as $rootFolder) { - foreach ($this->treeMapper->findChildren(Db\TreeMapper::TYPE_BOOKMARK, $rootFolder->getId()) as $bookmark) { + $exportedRootFolders = $this->treeMapper->findChildren(Db\TreeMapper::TYPE_FOLDER, $rootFolder->getId()); + $this->assertCount(4, $exportedRootFolders); + foreach ($exportedRootFolders as $exportedRootFolder) { + foreach ($this->treeMapper->findChildren(Db\TreeMapper::TYPE_BOOKMARK, $exportedRootFolder->getId()) as $bookmark) { + $this->assertStringContainsString($exportedRootFolder->getTitle(), $exported); $this->assertStringContainsString($bookmark->getUrl(), $exported); } } + + $f = new Db\Folder(); + $f->setTitle('Testimport'); + $f->setUserId($this->userId); + $f = $this->folderMapper->insert($f); + $this->htmlImporter->import($this->userId, $exported, $f->getId()); + $importedRootFolders = $this->treeMapper->findChildren(Db\TreeMapper::TYPE_FOLDER, $f->getId()); + foreach ($importedRootFolders as $i => $importedRootFolder) { + $exportedRootFolder = $exportedRootFolders[$i]; + $this->assertEquals($importedRootFolder->getTitle(), $exportedRootFolder->getTitle()); + $exportedBookmarks = $this->treeMapper->findChildren(Db\TreeMapper::TYPE_BOOKMARK, $exportedRootFolder->getId()); + foreach ($this->treeMapper->findChildren(Db\TreeMapper::TYPE_BOOKMARK, $importedRootFolder->getId()) as $j => $bookmark) { + $this->assertEquals($bookmark->getUrl(), $exportedBookmarks[$j]->getUrl()); + $this->assertEquals($bookmark->getTitle(), $exportedBookmarks[$j]->getTitle()); + $this->assertEquals($bookmark->getDescription(), $exportedBookmarks[$j]->getDescription()); + $this->assertEquals($this->tagMapper->findByBookmark($bookmark->getId()), $this->tagMapper->findByBookmark($exportedBookmarks[$j]->getId())); + } + } } public function importProvider(): array { @@ -166,10 +185,10 @@ public function exportProvider(): array { return Db\Bookmark::fromArray($props); }, [ ['url' => 'https://google.com/', 'title' => 'Google', 'description' => 'Search engine'], - ['url' => 'https://nextcloud.com/', 'title' => 'Nextcloud', 'description' => ''], + ['url' => 'https://nextcloud.com/', 'title' => 'Nextcloud', 'description' => 'cloud cloud cloud'], ['url' => 'https://php.net/', 'title' => '', 'description' => ''], - ['url' => 'https://de.wikipedia.org/wiki/%C3%9C', 'title' => '', 'description' => ''], - ['url' => 'https://github.com/nextcloud/bookmarks/projects/1', 'title' => '', 'description' => ''], + ['url' => 'https://de.wikipedia.org/wiki/%C3%9C', 'title' => '', 'description' => '

Hello

'], + ['url' => 'https://github.com/nextcloud/bookmarks/projects/1', 'title' => '', 'description' => ''], ]), ]; }