[Pkg-owncloud-commits] [owncloud] 114/129: Add a repair step that checks for group membership on shares

David Prévot taffit at moszumanska.debian.org
Thu Nov 5 01:04:29 UTC 2015


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch stable8
in repository owncloud.

commit 3f3bcbeb4728f8f2fd7ea380576862a27a7e05ba
Author: Joas Schilling <nickvergessen at owncloud.com>
Date:   Mon Oct 19 16:41:43 2015 +0200

    Add a repair step that checks for group membership on shares
---
 core/command/maintenance/repair.php               |  17 ++-
 lib/private/repair.php                            |  13 ++
 lib/repair/oldgroupmembershipshares.php           | 117 ++++++++++++++++++
 tests/lib/repair/oldgroupmembershipsharestest.php | 138 ++++++++++++++++++++++
 4 files changed, 284 insertions(+), 1 deletion(-)

diff --git a/core/command/maintenance/repair.php b/core/command/maintenance/repair.php
index 5df362f..f7c0cc4 100644
--- a/core/command/maintenance/repair.php
+++ b/core/command/maintenance/repair.php
@@ -26,6 +26,7 @@ namespace OC\Core\Command\Maintenance;
 
 use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
 use Symfony\Component\Console\Output\OutputInterface;
 
 class Repair extends Command {
@@ -49,10 +50,24 @@ class Repair extends Command {
 	protected function configure() {
 		$this
 			->setName('maintenance:repair')
-			->setDescription('repair this installation');
+			->setDescription('repair this installation')
+			->addOption(
+				'include-expensive',
+				null,
+				InputOption::VALUE_NONE,
+				'Use this option when you want to include resource and load expensive tasks'
+			)
+		;
 	}
 
 	protected function execute(InputInterface $input, OutputInterface $output) {
+		$includeExpensive = $input->getOption('include-expensive');
+		if ($includeExpensive) {
+			foreach ($this->repair->getExpensiveRepairSteps() as $step) {
+				$this->repair->addStep($step);
+			}
+		}
+
 		$maintenanceMode = $this->config->getSystemValue('maintenance', false);
 		$this->config->setSystemValue('maintenance', true);
 
diff --git a/lib/private/repair.php b/lib/private/repair.php
index 20219e3..f6ac7eb 100644
--- a/lib/private/repair.php
+++ b/lib/private/repair.php
@@ -34,6 +34,7 @@ use OC\Repair\AssetCache;
 use OC\Repair\CleanTags;
 use OC\Repair\Collation;
 use OC\Repair\DropOldJobs;
+use OC\Repair\OldGroupMembershipShares;
 use OC\Repair\RemoveGetETagEntries;
 use OC\Repair\SqliteAutoincrement;
 use OC\Repair\DropOldTables;
@@ -119,6 +120,18 @@ class Repair extends BasicEmitter {
 	}
 
 	/**
+	 * Returns expensive repair steps to be run on the
+	 * command line with a special option.
+	 *
+	 * @return array of RepairStep instances
+	 */
+	public static function getExpensiveRepairSteps() {
+		return [
+			new OldGroupMembershipShares(\OC::$server->getDatabaseConnection(), \OC::$server->getGroupManager()),
+		];
+	}
+
+	/**
 	 * Returns the repair steps to be run before an
 	 * upgrade.
 	 *
diff --git a/lib/repair/oldgroupmembershipshares.php b/lib/repair/oldgroupmembershipshares.php
new file mode 100644
index 0000000..2d701ac
--- /dev/null
+++ b/lib/repair/oldgroupmembershipshares.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen at owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, 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\Repair;
+
+
+use OC\Hooks\BasicEmitter;
+use OC\RepairStep;
+use OCP\IDBConnection;
+use OCP\IGroupManager;
+use OCP\Share;
+
+class OldGroupMembershipShares extends BasicEmitter implements RepairStep {
+
+	/** @var \OCP\IDBConnection */
+	protected $connection;
+
+	/** @var \OCP\IGroupManager */
+	protected $groupManager;
+
+	/**
+	 * @var array [gid => [uid => (bool)]]
+	 */
+	protected $memberships;
+
+	/**
+	 * @param IDBConnection $connection
+	 * @param IGroupManager $groupManager
+	 */
+	public function __construct(IDBConnection $connection, IGroupManager $groupManager) {
+		$this->connection = $connection;
+		$this->groupManager = $groupManager;
+	}
+
+	/**
+	 * Returns the step's name
+	 *
+	 * @return string
+	 */
+	public function getName() {
+		return 'Remove shares of old group memberships';
+	}
+
+	/**
+	 * Run repair step.
+	 * Must throw exception on error.
+	 *
+	 * @throws \Exception in case of failure
+	 */
+	public function run() {
+		$deletedEntries = 0;
+
+		$query = $this->connection->getQueryBuilder();
+		$query->select(['s1.id', $query->createFunction('s1.`share_with` AS `user`'), $query->createFunction('s2.`share_with` AS `group`')])
+			->from('share', 's1')
+			->where($query->expr()->isNotNull('s1.parent'))
+				// \OC\Share\Constant::$shareTypeGroupUserUnique === 2
+				->andWhere($query->expr()->eq('s1.share_type', $query->expr()->literal(2)))
+				->andWhere($query->expr()->isNotNull('s2.id'))
+				->andWhere($query->expr()->eq('s2.share_type', $query->expr()->literal(Share::SHARE_TYPE_GROUP)))
+			->leftJoin('s1', 'share', 's2', $query->expr()->eq('s1.parent', 's2.id'));
+
+		$deleteQuery = $this->connection->getQueryBuilder();
+		$deleteQuery->delete('share')
+			->where($query->expr()->eq('id', $deleteQuery->createParameter('share')));
+
+		$result = $query->execute();
+		while ($row = $result->fetch()) {
+			if (!$this->isMember($row['group'], $row['user'])) {
+				$deletedEntries += $deleteQuery->setParameter('share', (int) $row['id'])
+					->execute();
+			}
+		}
+		$result->closeCursor();
+
+		if ($deletedEntries) {
+			$this->emit('\OC\Repair', 'info', array('Removed ' . $deletedEntries . ' shares where user is not a member of the group anymore'));
+		}
+	}
+
+	/**
+	 * @param string $gid
+	 * @param string $uid
+	 * @return bool
+	 */
+	protected function isMember($gid, $uid) {
+		if (isset($this->memberships[$gid][$uid])) {
+			return $this->memberships[$gid][$uid];
+		}
+
+		$isMember = $this->groupManager->isInGroup($uid, $gid);
+		if (!isset($this->memberships[$gid])) {
+			$this->memberships[$gid] = [];
+		}
+		$this->memberships[$gid][$uid] = $isMember;
+
+		return $isMember;
+	}
+}
diff --git a/tests/lib/repair/oldgroupmembershipsharestest.php b/tests/lib/repair/oldgroupmembershipsharestest.php
new file mode 100644
index 0000000..74f68bd
--- /dev/null
+++ b/tests/lib/repair/oldgroupmembershipsharestest.php
@@ -0,0 +1,138 @@
+<?php
+/**
+ * Copyright (c) 2015 Vincent Petry <pvince81 at owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Repair;
+
+use OC\Repair\OldGroupMembershipShares;
+use OC\Share\Constants;
+
+class OldGroupMembershipSharesTest extends \Test\TestCase {
+
+	/** @var OldGroupMembershipShares */
+	protected $repair;
+
+	/** @var \OCP\IDBConnection */
+	protected $connection;
+
+	/** @var \OCP\IGroupManager|\PHPUnit_Framework_MockObject_MockObject */
+	protected $groupManager;
+
+	protected function setUp() {
+		parent::setUp();
+
+		/** \OCP\IGroupManager|\PHPUnit_Framework_MockObject_MockObject */
+		$this->groupManager = $this->getMockBuilder('OCP\IGroupManager')
+			->disableOriginalConstructor()
+			->getMock();
+		$this->connection = \OC::$server->getDatabaseConnection();
+
+		$this->deleteAllShares();
+	}
+
+	protected function tearDown() {
+		$this->deleteAllShares();
+
+		parent::tearDown();
+	}
+
+	protected function deleteAllShares() {
+		$qb = $this->connection->getQueryBuilder();
+		$qb->delete('share')->execute();
+	}
+
+	public function testRun() {
+		$repair = new OldGroupMembershipShares(
+			$this->connection,
+			$this->groupManager
+		);
+
+		$this->groupManager->expects($this->exactly(2))
+			->method('isInGroup')
+			->willReturnMap([
+				['member', 'group', true],
+				['not-a-member', 'group', false],
+			]);
+
+		$parent = $this->createShare(Constants::SHARE_TYPE_GROUP, 'group', null);
+		$group2 = $this->createShare(Constants::SHARE_TYPE_GROUP, 'group2', $parent);
+		$user1 = $this->createShare(Constants::SHARE_TYPE_USER, 'user1', $parent);
+
+		// \OC\Share\Constant::$shareTypeGroupUserUnique === 2
+		$member = $this->createShare(2, 'member', $parent);
+		$notAMember = $this->createShare(2, 'not-a-member', $parent);
+
+		$query = $this->connection->getQueryBuilder();
+		$result = $query->select('id')
+			->from('share')
+			->orderBy('id', 'ASC')
+			->execute();
+		$rows = $result->fetchAll();
+		$this->assertSame([['id' => $parent], ['id' => $group2], ['id' => $user1], ['id' => $member], ['id' => $notAMember]], $rows);
+		$result->closeCursor();
+
+		$repair->run();
+
+		$query = $this->connection->getQueryBuilder();
+		$result = $query->select('id')
+			->from('share')
+			->orderBy('id', 'ASC')
+			->execute();
+		$rows = $result->fetchAll();
+		$this->assertSame([['id' => $parent], ['id' => $group2], ['id' => $user1], ['id' => $member]], $rows);
+		$result->closeCursor();
+	}
+
+	/**
+	 * @param string $shareType
+	 * @param string $shareWith
+	 * @param null|int $parent
+	 * @return int
+	 */
+	protected function createShare($shareType, $shareWith, $parent) {
+		$qb = $this->connection->getQueryBuilder();
+		$shareValues = [
+			'share_type' => $qb->expr()->literal($shareType),
+			'share_with' => $qb->expr()->literal($shareWith),
+			'uid_owner' => $qb->expr()->literal('user1'),
+			'item_type' => $qb->expr()->literal('folder'),
+			'item_source' => $qb->expr()->literal(123),
+			'item_target' => $qb->expr()->literal('/123'),
+			'file_source' => $qb->expr()->literal(123),
+			'file_target' => $qb->expr()->literal('/test'),
+			'permissions' => $qb->expr()->literal(1),
+			'stime' => $qb->expr()->literal(time()),
+			'expiration' => $qb->expr()->literal('2015-09-25 00:00:00'),
+		];
+
+		if ($parent) {
+			$shareValues['parent'] = $qb->expr()->literal($parent);
+		}
+
+		$qb = $this->connection->getQueryBuilder();
+		$qb->insert('share')
+			->values($shareValues)
+			->execute();
+
+		return $this->getLastShareId();
+	}
+
+	/**
+	 * @return int
+	 */
+	protected function getLastShareId() {
+		// select because lastInsertId does not work with OCI
+		$query = $this->connection->getQueryBuilder();
+		$result = $query->select('id')
+			->from('share')
+			->orderBy('id', 'DESC')
+			->execute();
+		$row = $result->fetch();
+		$result->closeCursor();
+		return $row['id'];
+	}
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud.git



More information about the Pkg-owncloud-commits mailing list