summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoeland Jago Douma <rullzer@owncloud.com>2016-04-04 12:28:19 +0200
committerRoeland Jago Douma <rullzer@owncloud.com>2016-04-04 14:15:38 +0200
commite0cee43cf0a3899567f50a5fb03d867fc2f0327a (patch)
tree5f0d5503b3d971e0b813bc14fd7956cf114abbfe
parentf6cea3c9c436142110504ba76320d57ca7899b27 (diff)
downloadnextcloud-server-e0cee43cf0a3899567f50a5fb03d867fc2f0327a.tar.gz
nextcloud-server-e0cee43cf0a3899567f50a5fb03d867fc2f0327a.zip
Migrate post_userDelete hook to share manager
This makes the post_userDelete hook call the sharemanager. This will cleanup to and from this user. * All shares owned by this user * All shares with this user (user) * All custom group shares * All link share initiated by this user (to avoid invisible link shares) Unit tests are added for the defaultshare provider as well as the federated share provider
-rw-r--r--apps/federatedfilesharing/lib/federatedshareprovider.php17
-rw-r--r--apps/federatedfilesharing/tests/federatedshareprovidertest.php48
-rw-r--r--lib/base.php2
-rw-r--r--lib/private/Share20/DefaultShareProvider.php65
-rw-r--r--lib/private/Share20/Hooks.php27
-rw-r--r--lib/private/Share20/Manager.php12
-rw-r--r--lib/private/share/hooks.php18
-rw-r--r--lib/public/Share/IManager.php11
-rw-r--r--lib/public/Share/IShareProvider.php10
-rw-r--r--tests/lib/share20/defaultshareprovidertest.php127
10 files changed, 317 insertions, 20 deletions
diff --git a/apps/federatedfilesharing/lib/federatedshareprovider.php b/apps/federatedfilesharing/lib/federatedshareprovider.php
index e54ce08fb04..a450b420cf4 100644
--- a/apps/federatedfilesharing/lib/federatedshareprovider.php
+++ b/apps/federatedfilesharing/lib/federatedshareprovider.php
@@ -563,4 +563,21 @@ class FederatedShareProvider implements IShareProvider {
return $nodes[0];
}
+ /**
+ * A user is deleted from the system
+ * So clean up the relevant shares.
+ *
+ * @param string $uid
+ * @param int $shareType
+ */
+ public function userDeleted($uid, $shareType) {
+ //TODO: probabaly a good idea to send unshare info to remote servers
+
+ $qb = $this->dbConnection->getQueryBuilder();
+
+ $qb->delete('share')
+ ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
+ ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
+ ->execute();
+ }
}
diff --git a/apps/federatedfilesharing/tests/federatedshareprovidertest.php b/apps/federatedfilesharing/tests/federatedshareprovidertest.php
index dedd6767b49..92e9f10c3cd 100644
--- a/apps/federatedfilesharing/tests/federatedshareprovidertest.php
+++ b/apps/federatedfilesharing/tests/federatedshareprovidertest.php
@@ -462,4 +462,52 @@ class FederatedShareProviderTest extends TestCase {
$this->assertCount(1, $shares);
$this->assertEquals('user2@server.com', $shares[0]->getSharedWith());
}
+
+ public function dataDeleteUser() {
+ return [
+ ['a', 'b', 'c', 'a', true],
+ ['a', 'b', 'c', 'b', false],
+ // The recipient is non local.
+ ['a', 'b', 'c', 'c', false],
+ ['a', 'b', 'c', 'd', false],
+ ];
+ }
+
+ /**
+ * @dataProvider dataDeleteUser
+ *
+ * @param string $owner The owner of the share (uid)
+ * @param string $initiator The initiator of the share (uid)
+ * @param string $recipient The recipient of the share (uid/gid/pass)
+ * @param string $deletedUser The user that is deleted
+ * @param bool $rowDeleted Is the row deleted in this setup
+ */
+ public function testDeleteUser($owner, $initiator, $recipient, $deletedUser, $rowDeleted) {
+ $qb = $this->connection->getQueryBuilder();
+ $qb->insert('share')
+ ->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE))
+ ->setValue('uid_owner', $qb->createNamedParameter($owner))
+ ->setValue('uid_initiator', $qb->createNamedParameter($initiator))
+ ->setValue('share_with', $qb->createNamedParameter($recipient))
+ ->setValue('item_type', $qb->createNamedParameter('file'))
+ ->setValue('item_source', $qb->createNamedParameter(42))
+ ->setValue('file_source', $qb->createNamedParameter(42))
+ ->execute();
+
+ $id = $qb->getLastInsertId();
+
+ $this->provider->userDeleted($deletedUser, \OCP\Share::SHARE_TYPE_REMOTE);
+
+ $qb = $this->connection->getQueryBuilder();
+ $qb->select('*')
+ ->from('share')
+ ->where(
+ $qb->expr()->eq('id', $qb->createNamedParameter($id))
+ );
+ $cursor = $qb->execute();
+ $data = $cursor->fetchAll();
+ $cursor->closeCursor();
+
+ $this->assertCount($rowDeleted ? 0 : 1, $data);
+ }
}
diff --git a/lib/base.php b/lib/base.php
index f3076a1181a..d457d1ed485 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -776,7 +776,7 @@ class OC {
*/
public static function registerShareHooks() {
if (\OC::$server->getSystemConfig()->getValue('installed')) {
- OC_Hook::connect('OC_User', 'post_deleteUser', 'OC\Share\Hooks', 'post_deleteUser');
+ OC_Hook::connect('OC_User', 'post_deleteUser', 'OC\Share20\Hooks', 'post_deleteUser');
OC_Hook::connect('OC_User', 'post_addToGroup', 'OC\Share\Hooks', 'post_addToGroup');
OC_Hook::connect('OC_Group', 'pre_addToGroup', 'OC\Share\Hooks', 'pre_addToGroup');
OC_Hook::connect('OC_User', 'post_removeFromGroup', 'OC\Share\Hooks', 'post_removeFromGroup');
diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php
index f6171f87992..370655f8315 100644
--- a/lib/private/Share20/DefaultShareProvider.php
+++ b/lib/private/Share20/DefaultShareProvider.php
@@ -28,7 +28,6 @@ use OC\Share20\Exception\ProviderException;
use OCP\Share\Exceptions\ShareNotFound;
use OC\Share20\Exception\BackendError;
use OCP\DB\QueryBuilder\IQueryBuilder;
-use OCP\Files\NotFoundException;
use OCP\IGroup;
use OCP\IGroupManager;
use OCP\IUserManager;
@@ -804,4 +803,68 @@ class DefaultShareProvider implements IShareProvider {
return $share;
}
+ /**
+ * A user is deleted from the system
+ * So clean up the relevant shares.
+ *
+ * @param string $uid
+ * @param int $shareType
+ */
+ public function userDeleted($uid, $shareType) {
+ $qb = $this->dbConn->getQueryBuilder();
+
+ $qb->delete('share');
+
+ if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
+ /*
+ * Delete all user shares that are owned by this user
+ * or that are received by this user
+ */
+
+ $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)));
+
+ $qb->andWhere(
+ $qb->expr()->orX(
+ $qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)),
+ $qb->expr()->eq('share_with', $qb->createNamedParameter($uid))
+ )
+ );
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
+ /*
+ * Delete all group shares that are owned by this user
+ * Or special user group shares that are received by this user
+ */
+ $qb->where(
+ $qb->expr()->andX(
+ $qb->expr()->orX(
+ $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)),
+ $qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP))
+ ),
+ $qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))
+ )
+ );
+
+ $qb->orWhere(
+ $qb->expr()->andX(
+ $qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)),
+ $qb->expr()->eq('share_with', $qb->createNamedParameter($uid))
+ )
+ );
+ } else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
+ /*
+ * Delete all link shares owned by this user.
+ * And all link shares initiated by this user (until #22327 is in)
+ */
+ $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK)));
+
+ $qb->andWhere(
+ $qb->expr()->orX(
+ $qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)),
+ $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($uid))
+ )
+ );
+ }
+
+ $qb->execute();
+ }
}
diff --git a/lib/private/Share20/Hooks.php b/lib/private/Share20/Hooks.php
new file mode 100644
index 00000000000..93669974b28
--- /dev/null
+++ b/lib/private/Share20/Hooks.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Share20;
+
+class Hooks {
+ public static function post_deleteUser($arguments) {
+ \OC::$server->getShareManager()->userDeleted($arguments['uid']);
+ }
+}
diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index 1c9d4d82277..6c665f7e133 100644
--- a/lib/private/Share20/Manager.php
+++ b/lib/private/Share20/Manager.php
@@ -1019,6 +1019,18 @@ class Manager implements IManager {
}
/**
+ * @inheritdoc
+ */
+ public function userDeleted($uid) {
+ $types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE];
+
+ foreach ($types as $type) {
+ $provider = $this->factory->getProviderForType($type);
+ $provider->userDeleted($uid, $type);
+ }
+ }
+
+ /**
* Get access list to a path. This means
* all the users and groups that can access a given path.
*
diff --git a/lib/private/share/hooks.php b/lib/private/share/hooks.php
index 750486ba80f..dae273eefb8 100644
--- a/lib/private/share/hooks.php
+++ b/lib/private/share/hooks.php
@@ -33,24 +33,6 @@ class Hooks extends \OC\Share\Constants {
private static $updateTargets = array();
/**
- * Function that is called after a user is deleted. Cleans up the shares of that user.
- * @param array $arguments
- */
- public static function post_deleteUser($arguments) {
- // Delete any items shared with the deleted user
- $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share`'
- .' WHERE `share_with` = ? AND (`share_type` = ? OR `share_type` = ?)');
- $query->execute(array($arguments['uid'], self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique));
- // Delete any items the deleted user shared
- $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `uid_owner` = ?');
- $result = $query->execute(array($arguments['uid']));
- while ($item = $result->fetchRow()) {
- Helper::delete($item['id']);
- }
- }
-
-
- /**
* Function that is called before a user is added to a group.
* check if we need to create a unique target for the user
* @param array $arguments
diff --git a/lib/public/Share/IManager.php b/lib/public/Share/IManager.php
index 64e5b554de9..e3780ac070c 100644
--- a/lib/public/Share/IManager.php
+++ b/lib/public/Share/IManager.php
@@ -150,6 +150,17 @@ interface IManager {
public function checkPassword(IShare $share, $password);
/**
+ * The user with UID is deleted.
+ * All share providers have to cleanup the shares with this user as well
+ * as shares owned by this user.
+ * Shares only initiated by this user are fine.
+ *
+ * @param string $uid
+ * @since 9.1.0
+ */
+ public function userDeleted($uid);
+
+ /**
* Instantiates a new share object. This is to be passed to
* createShare.
*
diff --git a/lib/public/Share/IShareProvider.php b/lib/public/Share/IShareProvider.php
index d00b9da7b59..e201ba81ebc 100644
--- a/lib/public/Share/IShareProvider.php
+++ b/lib/public/Share/IShareProvider.php
@@ -146,4 +146,14 @@ interface IShareProvider {
* @since 9.0.0
*/
public function getShareByToken($token);
+
+ /**
+ * A user is deleted from the system
+ * So clean up the relevant shares.
+ *
+ * @param string $uid
+ * @param int $shareType
+ * @since 9.1.0
+ */
+ public function userDeleted($uid, $shareType);
}
diff --git a/tests/lib/share20/defaultshareprovidertest.php b/tests/lib/share20/defaultshareprovidertest.php
index 8d8ae8d4809..d8b594519b6 100644
--- a/tests/lib/share20/defaultshareprovidertest.php
+++ b/tests/lib/share20/defaultshareprovidertest.php
@@ -1872,4 +1872,131 @@ class DefaultShareProviderTest extends \Test\TestCase {
$share = $this->provider->getShareById($id, 'user0');
$this->assertSame('/ultraNewTarget', $share->getTarget());
}
+
+ public function dataDeleteUser() {
+ return [
+ [\OCP\Share::SHARE_TYPE_USER, 'a', 'b', 'c', 'a', true],
+ [\OCP\Share::SHARE_TYPE_USER, 'a', 'b', 'c', 'b', false],
+ [\OCP\Share::SHARE_TYPE_USER, 'a', 'b', 'c', 'c', true],
+ [\OCP\Share::SHARE_TYPE_USER, 'a', 'b', 'c', 'd', false],
+ [\OCP\Share::SHARE_TYPE_GROUP, 'a', 'b', 'c', 'a', true],
+ [\OCP\Share::SHARE_TYPE_GROUP, 'a', 'b', 'c', 'b', false],
+ // The group c is still valid but user c is deleted so group share stays
+ [\OCP\Share::SHARE_TYPE_GROUP, 'a', 'b', 'c', 'c', false],
+ [\OCP\Share::SHARE_TYPE_GROUP, 'a', 'b', 'c', 'd', false],
+ [\OCP\Share::SHARE_TYPE_LINK, 'a', 'b', 'c', 'a', true],
+ // To avoid invisible link shares delete initiated link shares as well (see #22327)
+ [\OCP\Share::SHARE_TYPE_LINK, 'a', 'b', 'c', 'b', true],
+ [\OCP\Share::SHARE_TYPE_LINK, 'a', 'b', 'c', 'c', false],
+ [\OCP\Share::SHARE_TYPE_LINK, 'a', 'b', 'c', 'd', false],
+ ];
+ }
+
+ /**
+ * @dataProvider dataDeleteUser
+ *
+ * @param int $type The shareType (user/group/link)
+ * @param string $owner The owner of the share (uid)
+ * @param string $initiator The initiator of the share (uid)
+ * @param string $recipient The recipient of the share (uid/gid/pass)
+ * @param string $deletedUser The user that is deleted
+ * @param bool $rowDeleted Is the row deleted in this setup
+ */
+ public function testDeleteUser($type, $owner, $initiator, $recipient, $deletedUser, $rowDeleted) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->setValue('share_type', $qb->createNamedParameter($type))
+ ->setValue('uid_owner', $qb->createNamedParameter($owner))
+ ->setValue('uid_initiator', $qb->createNamedParameter($initiator))
+ ->setValue('share_with', $qb->createNamedParameter($recipient))
+ ->setValue('item_type', $qb->createNamedParameter('file'))
+ ->setValue('item_source', $qb->createNamedParameter(42))
+ ->setValue('file_source', $qb->createNamedParameter(42))
+ ->execute();
+
+ $id = $qb->getLastInsertId();
+
+ $this->provider->userDeleted($deletedUser, $type);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share')
+ ->where(
+ $qb->expr()->eq('id', $qb->createNamedParameter($id))
+ );
+ $cursor = $qb->execute();
+ $data = $cursor->fetchAll();
+ $cursor->closeCursor();
+
+ $this->assertCount($rowDeleted ? 0 : 1, $data);
+ }
+
+ public function dataDeleteUserGroup() {
+ return [
+ ['a', 'b', 'c', 'a', true, true],
+ ['a', 'b', 'c', 'b', false, false],
+ ['a', 'b', 'c', 'c', false, true],
+ ['a', 'b', 'c', 'd', false, false],
+ ];
+ }
+
+ /**
+ * @dataProvider dataDeleteUserGroup
+ *
+ * @param string $owner The owner of the share (uid)
+ * @param string $initiator The initiator of the share (uid)
+ * @param string $recipient The recipient of the usergroup share (uid)
+ * @param string $deletedUser The user that is deleted
+ * @param bool $groupShareDeleted
+ * @param bool $userGroupShareDeleted
+ */
+ public function testDeleteUserGroup($owner, $initiator, $recipient, $deletedUser, $groupShareDeleted, $userGroupShareDeleted) {
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP))
+ ->setValue('uid_owner', $qb->createNamedParameter($owner))
+ ->setValue('uid_initiator', $qb->createNamedParameter($initiator))
+ ->setValue('share_with', $qb->createNamedParameter('group'))
+ ->setValue('item_type', $qb->createNamedParameter('file'))
+ ->setValue('item_source', $qb->createNamedParameter(42))
+ ->setValue('file_source', $qb->createNamedParameter(42))
+ ->execute();
+ $groupId = $qb->getLastInsertId();
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->insert('share')
+ ->setValue('share_type', $qb->createNamedParameter(2))
+ ->setValue('uid_owner', $qb->createNamedParameter($owner))
+ ->setValue('uid_initiator', $qb->createNamedParameter($initiator))
+ ->setValue('share_with', $qb->createNamedParameter($recipient))
+ ->setValue('item_type', $qb->createNamedParameter('file'))
+ ->setValue('item_source', $qb->createNamedParameter(42))
+ ->setValue('file_source', $qb->createNamedParameter(42))
+ ->execute();
+ $userGroupId = $qb->getLastInsertId();
+
+ $this->provider->userDeleted($deletedUser, \OCP\Share::SHARE_TYPE_GROUP);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share')
+ ->where(
+ $qb->expr()->eq('id', $qb->createNamedParameter($userGroupId))
+ );
+ $cursor = $qb->execute();
+ $data = $cursor->fetchAll();
+ $cursor->closeCursor();
+ $this->assertCount($userGroupShareDeleted ? 0 : 1, $data);
+
+ $qb = $this->dbConn->getQueryBuilder();
+ $qb->select('*')
+ ->from('share')
+ ->where(
+ $qb->expr()->eq('id', $qb->createNamedParameter($groupId))
+ );
+ $cursor = $qb->execute();
+ $data = $cursor->fetchAll();
+ $cursor->closeCursor();
+ $this->assertCount($groupShareDeleted ? 0 : 1, $data);
+ }
}