Merge pull request #23773 from owncloud/share_move_delete_user_hook

Migrate post_userDelete hook to share manager
This commit is contained in:
Joas Schilling 2016-04-07 13:01:10 +02:00
commit 0de15a86f0
10 changed files with 317 additions and 20 deletions

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -777,7 +777,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');

View File

@ -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();
}
}

View File

@ -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']);
}
}

View File

@ -1018,6 +1018,18 @@ class Manager implements IManager {
return true;
}
/**
* @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.

View File

@ -32,24 +32,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

View File

@ -149,6 +149,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.

View File

@ -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);
}

View File

@ -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);
}
}