diff --git a/lib/private/share20/defaultshareprovider.php b/lib/private/share20/defaultshareprovider.php index 7f21d3aadf..5805e41d41 100644 --- a/lib/private/share20/defaultshareprovider.php +++ b/lib/private/share20/defaultshareprovider.php @@ -69,19 +69,20 @@ class DefaultShareProvider implements IShareProvider { } /** - * Get all childre of this share + * Get all children of this share * - * @param IShare $share + * @param IShare $parent * @return IShare[] */ - private function getChildren(IShare $share) { + public function getChildren(IShare $parent) { $children = []; $qb = $this->dbConn->getQueryBuilder(); $qb->select('*') ->from('share') ->where($qb->expr()->eq('parent', $qb->createParameter('parent'))) - ->setParameter(':parent', $share->getId()); + ->setParameter(':parent', $parent->getId()) + ->orderBy('id'); $cursor = $qb->execute(); while($data = $cursor->fetch()) { @@ -92,51 +93,16 @@ class DefaultShareProvider implements IShareProvider { return $children; } - /** - * Delete all the children of this share - * - * @param IShare $share - */ - protected function deleteChildren(IShare $share) { - foreach($this->getChildren($share) as $child) { - $this->delete($child); - } - } - /** * Delete a share * - * @param Share $share + * @param IShare $share * @throws BackendError */ public function delete(IShare $share) { - $this->deleteChildren($share); - // Fetch share to make sure it exists $share = $this->getShareById($share->getId()); - $shareType = $share->getShareType(); - $sharedWith = ''; - if ($shareType === \OCP\Share::SHARE_TYPE_USER) { - $sharedWith = $share->getSharedWith()->getUID(); - } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) { - $sharedWith = $share->getSharedWith()->getGID(); - } - - $hookParams = [ - 'id' => $share->getId(), - 'itemType' => $share->getPath() instanceof \OCP\Files\File ? 'file' : 'folder', - 'itemSource' => $share->getPath()->getId(), - 'shareType' => $shareType, - 'shareWith' => $sharedWith, - 'itemparent' => $share->getParent(), - 'uidOwner' => $share->getSharedBy()->getUID(), - 'fileSource' => $share->getPath()->getId(), - 'fileTarget' => $share->getTarget() - ]; - - \OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams); - $qb = $this->dbConn->getQueryBuilder(); $qb->delete('share') ->where($qb->expr()->eq('id', $qb->createParameter('id'))) @@ -147,8 +113,6 @@ class DefaultShareProvider implements IShareProvider { } catch (\Exception $e) { throw new BackendError(); } - - \OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams); } /** @@ -195,8 +159,9 @@ class DefaultShareProvider implements IShareProvider { /** * Get shares for a given path * + * @param \OCP\IUser $user * @param \OCP\Files\Node $path - * @param Share[] + * @return IShare[] */ public function getSharesByPath(\OCP\IUser $user, \OCP\Files\Node $path) { throw new \Exception(); @@ -253,7 +218,7 @@ class DefaultShareProvider implements IShareProvider { $share->setSharedBy($this->userManager->get($data['uid_owner'])); // TODO: getById can return an array. How to handle this properly?? - $path = $this->userFolder->getById($data['file_source']); + $path = $this->userFolder->getById((int)$data['file_source']); $path = $path[0]; $share->setPath($path); diff --git a/lib/private/share20/ishareprovider.php b/lib/private/share20/ishareprovider.php index b3f4eb6868..833de1b58f 100644 --- a/lib/private/share20/ishareprovider.php +++ b/lib/private/share20/ishareprovider.php @@ -45,7 +45,7 @@ interface IShareProvider { /** * Delete a share * - * @param Share $share + * @param IShare $share * @throws BackendError */ public function delete(IShare $share); @@ -70,11 +70,20 @@ interface IShareProvider { */ public function getShareById($id); + /** + * Get children + * + * @param IShare $parent + * @return IShare[] + */ + public function getChildren(IShare $parent); + /** * Get shares for a given path * + * @param \OCP\IUser $user * @param \OCP\Files\Node $path - * @param Share[] + * @return IShare[] */ public function getSharesByPath(\OCP\IUser $user, \OCP\Files\Node $path); diff --git a/lib/private/share20/manager.php b/lib/private/share20/manager.php index 52e43a9aa9..57d8496797 100644 --- a/lib/private/share20/manager.php +++ b/lib/private/share20/manager.php @@ -96,6 +96,25 @@ class Manager { throw new \Exception(); } + /** + * Delete all the children of this share + * + * @param IShare $share + * @return IShare[] List of deleted shares + */ + protected function deleteChildren(IShare $share) { + $deletedShares = []; + foreach($this->defaultProvider->getChildren($share) as $child) { + $deletedChildren = $this->deleteChildren($child); + $deletedShares = array_merge($deletedShares, $deletedChildren); + + $this->defaultProvider->delete($child); + $deletedShares[] = $child; + } + + return $deletedShares; + } + /** * Delete a share * @@ -104,11 +123,58 @@ class Manager { * @throws \OC\Share20\Exception\BackendError */ public function deleteShare(IShare $share) { - if ($share->getId() === null) { - throw new ShareNotFound(); - } + // Just to make sure we have all the info + $share = $this->getShareById($share->getId()); + $formatHookParams = function($share) { + // Prepare hook + $shareType = $share->getShareType(); + $sharedWith = ''; + if ($shareType === \OCP\Share::SHARE_TYPE_USER) { + $sharedWith = $share->getSharedWith()->getUID(); + } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) { + $sharedWith = $share->getSharedWith()->getGID(); + } else if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) { + $sharedWith = $share->getSharedWith(); + } + + $hookParams = [ + 'id' => $share->getId(), + 'itemType' => $share->getPath() instanceof \OCP\Files\File ? 'file' : 'folder', + 'itemSource' => $share->getPath()->getId(), + 'shareType' => $shareType, + 'shareWith' => $sharedWith, + 'itemparent' => $share->getParent(), + 'uidOwner' => $share->getSharedBy()->getUID(), + 'fileSource' => $share->getPath()->getId(), + 'fileTarget' => $share->getTarget() + ]; + return $hookParams; + }; + + $hookParams = $formatHookParams($share); + + // Emit pre-hook + \OC_Hook::emit('OCP\Share', 'pre_unshare', $hookParams); + + // Get all children and delete them as well + $deletedShares = $this->deleteChildren($share); + + // Do the actual delete $this->defaultProvider->delete($share); + + // All the deleted shares caused by this delete + $deletedShares[] = $share; + + //Format hook info + $formattedDeletedShares = array_map(function($share) use ($formatHookParams) { + return $formatHookParams($share); + }, $deletedShares); + + $hookParams['deletedShares'] = $formattedDeletedShares; + + // Emit post hook + \OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams); } /** @@ -131,6 +197,10 @@ class Manager { * @throws ShareNotFound */ public function getShareById($id) { + if ($id === null) { + throw new ShareNotFound(); + } + $share = $this->defaultProvider->getShareById($id); if ($share->getSharedWith() !== $this->currentUser && diff --git a/tests/lib/share20/defaultshareprovidertest.php b/tests/lib/share20/defaultshareprovidertest.php index f8b6f98be7..4c0b552394 100644 --- a/tests/lib/share20/defaultshareprovidertest.php +++ b/tests/lib/share20/defaultshareprovidertest.php @@ -368,47 +368,8 @@ class DefaultShareProviderTest extends \Test\TestCase { $cursor->closeCursor(); - $path = $this->getMock('OCP\Files\File'); - $path - ->expects($this->exactly(2)) - ->method('getId') - ->willReturn(42); - - $sharedWith = $this->getMock('OCP\IUser'); - $sharedWith - ->expects($this->once()) - ->method('getUID') - ->willReturn('sharedWith'); - $sharedBy = $this->getMock('OCP\IUser'); - $sharedBy - ->expects($this->once()) - ->method('getUID') - ->willReturn('sharedBy'); - $share = $this->getMock('OC\Share20\IShare'); - $share - ->method('getId') - ->willReturn($id); - $share - ->expects($this->once()) - ->method('getShareType') - ->willReturn(\OCP\Share::SHARE_TYPE_USER); - $share - ->expects($this->exactly(3)) - ->method('getPath') - ->willReturn($path); - $share - ->expects($this->once()) - ->method('getSharedWith') - ->willReturn($sharedWith); - $share - ->expects($this->once()) - ->method('getSharedBy') - ->willReturn($sharedBy); - $share - ->expects($this->once()) - ->method('getTarget') - ->willReturn('myTarget'); + $share->method('getId')->willReturn($id); $provider = $this->getMockBuilder('OC\Share20\DefaultShareProvider') ->setConstructorArgs([ @@ -418,38 +379,13 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->userFolder, ] ) - ->setMethods(['deleteChildren', 'getShareById']) + ->setMethods(['getShareById']) ->getMock(); - $provider - ->expects($this->once()) - ->method('deleteChildren'); $provider ->expects($this->once()) ->method('getShareById') ->willReturn($share); - $hookListner = $this->getMockBuilder('Dummy')->setMethods(['listen'])->getMock(); - \OCP\Util::connectHook('OCP\Share', 'pre_unshare', $hookListner, 'listen'); - \OCP\Util::connectHook('OCP\Share', 'post_unshare', $hookListner, 'listen'); - - $hookListnerExpects = [ - 'id' => $id, - 'itemType' => 'file', - 'itemSource' => 42, - 'shareType' => \OCP\Share::SHARE_TYPE_USER, - 'shareWith' => 'sharedWith', - 'itemparent' => null, - 'uidOwner' => 'sharedBy', - 'fileSource' => 42, - 'fileTarget' => 'myTarget', - ]; - - $hookListner - ->expects($this->exactly(2)) - ->method('listen') - ->with($hookListnerExpects); - - $provider->delete($share); $qb = $this->dbConn->getQueryBuilder(); @@ -463,116 +399,6 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->assertEmpty($result); } - public function testDeleteNestedShares() { - $qb = $this->dbConn->getQueryBuilder(); - $qb->insert('share') - ->values([ - 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER), - 'share_with' => $qb->expr()->literal('sharedWith'), - 'uid_owner' => $qb->expr()->literal('sharedBy'), - 'item_type' => $qb->expr()->literal('file'), - 'file_source' => $qb->expr()->literal(42), - 'file_target' => $qb->expr()->literal('myTarget'), - 'permissions' => $qb->expr()->literal(13), - ]); - $this->assertEquals(1, $qb->execute()); - - // Get the id - $qb = $this->dbConn->getQueryBuilder(); - $cursor = $qb->select('id') - ->from('share') - ->setMaxResults(1) - ->orderBy('id', 'DESC') - ->execute(); - $id1 = $cursor->fetch(); - $id1 = $id1['id']; - $cursor->closeCursor(); - - - $qb = $this->dbConn->getQueryBuilder(); - $qb->insert('share') - ->values([ - 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER), - 'share_with' => $qb->expr()->literal('sharedWith'), - 'uid_owner' => $qb->expr()->literal('sharedBy'), - 'item_type' => $qb->expr()->literal('file'), - 'file_source' => $qb->expr()->literal(42), - 'file_target' => $qb->expr()->literal('myTarget'), - 'permissions' => $qb->expr()->literal(13), - 'parent' => $qb->expr()->literal($id1), - ]); - $this->assertEquals(1, $qb->execute()); - - // Get the id - $qb = $this->dbConn->getQueryBuilder(); - $cursor = $qb->select('id') - ->from('share') - ->setMaxResults(1) - ->orderBy('id', 'DESC') - ->execute(); - $id2 = $cursor->fetch(); - $id2 = $id2['id']; - $cursor->closeCursor(); - - - $qb = $this->dbConn->getQueryBuilder(); - $qb->insert('share') - ->values([ - 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER), - 'share_with' => $qb->expr()->literal('sharedWith'), - 'uid_owner' => $qb->expr()->literal('sharedBy'), - 'item_type' => $qb->expr()->literal('file'), - 'file_source' => $qb->expr()->literal(42), - 'file_target' => $qb->expr()->literal('myTarget'), - 'permissions' => $qb->expr()->literal(13), - 'parent' => $qb->expr()->literal($id2), - ]); - $this->assertEquals(1, $qb->execute()); - - $storage = $this->getMock('OC\Files\Storage\Storage'); - $storage - ->method('getOwner') - ->willReturn('shareOwner'); - $path = $this->getMock('OCP\Files\Node'); - $path - ->method('getStorage') - ->wilLReturn($storage); - $this->userFolder - ->method('getById') - ->with(42) - ->willReturn([$path]); - - $sharedWith = $this->getMock('OCP\IUser'); - $sharedWith - ->method('getUID') - ->willReturn('sharedWith'); - $sharedBy = $this->getMock('OCP\IUser'); - $sharedBy - ->method('getUID') - ->willReturn('sharedBy'); - $shareOwner = $this->getMock('OCP\IUser'); - $this->userManager - ->method('get') - ->will($this->returnValueMap([ - ['sharedWith', $sharedWith], - ['sharedBy', $sharedBy], - ['shareOwner', $shareOwner], - ])); - - $share = $this->provider->getShareById($id1); - $this->provider->delete($share); - - $qb = $this->dbConn->getQueryBuilder(); - $qb->select('*') - ->from('share'); - - $cursor = $qb->execute(); - $result = $cursor->fetchAll(); - $cursor->closeCursor(); - - $this->assertEmpty($result); - } - /** * @expectedException \OC\Share20\Exception\BackendError */ @@ -581,29 +407,6 @@ class DefaultShareProviderTest extends \Test\TestCase { $share ->method('getId') ->willReturn(42); - $share - ->expects($this->once()) - ->method('getShareType') - ->willReturn(\OCP\Share::SHARE_TYPE_LINK); - - $path = $this->getMock('OCP\Files\Folder'); - $path - ->expects($this->exactly(2)) - ->method('getId') - ->willReturn(100); - $share - ->expects($this->exactly(3)) - ->method('getPath') - ->willReturn($path); - - $sharedBy = $this->getMock('OCP\IUser'); - $sharedBy - ->expects($this->once()) - ->method('getUID'); - $share - ->expects($this->once()) - ->method('getSharedBy') - ->willReturn($sharedBy); $expr = $this->getMock('OCP\DB\QueryBuilder\IExpressionBuilder'); $qb = $this->getMock('OCP\DB\QueryBuilder\IQueryBuilder'); @@ -637,12 +440,8 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->userFolder, ] ) - ->setMethods(['deleteChildren', 'getShareById']) + ->setMethods(['getShareById']) ->getMock(); - $provider - ->expects($this->once()) - ->method('deleteChildren') - ->with($share); $provider ->expects($this->once()) ->method('getShareById') @@ -651,4 +450,123 @@ class DefaultShareProviderTest extends \Test\TestCase { $provider->delete($share); } + + public function testGetChildren() { + $qb = $this->dbConn->getQueryBuilder(); + $qb->insert('share') + ->values([ + 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER), + 'share_with' => $qb->expr()->literal('sharedWith'), + 'uid_owner' => $qb->expr()->literal('sharedBy'), + 'item_type' => $qb->expr()->literal('file'), + 'file_source' => $qb->expr()->literal(42), + 'file_target' => $qb->expr()->literal('myTarget'), + 'permissions' => $qb->expr()->literal(13), + ]); + $qb->execute(); + + // Get the id + $qb = $this->dbConn->getQueryBuilder(); + $cursor = $qb->select('id') + ->from('share') + ->setMaxResults(1) + ->orderBy('id', 'DESC') + ->execute(); + $id = $cursor->fetch(); + $id = $id['id']; + $cursor->closeCursor(); + + $qb = $this->dbConn->getQueryBuilder(); + $qb->insert('share') + ->values([ + 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER), + 'share_with' => $qb->expr()->literal('user1'), + 'uid_owner' => $qb->expr()->literal('user2'), + 'item_type' => $qb->expr()->literal('file'), + 'file_source' => $qb->expr()->literal(1), + 'file_target' => $qb->expr()->literal('myTarget1'), + 'permissions' => $qb->expr()->literal(2), + 'parent' => $qb->expr()->literal($id), + ]); + $qb->execute(); + + $qb = $this->dbConn->getQueryBuilder(); + $qb->insert('share') + ->values([ + 'share_type' => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP), + 'share_with' => $qb->expr()->literal('group1'), + 'uid_owner' => $qb->expr()->literal('user3'), + 'item_type' => $qb->expr()->literal('folder'), + 'file_source' => $qb->expr()->literal(3), + 'file_target' => $qb->expr()->literal('myTarget2'), + 'permissions' => $qb->expr()->literal(4), + 'parent' => $qb->expr()->literal($id), + ]); + $qb->execute(); + + + $storage = $this->getMock('OC\Files\Storage\Storage'); + $storage + ->method('getOwner') + ->willReturn('shareOwner'); + $path1 = $this->getMock('OCP\Files\File'); + $path1->expects($this->once())->method('getStorage')->willReturn($storage); + $path2 = $this->getMock('OCP\Files\Folder'); + $path2->expects($this->once())->method('getStorage')->willReturn($storage); + $this->userFolder + ->method('getById') + ->will($this->returnValueMap([ + [1, [$path1]], + [3, [$path2]], + ])); + + $shareOwner = $this->getMock('OCP\IUser'); + $user1 = $this->getMock('OCP\IUser'); + $user2 = $this->getMock('OCP\IUser'); + $user3 = $this->getMock('OCP\IUser'); + $this->userManager + ->method('get') + ->will($this->returnValueMap([ + ['shareOwner', $shareOwner], + ['user1', $user1], + ['user2', $user2], + ['user3', $user3], + ])); + + $group1 = $this->getMock('OCP\IGroup'); + $this->groupManager + ->method('get') + ->will($this->returnValueMap([ + ['group1', $group1] + ])); + + $share = $this->getMock('\OC\Share20\IShare'); + $share->method('getId')->willReturn($id); + + $children = $this->provider->getChildren($share); + + $this->assertCount(2, $children); + + //Child1 + $this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $children[0]->getShareType()); + $this->assertEquals($user1, $children[0]->getSharedWith()); + $this->assertEquals($user2, $children[0]->getSharedBy()); + $this->assertEquals($shareOwner, $children[0]->getShareOwner()); + $this->assertEquals($path1, $children[0]->getPath()); + $this->assertEquals(2, $children[0]->getPermissions()); + $this->assertEquals(null, $children[0]->getToken()); + $this->assertEquals(null, $children[0]->getExpirationDate()); + $this->assertEquals('myTarget1', $children[0]->getTarget()); + + //Child2 + $this->assertEquals(\OCP\Share::SHARE_TYPE_GROUP, $children[1]->getShareType()); + $this->assertEquals($group1, $children[1]->getSharedWith()); + $this->assertEquals($user3, $children[1]->getSharedBy()); + $this->assertEquals($shareOwner, $children[1]->getShareOwner()); + $this->assertEquals($path2, $children[1]->getPath()); + $this->assertEquals(4, $children[1]->getPermissions()); + $this->assertEquals(null, $children[1]->getToken()); + $this->assertEquals(null, $children[1]->getExpirationDate()); + $this->assertEquals('myTarget2', $children[1]->getTarget()); + } } diff --git a/tests/lib/share20/managertest.php b/tests/lib/share20/managertest.php index fc6c30692f..54be903356 100644 --- a/tests/lib/share20/managertest.php +++ b/tests/lib/share20/managertest.php @@ -94,20 +94,301 @@ class ManagerTest extends \Test\TestCase { $this->manager->deleteShare($share); } - public function testDelete() { - $share = $this->getMock('\OC\Share20\IShare'); + public function dataTestDelete() { + $user = $this->getMock('\OCP\IUser'); + $user->method('getUID')->willReturn('sharedWithUser'); + + $group = $this->getMock('\OCP\IGroup'); + $group->method('getGID')->willReturn('sharedWithGroup'); + + return [ + [\OCP\Share::SHARE_TYPE_USER, $user, 'sharedWithUser'], + [\OCP\Share::SHARE_TYPE_GROUP, $group, 'sharedWithGroup'], + [\OCP\Share::SHARE_TYPE_LINK, '', ''], + [\OCP\Share::SHARE_TYPE_REMOTE, 'foo@bar.com', 'foo@bar.com'], + ]; + } + + /** + * @dataProvider dataTestDelete + */ + public function testDelete($shareType, $sharedWith, $sharedWith_string) { + $manager = $this->getMockBuilder('\OC\Share20\Manager') + ->setConstructorArgs([ + $this->user, + $this->userManager, + $this->groupManager, + $this->logger, + $this->appConfig, + $this->userFolder, + $this->defaultProvider + ]) + ->setMethods(['getShareById', 'deleteChildren']) + ->getMock(); + + $sharedBy = $this->getMock('\OCP\IUser'); + $sharedBy->method('getUID')->willReturn('sharedBy'); + + $path = $this->getMock('\OCP\Files\File'); + $path->method('getId')->willReturn(1); + + $share = $this->getMock('\OC\Share20\IShare'); + $share->method('getId')->willReturn(42); + $share->method('getShareType')->willReturn($shareType); + $share->method('getSharedWith')->willReturn($sharedWith); + $share->method('getSharedBy')->willReturn($sharedBy); + $share->method('getPath')->willReturn($path); + $share->method('getTarget')->willReturn('myTarget'); + + $manager->expects($this->once())->method('getShareById')->with(42)->willReturn($share); + $manager->expects($this->once())->method('deleteChildren')->with($share); - $share - ->expects($this->once()) - ->method('getId') - ->with() - ->willReturn(42); $this->defaultProvider ->expects($this->once()) ->method('delete') ->with($share); - $this->manager->deleteShare($share); + $hookListner = $this->getMockBuilder('Dummy')->setMethods(['pre', 'post'])->getMock(); + \OCP\Util::connectHook('OCP\Share', 'pre_unshare', $hookListner, 'pre'); + \OCP\Util::connectHook('OCP\Share', 'post_unshare', $hookListner, 'post'); + + $hookListnerExpectsPre = [ + 'id' => 42, + 'itemType' => 'file', + 'itemSource' => 1, + 'shareType' => $shareType, + 'shareWith' => $sharedWith_string, + 'itemparent' => null, + 'uidOwner' => 'sharedBy', + 'fileSource' => 1, + 'fileTarget' => 'myTarget', + ]; + + $hookListnerExpectsPost = [ + 'id' => 42, + 'itemType' => 'file', + 'itemSource' => 1, + 'shareType' => $shareType, + 'shareWith' => $sharedWith_string, + 'itemparent' => null, + 'uidOwner' => 'sharedBy', + 'fileSource' => 1, + 'fileTarget' => 'myTarget', + 'deletedShares' => [ + [ + 'id' => 42, + 'itemType' => 'file', + 'itemSource' => 1, + 'shareType' => $shareType, + 'shareWith' => $sharedWith_string, + 'itemparent' => null, + 'uidOwner' => 'sharedBy', + 'fileSource' => 1, + 'fileTarget' => 'myTarget', + ], + ], + ]; + + + $hookListner + ->expects($this->exactly(1)) + ->method('pre') + ->with($hookListnerExpectsPre); + $hookListner + ->expects($this->exactly(1)) + ->method('post') + ->with($hookListnerExpectsPost); + + $manager->deleteShare($share); + } + + public function testDeleteNested() { + $manager = $this->getMockBuilder('\OC\Share20\Manager') + ->setConstructorArgs([ + $this->user, + $this->userManager, + $this->groupManager, + $this->logger, + $this->appConfig, + $this->userFolder, + $this->defaultProvider + ]) + ->setMethods(['getShareById']) + ->getMock(); + + $sharedBy1 = $this->getMock('\OCP\IUser'); + $sharedBy1->method('getUID')->willReturn('sharedBy1'); + $sharedBy2 = $this->getMock('\OCP\IUser'); + $sharedBy2->method('getUID')->willReturn('sharedBy2'); + $sharedBy3 = $this->getMock('\OCP\IUser'); + $sharedBy3->method('getUID')->willReturn('sharedBy3'); + + $sharedWith1 = $this->getMock('\OCP\IUser'); + $sharedWith1->method('getUID')->willReturn('sharedWith1'); + $sharedWith2 = $this->getMock('\OCP\IGroup'); + $sharedWith2->method('getGID')->willReturn('sharedWith2'); + + $path = $this->getMock('\OCP\Files\File'); + $path->method('getId')->willReturn(1); + + $share1 = $this->getMock('\OC\Share20\IShare'); + $share1->method('getId')->willReturn(42); + $share1->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_USER); + $share1->method('getSharedWith')->willReturn($sharedWith1); + $share1->method('getSharedBy')->willReturn($sharedBy1); + $share1->method('getPath')->willReturn($path); + $share1->method('getTarget')->willReturn('myTarget1'); + + $share2 = $this->getMock('\OC\Share20\IShare'); + $share2->method('getId')->willReturn(43); + $share2->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_GROUP); + $share2->method('getSharedWith')->willReturn($sharedWith2); + $share2->method('getSharedBy')->willReturn($sharedBy2); + $share2->method('getPath')->willReturn($path); + $share2->method('getTarget')->willReturn('myTarget2'); + $share2->method('getParent')->willReturn(42); + + $share3 = $this->getMock('\OC\Share20\IShare'); + $share3->method('getId')->willReturn(44); + $share3->method('getShareType')->willReturn(\OCP\Share::SHARE_TYPE_LINK); + $share3->method('getSharedBy')->willReturn($sharedBy3); + $share3->method('getPath')->willReturn($path); + $share3->method('getTarget')->willReturn('myTarget3'); + $share3->method('getParent')->willReturn(43); + + $manager->expects($this->once())->method('getShareById')->with(42)->willReturn($share1); + + $this->defaultProvider + ->method('getChildren') + ->will($this->returnValueMap([ + [$share1, [$share2]], + [$share2, [$share3]], + [$share3, []], + ])); + + $this->defaultProvider + ->method('delete') + ->withConsecutive($share3, $share2, $share1); + + $hookListner = $this->getMockBuilder('Dummy')->setMethods(['pre', 'post'])->getMock(); + \OCP\Util::connectHook('OCP\Share', 'pre_unshare', $hookListner, 'pre'); + \OCP\Util::connectHook('OCP\Share', 'post_unshare', $hookListner, 'post'); + + $hookListnerExpectsPre = [ + 'id' => 42, + 'itemType' => 'file', + 'itemSource' => 1, + 'shareType' => \OCP\Share::SHARE_TYPE_USER, + 'shareWith' => 'sharedWith1', + 'itemparent' => null, + 'uidOwner' => 'sharedBy1', + 'fileSource' => 1, + 'fileTarget' => 'myTarget1', + ]; + + $hookListnerExpectsPost = [ + 'id' => 42, + 'itemType' => 'file', + 'itemSource' => 1, + 'shareType' => \OCP\Share::SHARE_TYPE_USER, + 'shareWith' => 'sharedWith1', + 'itemparent' => null, + 'uidOwner' => 'sharedBy1', + 'fileSource' => 1, + 'fileTarget' => 'myTarget1', + 'deletedShares' => [ + [ + 'id' => 44, + 'itemType' => 'file', + 'itemSource' => 1, + 'shareType' => \OCP\Share::SHARE_TYPE_LINK, + 'shareWith' => '', + 'itemparent' => 43, + 'uidOwner' => 'sharedBy3', + 'fileSource' => 1, + 'fileTarget' => 'myTarget3', + ], + [ + 'id' => 43, + 'itemType' => 'file', + 'itemSource' => 1, + 'shareType' => \OCP\Share::SHARE_TYPE_GROUP, + 'shareWith' => 'sharedWith2', + 'itemparent' => 42, + 'uidOwner' => 'sharedBy2', + 'fileSource' => 1, + 'fileTarget' => 'myTarget2', + ], + [ + 'id' => 42, + 'itemType' => 'file', + 'itemSource' => 1, + 'shareType' => \OCP\Share::SHARE_TYPE_USER, + 'shareWith' => 'sharedWith1', + 'itemparent' => null, + 'uidOwner' => 'sharedBy1', + 'fileSource' => 1, + 'fileTarget' => 'myTarget1', + ], + ], + ]; + + + $hookListner + ->expects($this->exactly(1)) + ->method('pre') + ->with($hookListnerExpectsPre); + $hookListner + ->expects($this->exactly(1)) + ->method('post') + ->with($hookListnerExpectsPost); + + $manager->deleteShare($share1); + } + + public function testDeleteChildren() { + $manager = $this->getMockBuilder('\OC\Share20\Manager') + ->setConstructorArgs([ + $this->user, + $this->userManager, + $this->groupManager, + $this->logger, + $this->appConfig, + $this->userFolder, + $this->defaultProvider + ]) + ->setMethods(['deleteShare']) + ->getMock(); + + $share = $this->getMock('\OC\Share20\IShare'); + + $child1 = $this->getMock('\OC\Share20\IShare'); + $child2 = $this->getMock('\OC\Share20\IShare'); + $child3 = $this->getMock('\OC\Share20\IShare'); + + $shares = [ + $child1, + $child2, + $child3, + ]; + + $this->defaultProvider + ->expects($this->exactly(4)) + ->method('getChildren') + ->will($this->returnCallback(function($_share) use ($share, $shares) { + if ($_share === $share) { + return $shares; + } + return []; + })); + + $this->defaultProvider + ->expects($this->exactly(3)) + ->method('delete') + ->withConsecutive($child1, $child2, $child3); + + $result = $this->invokePrivate($manager, 'deleteChildren', [$share]); + $this->assertSame($shares, $result); } /**