Add tests for BookmarksController with shares

Signed-off-by: Marcel Klehr <mklehr@gmx.net>
This commit is contained in:
Marcel Klehr 2019-12-28 15:41:02 +01:00
parent 478a0b7e0a
commit f19f431e36
5 changed files with 247 additions and 86 deletions

View File

@ -16,8 +16,10 @@ use OCA\Bookmarks\Db\BookmarkMapper;
use OCA\Bookmarks\Db\Folder;
use OCA\Bookmarks\Db\FolderMapper;
use OCA\Bookmarks\Db\TagMapper;
use OCA\Bookmarks\Exception\AlreadyExistsError;
use OCA\Bookmarks\Exception\UnauthorizedAccessError;
use OCA\Bookmarks\Exception\UrlParseError;
use OCA\Bookmarks\Exception\UserLimitExceededError;
use OCA\Bookmarks\Service\Authorizer;
use OCA\Bookmarks\Service\BookmarkPreviewer;
use OCA\Bookmarks\Service\FaviconPreviewer;
@ -415,32 +417,64 @@ class BookmarkController extends ApiController {
}
}
$bookmark = new Bookmark();
$bookmark->setTitle($title);
$bookmark->setUrl($url);
$bookmark->setDescription($description);
$bookmark->setUserId($this->userId);
try {
$bookmark = $this->bookmarkMapper->insertOrUpdate($bookmark);
} catch (UrlParseError $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Failed to parse URL']], Http::STATUS_BAD_REQUEST);
} catch (MultipleObjectsReturnedException $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Multiple existing objects found']], Http::STATUS_BAD_REQUEST);
}
$this->tagMapper->setOn($tags, $bookmark->getId());
if (count($folders) === 0) {
$folders = [-1];
}
try {
$this->folderMapper->setToFolders($bookmark->getId(), $folders);
} catch (UnauthorizedAccessError $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Could not set some folders']], Http::STATUS_BAD_REQUEST);
} catch (DoesNotExistException $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Could not set some folders']], Http::STATUS_BAD_REQUEST);
} catch (MultipleObjectsReturnedException $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Could not set some folders']], Http::STATUS_BAD_REQUEST);
$bookmark = new Bookmark();
$bookmark->setTitle($title);
$bookmark->setUrl($url);
$bookmark->setDescription($description);
$bookmark->setUserId($this->userId);
try {
$bookmark = $this->bookmarkMapper->insertOrUpdate($bookmark);
} catch (UrlParseError $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Failed to parse URL']], Http::STATUS_BAD_REQUEST);
} catch (MultipleObjectsReturnedException $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Multiple existing objects found']], Http::STATUS_BAD_REQUEST);
}
$this->tagMapper->setOn($tags, $bookmark->getId());
if (count($folders) === 0) {
$folders = [-1];
}
try {
$this->folderMapper->setToFolders($bookmark->getId(), $folders);
} catch (DoesNotExistException $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Could not set some folders']], Http::STATUS_BAD_REQUEST);
} catch (MultipleObjectsReturnedException $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Could not set some folders']], Http::STATUS_BAD_REQUEST);
}
}else{
foreach($folders as $folderId) {
try {
$folder = $this->folderMapper->find($folderId);
} catch (DoesNotExistException $e) {
continue;
} catch (MultipleObjectsReturnedException $e) {
continue;
}
$bookmark = new Bookmark();
$bookmark->setTitle($title);
$bookmark->setUrl($url);
$bookmark->setDescription($description);
$bookmark->setUserId($folder->getUserId());
try {
$bookmark = $this->bookmarkMapper->insertOrUpdate($bookmark);
} catch (UrlParseError $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Failed to parse URL']], Http::STATUS_BAD_REQUEST);
} catch (MultipleObjectsReturnedException $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Multiple existing objects found']], Http::STATUS_BAD_REQUEST);
}
$this->tagMapper->setOn($tags, $bookmark->getId());
try {
$this->folderMapper->setToFolders($bookmark->getId(), [$folder->getId()]);
} catch (DoesNotExistException $e) {
continue;
} catch (MultipleObjectsReturnedException $e) {
continue;
}
}
}
return new JSONResponse(['item' => $this->_returnBookmarkAsArray($bookmark), 'status' => 'success']);
@ -463,16 +497,6 @@ class BookmarkController extends ApiController {
if (!Authorizer::hasPermission(Authorizer::PERM_EDIT, $this->authorizer->getPermissionsForBookmark($id, $this->userId, $this->request))) {
return new JSONResponse(['status' => 'error', 'data' => 'Insufficient permissions'], Http::STATUS_BAD_REQUEST);
}
if (isset($folders)) {
$permissions = Authorizer::PERM_ALL;
foreach ($folders as $folder) {
$permissions &= $this->authorizer->getPermissionsForFolder($folder, $this->userId, $this->request);
}
if (!Authorizer::hasPermission(Authorizer::PERM_EDIT, $permissions)) {
return new JSONResponse(['status' => 'error', 'data' => 'Insufficient permissions'], Http::STATUS_BAD_REQUEST);
}
}
try {
$bookmark = $this->bookmarkMapper->find($id);
} catch (DoesNotExistException $e) {
@ -489,6 +513,50 @@ class BookmarkController extends ApiController {
if (isset($description)) {
$bookmark->setDescription($description);
}
if (isset($folders)) {
$permissions = Authorizer::PERM_ALL;
foreach ($folders as $folder) {
$permissions &= $this->authorizer->getPermissionsForFolder($folder, $this->userId, $this->request);
}
if (!Authorizer::hasPermission(Authorizer::PERM_EDIT, $permissions)) {
return new JSONResponse(['status' => 'error', 'data' => 'Insufficient permissions'], Http::STATUS_BAD_REQUEST);
}
$this->bookmarkMapper->delete($bookmark);
foreach($folders as $folderId) {
try {
$folder = $this->folderMapper->find($folderId);
} catch (DoesNotExistException $e) {
continue;
} catch (MultipleObjectsReturnedException $e) {
continue;
}
if ($bookmark->getUserId() !== $folder->getUserId()) {
$bookmark->setUserId($folder->getUserId());
}
try {
$bookmark = $this->bookmarkMapper->insert($bookmark);
} catch (UrlParseError $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Failed to parse URL']], Http::STATUS_BAD_REQUEST);
} catch (AlreadyExistsError $e) {
continue;
} catch (UserLimitExceededError $e) {
continue;
}
$this->tagMapper->setOn($tags, $bookmark->getId());
try {
$this->folderMapper->setToFolders($bookmark->getId(), [$folder->getId()]);
} catch (DoesNotExistException $e) {
continue;
} catch (MultipleObjectsReturnedException $e) {
continue;
}
}
}
if (is_array($tags)) {
$this->tagMapper->setOn($tags, $bookmark->getId());
}
@ -502,8 +570,6 @@ class BookmarkController extends ApiController {
if (isset($folders)) {
try {
$this->folderMapper->setToFolders($bookmark->getId(), $folders);
} catch (UnauthorizedAccessError $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Could not set some folders']], Http::STATUS_BAD_REQUEST);
} catch (DoesNotExistException $e) {
return new JSONResponse(['status' => 'error', 'data' => ['Could not set some folders']], Http::STATUS_BAD_REQUEST);
} catch (MultipleObjectsReturnedException $e) {
@ -522,11 +588,7 @@ class BookmarkController extends ApiController {
* @NoCSRFRequired
* @CORS
*/
public function deleteBookmark($id = -1) {
if ($id === -1) {
return new JSONResponse([], Http::STATUS_BAD_REQUEST);
}
public function deleteBookmark($id) {
if (!Authorizer::hasPermission(Authorizer::PERM_EDIT, $this->authorizer->getPermissionsForBookmark($id, $this->userId, $this->request))) {
return new JSONResponse(['status' => 'error', 'data' => 'Insufficient permissions'], Http::STATUS_BAD_REQUEST);
}

View File

@ -115,13 +115,23 @@ class BookmarkMapper extends QBMapper {
*/
public function findAll($userId, array $filters, string $conjunction = 'and', string $sortBy = 'lastmodified', int $offset = 0, int $limit = -1) {
$qb = $this->db->getQueryBuilder();
$qb->select(Bookmark::$columns);
$qb->groupBy(Bookmark::$columns);
$bookmark_cols = array_map(function($c) {
return 'b.'.$c;
},Bookmark::$columns);
$qb->select($bookmark_cols);
$qb->groupBy($bookmark_cols);
// Finds bookmarks in 2-levels nested shares only
$qb
->from('bookmarks', 'b')
->leftJoin('b', 'bookmarks_tags', 't', $qb->expr()->eq('t.bookmark_id', 'b.id'))
->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId)));
->leftJoin('b', 'bookmarks_folders_bookmarks', 'f', $qb->expr()->eq('f.bookmark_id', 'b.id'))
->leftJoin('f', 'bookmarks_shares', 's', $qb->expr()->eq('f.folder_id', 's.folder_id'))
->leftJoin('s', 'bookmarks_shared', 'p', $qb->expr()->eq('s.id', 'p.share_id'))
->where($qb->expr()->eq('b.user_id', $qb->createPositionalParameter($userId)))
->orWhere($qb->expr()->eq('p.user_id', $qb->createPositionalParameter($userId)));
$this->_findBookmarksBuildFilter($qb, $filters, $conjunction);
$this->_queryBuilderSortAndPaginate($qb, $sortBy, $offset, $limit);

View File

@ -186,16 +186,16 @@ class FolderMapper extends QBMapper {
public function hasDescendantBookmark($folderId, $descendantBookmarkId) {
$newAncestors = $this->findByBookmark($descendantBookmarkId);
do {
$newAncestors = array_map(function ($ancestor) {
return $this->find($ancestor->getParentFolder());
}, array_filter($newAncestors, function ($ancestor) {
return $ancestor->getParentFolder() !== -1 && $ancestor->getId() !== -1;
}));
foreach ($newAncestors as $ancestor) {
if ($ancestor->getId() === $folderId) {
return true;
}
}
$newAncestors = array_map(function ($ancestor) {
return $this->find($ancestor->getParentFolder());
}, array_filter($newAncestors, function ($ancestor) {
return $ancestor->getParentFolder() !== -1 && $ancestor->getId() !== -1;
}));
} while (count($newAncestors) > 0);
return false;
}
@ -623,7 +623,6 @@ class FolderMapper extends QBMapper {
* @param array $folders Set of folders ids to add the bookmark to
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
* @throws UnauthorizedAccessError
*/
public function setToFolders(int $bookmarkId, array $folders) {
if (0 === count($folders)) {
@ -647,7 +646,6 @@ class FolderMapper extends QBMapper {
* @param array $folders Set of folders ids to add the bookmark to
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
* @throws UnauthorizedAccessError
*/
public function addToFolders(int $bookmarkId, array $folders) {
$bookmark = $this->bookmarkMapper->find($bookmarkId);
@ -655,9 +653,6 @@ class FolderMapper extends QBMapper {
// check if folder exists
if ($folderId !== -1 && $folderId !== '-1') {
$folder = $this->find($folderId);
if ($folder->getUserId() !== $bookmark->getUserId()) {
throw new UnauthorizedAccessError('Can only add bookmarks to folders of the same user');
}
}
// check if this folder<->bookmark mapping already exists

View File

@ -10,6 +10,10 @@ use OCA\Bookmarks\Db\Folder;
use OCA\Bookmarks\Db\FolderMapper;
use OCA\Bookmarks\Db\PublicFolder;
use OCA\Bookmarks\Db\PublicFolderMapper;
use OCA\Bookmarks\Db\Share;
use OCA\Bookmarks\Db\SharedFolder;
use OCA\Bookmarks\Db\SharedFolderMapper;
use OCA\Bookmarks\Db\ShareMapper;
use OCA\Bookmarks\Db\TagMapper;
use OCA\Bookmarks\Service\Authorizer;
use OCA\Bookmarks\Service\LinkExplorer;
@ -112,6 +116,8 @@ class BookmarkControllerTest extends TestCase {
$this->tagMapper = \OC::$server->query(TagMapper::class);
$this->folderMapper = \OC::$server->query(FolderMapper::class);
$this->publicFolderMapper = \OC::$server->query(PublicFolderMapper::class);
$this->shareMapper = \OC::$server->query(ShareMapper::class);
$this->sharedFolderMapper = \OC::$server->query(SharedFolderMapper::class);
$bookmarkPreviewer = \OC::$server->query(BookmarkPreviewer::class);
$faviconPreviewer= \OC::$server->query(FaviconPreviewer::class);
@ -152,19 +158,22 @@ class BookmarkControllerTest extends TestCase {
$this->tagMapper->addTo(['four'], $bookmark2->getId());
$this->bookmark1Id = $bookmark1->getId();
$this->bookmark2Id = $bookmark2->getId();
// Finish up publicRequest stub
$this->publicRequest->method('getHeader')
->willReturn('');
}
public function setupBookmarksWithPublicFolder() {
$this->setupBookmarks();
$this->folder1 = new Folder();
$this->folder1->setTitle('foo');
$this->folder1->setParentFolder(-1);
$this->folder1->setUserId($this->userId);
$this->folderMapper->insert($this->folder1);
$this->folder2 = new Folder();
$this->folder2->setTitle('bar');
$this->folder2->setParentFolder($this->folder1->getId());
$this->folder2->setUserId($this->userId);
$this->folderMapper->insert($this->folder2);
$this->publicFolder = new PublicFolder();
$this->publicFolder->setFolderId($this->folder1->getId());
@ -174,34 +183,28 @@ class BookmarkControllerTest extends TestCase {
$this->publicRequest->method('getHeader')
->willReturn('Bearer '.$this->publicFolder->getId());
$this->folder2 = new Folder();
$this->folder2->setTitle('bar');
$this->folder2->setParentFolder($this->folder1->getId());
$this->folder2->setUserId($this->userId);
$this->folderMapper->insert($this->folder2);
$this->folderMapper->addToFolders($this->bookmark1Id, [$this->folder1->getId()]);
$this->folderMapper->addToFolders($this->bookmark2Id, [$this->folder2->getId()]);
}
$bookmark1 = Bookmark::fromArray([
'userId' => $this->userId,
'url' => "https://www.golem.de",
'title' => "Golem",
'description' => "PublicNoTag"
]);
$bookmark1 = $this->bookmarkMapper->insertOrUpdate($bookmark1);
$this->tagMapper->addTo(['four'], $bookmark1->getId());
$this->folderMapper->addToFolders($bookmark1->getId(), [$this->folder2->getId()]);
public function setupBookmarksWithSharedFolder() {
$this->setupBookmarksWithPublicFolder();
$this->share = new Share();
$this->share->setFolderId($this->folder1->getId());
$this->share->setOwner($this->userId);
$this->share->setParticipant($this->otherUserId);
$this->share->setType(ShareMapper::TYPE_USER);
$this->share->setCanWrite(true);
$this->share->setCanShare(false);
$this->shareMapper->insert($this->share);
$bookmark2 = Bookmark::fromArray([
'userId' => $this->userId,
'url' => "https://9gag.com",
'title' => "9gag",
'description' => "PublicTag"
]);
$bookmark2 = $this->bookmarkMapper->insertOrUpdate($bookmark2);
$this->tagMapper->addTo(['four'], $bookmark2->getId());
$this->folderMapper->addToFolders($bookmark2->getId(), [$this->folder2->getId()]);
$this->bookmark1Id = $bookmark1->getId();
$this->bookmark2Id = $bookmark2->getId();
$this->sharedFolder = new SharedFolder();
$this->sharedFolder->setShareId($this->share->getId());
$this->sharedFolder->setTitle('foo');
$this->sharedFolder->setParentFolder(-1);
$this->sharedFolder->setUserId($this->otherUser);
$this->sharedFolder->setIndex(0);
$this->sharedFolderMapper->insert($this->sharedFolder);
}
public function testRead() {
@ -338,7 +341,7 @@ class BookmarkControllerTest extends TestCase {
$this->setupBookmarksWithPublicFolder();
$output = $this->publicController->getBookmarks(-1, null,"or", "", [],10,false, $this->folder2->getId());
$data = $output->getData();
$this->assertEquals(2, count($data['data']));
$this->assertEquals(1, count($data['data'])); // TODO: 1-level search Limit!
}
public function testPublicCreateFail() {
@ -364,10 +367,100 @@ class BookmarkControllerTest extends TestCase {
$this->assertEquals('error', $res->getData()['status']);
}
public function testReadShared() {
$this->cleanDB();
$this->setupBookmarksWithSharedFolder();
$output = $this->otherController->getSingleBookmark($this->bookmark2Id);
$data = $output->getData();
$this->assertEquals('success', $data['status']);
$this->assertEquals("https://9gag.com/", $data['item']['url']);
}
public function testQueryShared() {
$this->cleanDB();
$this->setupBookmarksWithSharedFolder();
$output = $this->otherController->getBookmarks();
$data = $output->getData();
$this->assertEquals(1, count($data['data'])); // TODO: 1 level search Limit
}
public function testCreateShared() {
$this->cleanDB();
$this->setupBookmarksWithSharedFolder();
$res = $this->otherController->newBookmark("https://www.heise.de", 'Heise', "Private", ["four"],[$this->folder1->getId()]);
$this->assertEquals('success', $res->getData()['status']);
// the bookmark should exist
$this->bookmarkMapper->findByUrl($this->userId, "https://www.heise.de");
// user should see this bookmark
$output = $this->controller->getBookmarks();
$data = $output->getData();
$this->assertEquals(3, count($data['data']));
// others should see this bookmark
$output = $this->otherController->getBookmarks();
$data = $output->getData();
$this->assertEquals(2, count($data['data'])); // TODO: 1 level search limit
}
public function testEditBookmarkShared() {
$this->cleanDB();
$this->setupBookmarksWithSharedFolder();
$res = $this->controller->newBookmark("https://www.heise.de", 'Heise', "PublicNoTag", ["four"],[$this->folder1->getId()]);
$this->assertEquals('success', $res->getData()['status']);
$id = $res->getData()['item']['id'];
$res = $this->otherController->editBookmark($id, 'https://www.heise.de', '');
$this->assertEquals('success', $res->getData()['status']);
$bookmark = $this->bookmarkMapper->find($id);
$this->assertEquals("https://www.heise.de/", $bookmark->getUrl()); // normalized URL
$this->assertEquals("", $bookmark->getTitle());
}
public function testDeleteBookmarkShared() {
$this->cleanDB();
$this->setupBookmarksWithSharedFolder();
$res = $this->controller->newBookmark("https://www.google.com", 'Google', "PrivateTag", ["one", 'two'], [$this->folder1->getId()]);
$this->assertEquals('success', $res->getData()['status']);
$id = $res->getData()['item']['id'];
$res = $this->otherController->deleteBookmark($id);
$this->assertEquals('success', $res->getData()['status']);
$exception = null;
try {
$this->bookmarkMapper->findByUrl($this->userId, "https://www.google.com");
}catch(\Exception $e){
$exception = $e;
}
$this->assertInstanceOf(DoesNotExistException::class, $exception, 'Expected bookmark not to exist and throw');
}
public function testClickSharedFail() {
$this->cleanDB();
$this->setupBookmarksWithSharedFolder();
$r = $this->otherController->clickBookmark('https://www.golem.de');
$this->assertInstanceOf(JSONResponse::class, $r);
$this->assertNotSame(Http::STATUS_OK, $r->getStatus());
}
public function cleanDB() {
$query1 = \OC_DB::prepare('DELETE FROM *PREFIX*bookmarks');
$query1->execute();
$query2 = \OC_DB::prepare('DELETE FROM *PREFIX*bookmarks_tags');
$query2->execute();
$query3 = \OC_DB::prepare('DELETE FROM *PREFIX*bookmarks_folders');
$query3->execute();
$query4 = \OC_DB::prepare('DELETE FROM *PREFIX*bookmarks_folders_bookmarks');
$query4->execute();
$query5 = \OC_DB::prepare('DELETE FROM *PREFIX*bookmarks_folders_public');
$query5->execute();
$query6 = \OC_DB::prepare('DELETE FROM *PREFIX*bookmarks_shared');
$query6->execute();
$query7 = \OC_DB::prepare('DELETE FROM *PREFIX*bookmarks_shares');
$query7->execute();
}
}

View File

@ -192,6 +192,7 @@ class FolderControllerTest extends TestCase {
$this->sharedFolder->setTitle('foo');
$this->sharedFolder->setParentFolder(-1);
$this->sharedFolder->setUserId($this->otherUser);
$this->sharedFolder->setIndex(0);
$this->sharedFolderMapper->insert($this->sharedFolder);
}