]> source.dussan.org Git - nextcloud-server.git/commitdiff
[Share 2.0] Add deleteFromSelf method
authorRoeland Jago Douma <rullzer@owncloud.com>
Thu, 21 Jan 2016 13:31:09 +0000 (14:31 +0100)
committerRoeland Jago Douma <rullzer@owncloud.com>
Fri, 22 Jan 2016 14:06:50 +0000 (15:06 +0100)
This allows recipient to delete a share. For user shares this is the
same as deleting (at least for now).
But for group shares this means creating a new share with type 2. With
permissions set to 0.

lib/private/share20/defaultshareprovider.php
lib/private/share20/ishareprovider.php
lib/private/share20/manager.php
tests/lib/share20/defaultshareprovidertest.php

index 5d768a4bc4b3ef5a0c6e26ad22afbb0679f0c94f..8c193c437d3168ff9e561b44e086275325aec4a9 100644 (file)
@@ -21,6 +21,7 @@
 namespace OC\Share20;
 
 use OC\Share20\Exception\InvalidShare;
+use OC\Share20\Exception\ProviderException;
 use OC\Share20\Exception\ShareNotFound;
 use OC\Share20\Exception\BackendError;
 use OCP\Files\NotFoundException;
@@ -241,6 +242,84 @@ class DefaultShareProvider implements IShareProvider {
                }
        }
 
+       /**
+        * Unshare a share from the recipient. If this is a group share
+        * this means we need a special entry in the share db.
+        *
+        * @param IShare $share
+        * @param IUser $recipient
+        * @throws BackendError
+        * @throws ProviderException
+        */
+       public function deleteFromSelf(IShare $share, IUser $recipient) {
+               if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
+
+                       /** @var IGroup $group */
+                       $group = $share->getSharedWith();
+
+                       if (!$group->inGroup($recipient)) {
+                               throw new ProviderException('Recipient not in receiving group');
+                       }
+
+                       // Try to fetch user specific share
+                       $qb = $this->dbConn->getQueryBuilder();
+                       $stmt = $qb->select('*')
+                               ->from('share')
+                               ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
+                               ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient->getUID())))
+                               ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
+                               ->execute();
+
+                       $data = $stmt->fetch();
+
+                       /*
+                        * Check if there already is a user specific group share.
+                        * If there is update it (if required).
+                        */
+                       if ($data === false) {
+                               $qb = $this->dbConn->getQueryBuilder();
+
+                               $type = $share->getPath() instanceof \OCP\Files\File ? 'file' : 'folder';
+
+                               //Insert new share
+                               $qb->insert('share')
+                                       ->values([
+                                               'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP),
+                                               'share_with' => $qb->createNamedParameter($recipient->getUID()),
+                                               'uid_owner' => $qb->createNamedParameter($share->getShareOwner()->getUID()),
+                                               'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()->getUID()),
+                                               'parent' => $qb->createNamedParameter($share->getId()),
+                                               'item_type' => $qb->createNamedParameter($type),
+                                               'item_source' => $qb->createNamedParameter($share->getPath()->getId()),
+                                               'file_source' => $qb->createNamedParameter($share->getPath()->getId()),
+                                               'file_target' => $qb->createNamedParameter($share->getTarget()),
+                                               'permissions' => $qb->createNamedParameter(0),
+                                               'stime' => $qb->createNamedParameter($share->getSharetime()),
+                                       ])->execute();
+
+                       } else if ($data['permissions'] !== 0) {
+
+                               // Update existing usergroup share
+                               $qb = $this->dbConn->getQueryBuilder();
+                               $qb->update('share')
+                                       ->set('permissions', $qb->createNamedParameter(0))
+                                       ->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
+                                       ->execute();
+                       }
+
+               } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
+
+                       if ($share->getSharedWith() !== $recipient) {
+                               throw new ProviderException('Recipient does not match');
+                       }
+
+                       // We can just delete user and link shares
+                       $this->delete($share);
+               } else {
+                       throw new ProviderException('Invalid shareType');
+               }
+       }
+
        /**
         * Get all shares by the given user. Sharetype and path can be used to filter.
         *
index 36d0f10c7f1e175c396e0ce7d07011719ea29719..17ee4abb9a8e2e9640a1c91a72f8e9e47e6f6aec 100644 (file)
@@ -57,6 +57,15 @@ interface IShareProvider {
         */
        public function delete(IShare $share);
 
+       /**
+        * Unshare a file from self as recipient.
+        * This may require special handling.
+        *
+        * @param IShare $share
+        * @param IUser $recipient
+        */
+       public function deleteFromSelf(IShare $share, IUser $recipient);
+
        /**
         * Get all shares by the given user
         *
index 3935307b977b9789cc03257162c196c79a81299a..ea6463c745c6f7201f7be486ee338a85cad8b226 100644 (file)
@@ -606,6 +606,22 @@ class Manager {
        }
 
 
+       /**
+        * Unshare a file as the recipient.
+        * This can be different from a regular delete for example when one of
+        * the users in a groups deletes that share. But the provider should
+        * handle this.
+        *
+        * @param IShare $share
+        * @param IUser $recipient
+        */
+       public function deleteFromSelf(IShare $share, IUser $recipient) {
+               list($providerId, $id) = $this->splitFullId($share->getId());
+               $provider = $this->factory->getProvider($providerId);
+
+               $provider->deleteFromSelf($share, $recipient);
+       }
+
        /**
         * Get shares shared by (initiated) by the provided user.
         *
index 812c6ecc27e98954b60d8de4c2f1eaae60685d42..574b1481c9599245667b0848d72810f0a6da7f79 100644 (file)
@@ -20,6 +20,7 @@
  */
 namespace Test\Share20;
 
+use OC\Share20\Exception\ProviderException;
 use OCP\IDBConnection;
 use OCP\IUserManager;
 use OCP\IGroupManager;
@@ -1061,7 +1062,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
                                'share_with' => $qb->expr()->literal('sharedWith'),
                                'uid_owner' => $qb->expr()->literal('shareOwner'),
                                'uid_initiator' => $qb->expr()->literal('shareOwner'),
-                               'item_type'   => $qb->expr()->literal('file'),
+                               'item_type' => $qb->expr()->literal('file'),
                                'file_source' => $qb->expr()->literal(42),
                                'file_target' => $qb->expr()->literal('myTarget'),
                                'permissions' => $qb->expr()->literal(13),
@@ -1076,7 +1077,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
                                'share_with' => $qb->expr()->literal('sharedWith'),
                                'uid_owner' => $qb->expr()->literal('shareOwner'),
                                'uid_initiator' => $qb->expr()->literal('sharedBy'),
-                               'item_type'   => $qb->expr()->literal('file'),
+                               'item_type' => $qb->expr()->literal('file'),
                                'file_source' => $qb->expr()->literal(42),
                                'file_target' => $qb->expr()->literal('userTarget'),
                                'permissions' => $qb->expr()->literal(0),
@@ -1123,4 +1124,301 @@ class DefaultShareProviderTest extends \Test\TestCase {
                $this->assertEquals(0, $share->getPermissions());
                $this->assertEquals('userTarget', $share->getTarget());
        }
+
+       public function testDeleteFromSelfGroupNoCustomShare() {
+               $qb = $this->dbConn->getQueryBuilder();
+               $stmt = $qb->insert('share')
+                       ->values([
+                               'share_type'    => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP),
+                               'share_with'    => $qb->expr()->literal('group'),
+                               'uid_owner'     => $qb->expr()->literal('user1'),
+                               'uid_initiator' => $qb->expr()->literal('user1'),
+                               'item_type'     => $qb->expr()->literal('file'),
+                               'file_source'   => $qb->expr()->literal(1),
+                               'file_target'   => $qb->expr()->literal('myTarget1'),
+                               'permissions'   => $qb->expr()->literal(2)
+                       ])->execute();
+               $this->assertEquals(1, $stmt);
+               $id = $qb->getLastInsertId();
+
+               $user1 = $this->getMock('\OCP\IUser');
+               $user1->method('getUID')->willReturn('user1');
+               $user2 = $this->getMock('\OCP\IUser');
+               $user2->method('getUID')->willReturn('user2');
+               $this->userManager->method('get')->will($this->returnValueMap([
+                       ['user1', $user1],
+                       ['user2', $user2],
+               ]));
+
+               $group = $this->getMock('\OCP\IGroup');
+               $group->method('getGID')->willReturn('group');
+               $group->method('inGroup')->with($user2)->willReturn(true);
+               $this->groupManager->method('get')->with('group')->willReturn($group);
+
+               $file = $this->getMock('\OCP\Files\File');
+               $file->method('getId')->willReturn(1);
+
+               $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+               $this->rootFolder->method('getById')->with(1)->willReturn([$file]);
+
+               $share = $this->provider->getShareById($id);
+
+               $this->provider->deleteFromSelf($share, $user2);
+
+               $qb = $this->dbConn->getQueryBuilder();
+               $stmt = $qb->select('*')
+                       ->from('share')
+                       ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(2)))
+                       ->execute();
+
+               $shares = $stmt->fetchAll();
+               $stmt->closeCursor();
+
+               $this->assertCount(1, $shares);
+               $share2 = $shares[0];
+               $this->assertEquals($id, $share2['parent']);
+               $this->assertEquals(0, $share2['permissions']);
+               $this->assertEquals('user2', $share2['share_with']);
+       }
+
+       public function testDeleteFromSelfGroupAlreadyCustomShare() {
+               $qb = $this->dbConn->getQueryBuilder();
+               $stmt = $qb->insert('share')
+                       ->values([
+                               'share_type'    => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP),
+                               'share_with'    => $qb->expr()->literal('group'),
+                               'uid_owner'     => $qb->expr()->literal('user1'),
+                               'uid_initiator' => $qb->expr()->literal('user1'),
+                               'item_type'     => $qb->expr()->literal('file'),
+                               'file_source'   => $qb->expr()->literal(1),
+                               'file_target'   => $qb->expr()->literal('myTarget1'),
+                               'permissions'   => $qb->expr()->literal(2)
+                       ])->execute();
+               $this->assertEquals(1, $stmt);
+               $id = $qb->getLastInsertId();
+
+               $qb = $this->dbConn->getQueryBuilder();
+               $stmt = $qb->insert('share')
+                       ->values([
+                               'share_type'    => $qb->expr()->literal(2),
+                               'share_with'    => $qb->expr()->literal('user2'),
+                               'uid_owner'     => $qb->expr()->literal('user1'),
+                               'uid_initiator' => $qb->expr()->literal('user1'),
+                               '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),
+                       ])->execute();
+               $this->assertEquals(1, $stmt);
+
+               $user1 = $this->getMock('\OCP\IUser');
+               $user1->method('getUID')->willReturn('user1');
+               $user2 = $this->getMock('\OCP\IUser');
+               $user2->method('getUID')->willReturn('user2');
+               $this->userManager->method('get')->will($this->returnValueMap([
+                       ['user1', $user1],
+                       ['user2', $user2],
+               ]));
+
+               $group = $this->getMock('\OCP\IGroup');
+               $group->method('getGID')->willReturn('group');
+               $group->method('inGroup')->with($user2)->willReturn(true);
+               $this->groupManager->method('get')->with('group')->willReturn($group);
+
+               $file = $this->getMock('\OCP\Files\File');
+               $file->method('getId')->willReturn(1);
+
+               $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+               $this->rootFolder->method('getById')->with(1)->willReturn([$file]);
+
+               $share = $this->provider->getShareById($id);
+
+               $this->provider->deleteFromSelf($share, $user2);
+
+               $qb = $this->dbConn->getQueryBuilder();
+               $stmt = $qb->select('*')
+                       ->from('share')
+                       ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(2)))
+                       ->execute();
+
+               $shares = $stmt->fetchAll();
+               $stmt->closeCursor();
+
+               $this->assertCount(1, $shares);
+               $share2 = $shares[0];
+               $this->assertEquals($id, $share2['parent']);
+               $this->assertEquals(0, $share2['permissions']);
+               $this->assertEquals('user2', $share2['share_with']);
+       }
+
+       /**
+        * @expectedException \OC\Share20\Exception\ProviderException
+        * @expectedExceptionMessage  Recipient not in receiving group
+        */
+       public function testDeleteFromSelfGroupUserNotInGroup() {
+               $qb = $this->dbConn->getQueryBuilder();
+               $stmt = $qb->insert('share')
+                       ->values([
+                               'share_type'    => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_GROUP),
+                               'share_with'    => $qb->expr()->literal('group'),
+                               'uid_owner'     => $qb->expr()->literal('user1'),
+                               'uid_initiator' => $qb->expr()->literal('user1'),
+                               'item_type'     => $qb->expr()->literal('file'),
+                               'file_source'   => $qb->expr()->literal(1),
+                               'file_target'   => $qb->expr()->literal('myTarget1'),
+                               'permissions'   => $qb->expr()->literal(2)
+                       ])->execute();
+               $this->assertEquals(1, $stmt);
+               $id = $qb->getLastInsertId();
+
+               $user1 = $this->getMock('\OCP\IUser');
+               $user1->method('getUID')->willReturn('user1');
+               $user2 = $this->getMock('\OCP\IUser');
+               $user2->method('getUID')->willReturn('user2');
+               $this->userManager->method('get')->will($this->returnValueMap([
+                       ['user1', $user1],
+                       ['user2', $user2],
+               ]));
+
+               $group = $this->getMock('\OCP\IGroup');
+               $group->method('getGID')->willReturn('group');
+               $group->method('inGroup')->with($user2)->willReturn(false);
+               $this->groupManager->method('get')->with('group')->willReturn($group);
+
+               $file = $this->getMock('\OCP\Files\File');
+               $file->method('getId')->willReturn(1);
+
+               $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+               $this->rootFolder->method('getById')->with(1)->willReturn([$file]);
+
+               $share = $this->provider->getShareById($id);
+
+               $this->provider->deleteFromSelf($share, $user2);
+       }
+
+       public function testDeleteFromSelfUser() {
+               $qb = $this->dbConn->getQueryBuilder();
+               $stmt = $qb->insert('share')
+                       ->values([
+                               'share_type'    => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+                               'share_with'    => $qb->expr()->literal('user2'),
+                               'uid_owner'     => $qb->expr()->literal('user1'),
+                               'uid_initiator' => $qb->expr()->literal('user1'),
+                               'item_type'     => $qb->expr()->literal('file'),
+                               'file_source'   => $qb->expr()->literal(1),
+                               'file_target'   => $qb->expr()->literal('myTarget1'),
+                               'permissions'   => $qb->expr()->literal(2)
+                       ])->execute();
+               $this->assertEquals(1, $stmt);
+               $id = $qb->getLastInsertId();
+
+               $user1 = $this->getMock('\OCP\IUser');
+               $user1->method('getUID')->willReturn('user1');
+               $user2 = $this->getMock('\OCP\IUser');
+               $user2->method('getUID')->willReturn('user2');
+               $this->userManager->method('get')->will($this->returnValueMap([
+                       ['user1', $user1],
+                       ['user2', $user2],
+               ]));
+
+               $file = $this->getMock('\OCP\Files\File');
+               $file->method('getId')->willReturn(1);
+
+               $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+               $this->rootFolder->method('getById')->with(1)->willReturn([$file]);
+
+               $share = $this->provider->getShareById($id);
+
+               $this->provider->deleteFromSelf($share, $user2);
+
+               $qb = $this->dbConn->getQueryBuilder();
+               $stmt = $qb->select('*')
+                       ->from('share')
+                       ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
+                       ->execute();
+
+               $shares = $stmt->fetchAll();
+               $stmt->closeCursor();
+
+               $this->assertCount(0, $shares);
+       }
+
+       /**
+        * @expectedException \OC\Share20\Exception\ProviderException
+        * @expectedExceptionMessage Recipient does not match
+        */
+       public function testDeleteFromSelfUserNotRecipient() {
+               $qb = $this->dbConn->getQueryBuilder();
+               $stmt = $qb->insert('share')
+                       ->values([
+                               'share_type'    => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_USER),
+                               'share_with'    => $qb->expr()->literal('user2'),
+                               'uid_owner'     => $qb->expr()->literal('user1'),
+                               'uid_initiator' => $qb->expr()->literal('user1'),
+                               'item_type'     => $qb->expr()->literal('file'),
+                               'file_source'   => $qb->expr()->literal(1),
+                               'file_target'   => $qb->expr()->literal('myTarget1'),
+                               'permissions'   => $qb->expr()->literal(2)
+                       ])->execute();
+               $this->assertEquals(1, $stmt);
+               $id = $qb->getLastInsertId();
+
+               $user1 = $this->getMock('\OCP\IUser');
+               $user1->method('getUID')->willReturn('user1');
+               $user2 = $this->getMock('\OCP\IUser');
+               $user2->method('getUID')->willReturn('user2');
+               $user3 = $this->getMock('\OCP\IUser');
+               $this->userManager->method('get')->will($this->returnValueMap([
+                       ['user1', $user1],
+                       ['user2', $user2],
+               ]));
+
+               $file = $this->getMock('\OCP\Files\File');
+               $file->method('getId')->willReturn(1);
+
+               $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+               $this->rootFolder->method('getById')->with(1)->willReturn([$file]);
+
+               $share = $this->provider->getShareById($id);
+
+               $this->provider->deleteFromSelf($share, $user3);
+       }
+
+       /**
+        * @expectedException \OC\Share20\Exception\ProviderException
+        * @expectedExceptionMessage Invalid shareType
+        */
+       public function testDeleteFromSelfLink() {
+               $qb = $this->dbConn->getQueryBuilder();
+               $stmt = $qb->insert('share')
+                       ->values([
+                               'share_type'    => $qb->expr()->literal(\OCP\Share::SHARE_TYPE_LINK),
+                               'uid_owner'     => $qb->expr()->literal('user1'),
+                               'uid_initiator' => $qb->expr()->literal('user1'),
+                               'item_type'     => $qb->expr()->literal('file'),
+                               'file_source'   => $qb->expr()->literal(1),
+                               'file_target'   => $qb->expr()->literal('myTarget1'),
+                               'permissions'   => $qb->expr()->literal(2),
+                               'token'         => $qb->expr()->literal('token'),
+                       ])->execute();
+               $this->assertEquals(1, $stmt);
+               $id = $qb->getLastInsertId();
+
+               $user1 = $this->getMock('\OCP\IUser');
+               $user1->method('getUID')->willReturn('user1');
+               $this->userManager->method('get')->will($this->returnValueMap([
+                       ['user1', $user1],
+               ]));
+
+               $file = $this->getMock('\OCP\Files\File');
+               $file->method('getId')->willReturn(1);
+
+               $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+               $this->rootFolder->method('getById')->with(1)->willReturn([$file]);
+
+               $share = $this->provider->getShareById($id);
+
+               $this->provider->deleteFromSelf($share, $user1);
+       }
 }