diff options
Diffstat (limited to 'apps/files_sharing/lib')
-rw-r--r-- | apps/files_sharing/lib/migration.php | 243 |
1 files changed, 233 insertions, 10 deletions
diff --git a/apps/files_sharing/lib/migration.php b/apps/files_sharing/lib/migration.php index 0c5f46a5b3f..90e0dead480 100644 --- a/apps/files_sharing/lib/migration.php +++ b/apps/files_sharing/lib/migration.php @@ -1,7 +1,6 @@ <?php /** * @author Björn Schießle <schiessle@owncloud.com> - * @author Morris Jobke <hey@morrisjobke.de> * * @copyright Copyright (c) 2016, ownCloud, Inc. * @license AGPL-3.0 @@ -20,22 +19,246 @@ * */ - namespace OCA\Files_Sharing; +namespace OCA\Files_Sharing; +use Doctrine\DBAL\Connection; +use OCP\IDBConnection; +use OC\Cache\CappedMemoryCache; + +/** + * Class Migration + * + * @package OCA\Files_Sharing + * @group DB + */ class Migration { + /** @var IDBConnection */ + private $connection; + + /** @var array with all shares we already saw */ + private $shareCache; + + /** @var string */ + private $table = 'share'; + + public function __construct(IDBConnection $connection) { + $this->connection = $connection; + + // We cache up to 10k share items (~20MB) + $this->shareCache = new CappedMemoryCache(10000); + } + + /** + * move all re-shares to the owner in order to have a flat list of shares + * upgrade from oC 8.2 to 9.0 with the new sharing + */ + public function removeReShares() { + + while(true) { + $reShares = $this->getReShares(1000); + + if (empty($reShares)) { + break; + } + + // Update the cache + foreach($reShares as $reShare) { + $this->shareCache[$reShare['id']] = $reShare; + } + + $owners = []; + foreach ($reShares as $share) { + $owners[$share['id']] = [ + 'owner' => $this->findOwner($share), + 'initiator' => $share['uid_owner'] + ]; + } + $this->updateOwners($owners); + + //Clear the cache of the shares we just updated so we have more room + foreach($owners as $id => $owner) { + unset($this->shareCache[$id]); + } + } + } /** - * set accepted to 1 for all external shares. At this point in time we only - * have shares from the first version of server-to-server sharing so all should - * be accepted + * update all owner information so that all shares have an owner + * and an initiator for the upgrade from oC 8.2 to 9.0 with the new sharing */ - public function addAcceptRow() { - $statement = 'UPDATE `*PREFIX*share_external` SET `accepted` = 1'; - $connection = \OC::$server->getDatabaseConnection(); - $query = $connection->prepare($statement); - $query->execute(); + public function updateInitiatorInfo() { + while (true) { + $shares = $this->getMissingInitiator(1000); + + if (empty($shares)) { + break; + } + + $owners = []; + foreach ($shares as $share) { + $owners[$share['id']] = [ + 'owner' => $share['uid_owner'], + 'initiator' => $share['uid_owner'] + ]; + } + $this->updateOwners($owners); + } } + /** + * find the owner of a re-shared file/folder + * + * @param array $share + * @return array + */ + private function findOwner($share) { + $currentShare = $share; + while(!is_null($currentShare['parent'])) { + if (isset($this->shareCache[$currentShare['parent']])) { + $currentShare = $this->shareCache[$currentShare['parent']]; + } else { + $currentShare = $this->getShare((int)$currentShare['parent']); + $this->shareCache[$currentShare['id']] = $currentShare; + } + } + + return $currentShare['uid_owner']; + } + + /** + * Get $n re-shares from the database + * + * @param int $n The max number of shares to fetch + * @return array + */ + private function getReShares($n = 1000) { + $query = $this->connection->getQueryBuilder(); + $query->select(['id', 'parent', 'uid_owner']) + ->from($this->table) + ->where($query->expr()->in( + 'share_type', + $query->createNamedParameter( + [ + \OCP\Share::SHARE_TYPE_USER, + \OCP\Share::SHARE_TYPE_GROUP, + \OCP\Share::SHARE_TYPE_LINK + ], + Connection::PARAM_INT_ARRAY + ) + )) + ->andWhere($query->expr()->in( + 'item_type', + $query->createNamedParameter( + ['file', 'folder'], + Connection::PARAM_STR_ARRAY + ) + )) + ->andWhere($query->expr()->isNotNull('parent')) + ->orderBy('id', 'asc') + ->setMaxResults($n); + $result = $query->execute(); + $shares = $result->fetchAll(); + $result->closeCursor(); + + $ordered = []; + foreach ($shares as $share) { + $ordered[(int)$share['id']] = $share; + } + + return $ordered; + } + + /** + * Get $n re-shares from the database + * + * @param int $n The max number of shares to fetch + * @return array + */ + private function getMissingInitiator($n = 1000) { + $query = $this->connection->getQueryBuilder(); + $query->select(['id', 'uid_owner']) + ->from($this->table) + ->where($query->expr()->in( + 'share_type', + $query->createNamedParameter( + [ + \OCP\Share::SHARE_TYPE_USER, + \OCP\Share::SHARE_TYPE_GROUP, + \OCP\Share::SHARE_TYPE_LINK + ], + Connection::PARAM_INT_ARRAY + ) + )) + ->andWhere($query->expr()->in( + 'item_type', + $query->createNamedParameter( + ['file', 'folder'], + Connection::PARAM_STR_ARRAY + ) + )) + ->andWhere($query->expr()->isNull('uid_initiator')) + ->orderBy('id', 'asc') + ->setMaxResults($n); + $result = $query->execute(); + $shares = $result->fetchAll(); + $result->closeCursor(); + + $ordered = []; + foreach ($shares as $share) { + $ordered[(int)$share['id']] = $share; + } + + return $ordered; + } + + /** + * get a specific share + * + * @param int $id + * @return array + */ + private function getShare($id) { + $query = $this->connection->getQueryBuilder(); + $query->select(['id', 'parent', 'uid_owner']) + ->from($this->table) + ->where($query->expr()->eq('id', $query->createNamedParameter($id))); + $result = $query->execute(); + $share = $result->fetchAll(); + $result->closeCursor(); + + return $share[0]; + } + + /** + * update database with the new owners + * + * @param array $owners + * @throws \Exception + */ + private function updateOwners($owners) { + + $this->connection->beginTransaction(); + + try { + + foreach ($owners as $id => $owner) { + $query = $this->connection->getQueryBuilder(); + $query->update($this->table) + ->set('parent', $query->createNamedParameter(null)) + ->set('uid_owner', $query->createNamedParameter($owner['owner'])) + ->set('uid_initiator', $query->createNamedParameter($owner['initiator'])) + ->where($query->expr()->eq('id', $query->createNamedParameter($id))) + ->execute(); + } + + $this->connection->commit(); + + } catch (\Exception $e) { + $this->connection->rollBack(); + throw $e; + } + + } } |