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
This commit is contained in:
parent
f6cea3c9c4
commit
e0cee43cf0
10 changed files with 317 additions and 20 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
27
lib/private/Share20/Hooks.php
Normal file
27
lib/private/Share20/Hooks.php
Normal 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']);
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue