Merge pull request #3589 from nextcloud/remove-unneeded-repair-step

Remove unneeded repair steps
This commit is contained in:
Morris Jobke 2017-02-23 15:57:21 -06:00 committed by GitHub
commit ee52313e76
29 changed files with 19 additions and 3284 deletions

View File

@ -679,13 +679,8 @@ return array(
'OC\\RedisFactory' => $baseDir . '/lib/private/RedisFactory.php',
'OC\\Repair' => $baseDir . '/lib/private/Repair.php',
'OC\\RepairException' => $baseDir . '/lib/private/RepairException.php',
'OC\\Repair\\AssetCache' => $baseDir . '/lib/private/Repair/AssetCache.php',
'OC\\Repair\\CleanTags' => $baseDir . '/lib/private/Repair/CleanTags.php',
'OC\\Repair\\Collation' => $baseDir . '/lib/private/Repair/Collation.php',
'OC\\Repair\\DropOldJobs' => $baseDir . '/lib/private/Repair/DropOldJobs.php',
'OC\\Repair\\DropOldTables' => $baseDir . '/lib/private/Repair/DropOldTables.php',
'OC\\Repair\\FillETags' => $baseDir . '/lib/private/Repair/FillETags.php',
'OC\\Repair\\InnoDB' => $baseDir . '/lib/private/Repair/InnoDB.php',
'OC\\Repair\\MoveUpdaterStepFile' => $baseDir . '/lib/private/Repair/MoveUpdaterStepFile.php',
'OC\\Repair\\NC11\\CleanPreviews' => $baseDir . '/lib/private/Repair/NC11/CleanPreviews.php',
'OC\\Repair\\NC11\\CleanPreviewsBackgroundJob' => $baseDir . '/lib/private/Repair/NC11/CleanPreviewsBackgroundJob.php',
@ -693,18 +688,10 @@ return array(
'OC\\Repair\\NC11\\MoveAvatars' => $baseDir . '/lib/private/Repair/NC11/MoveAvatars.php',
'OC\\Repair\\NC11\\MoveAvatarsBackgroundJob' => $baseDir . '/lib/private/Repair/NC11/MoveAvatarsBackgroundJob.php',
'OC\\Repair\\OldGroupMembershipShares' => $baseDir . '/lib/private/Repair/OldGroupMembershipShares.php',
'OC\\Repair\\Preview' => $baseDir . '/lib/private/Repair/Preview.php',
'OC\\Repair\\RemoveGetETagEntries' => $baseDir . '/lib/private/Repair/RemoveGetETagEntries.php',
'OC\\Repair\\RemoveOldShares' => $baseDir . '/lib/private/Repair/RemoveOldShares.php',
'OC\\Repair\\RemoveRootShares' => $baseDir . '/lib/private/Repair/RemoveRootShares.php',
'OC\\Repair\\RepairInvalidShares' => $baseDir . '/lib/private/Repair/RepairInvalidShares.php',
'OC\\Repair\\RepairMimeTypes' => $baseDir . '/lib/private/Repair/RepairMimeTypes.php',
'OC\\Repair\\RepairUnmergedShares' => $baseDir . '/lib/private/Repair/RepairUnmergedShares.php',
'OC\\Repair\\SearchLuceneTables' => $baseDir . '/lib/private/Repair/SearchLuceneTables.php',
'OC\\Repair\\SharePropagation' => $baseDir . '/lib/private/Repair/SharePropagation.php',
'OC\\Repair\\SqliteAutoincrement' => $baseDir . '/lib/private/Repair/SqliteAutoincrement.php',
'OC\\Repair\\UpdateCertificateStore' => $baseDir . '/lib/private/Repair/UpdateCertificateStore.php',
'OC\\Repair\\UpdateOutdatedOcsIds' => $baseDir . '/lib/private/Repair/UpdateOutdatedOcsIds.php',
'OC\\RichObjectStrings\\Validator' => $baseDir . '/lib/private/RichObjectStrings/Validator.php',
'OC\\Route\\CachingRouter' => $baseDir . '/lib/private/Route/CachingRouter.php',
'OC\\Route\\Route' => $baseDir . '/lib/private/Route/Route.php',

View File

@ -709,13 +709,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\RedisFactory' => __DIR__ . '/../../..' . '/lib/private/RedisFactory.php',
'OC\\Repair' => __DIR__ . '/../../..' . '/lib/private/Repair.php',
'OC\\RepairException' => __DIR__ . '/../../..' . '/lib/private/RepairException.php',
'OC\\Repair\\AssetCache' => __DIR__ . '/../../..' . '/lib/private/Repair/AssetCache.php',
'OC\\Repair\\CleanTags' => __DIR__ . '/../../..' . '/lib/private/Repair/CleanTags.php',
'OC\\Repair\\Collation' => __DIR__ . '/../../..' . '/lib/private/Repair/Collation.php',
'OC\\Repair\\DropOldJobs' => __DIR__ . '/../../..' . '/lib/private/Repair/DropOldJobs.php',
'OC\\Repair\\DropOldTables' => __DIR__ . '/../../..' . '/lib/private/Repair/DropOldTables.php',
'OC\\Repair\\FillETags' => __DIR__ . '/../../..' . '/lib/private/Repair/FillETags.php',
'OC\\Repair\\InnoDB' => __DIR__ . '/../../..' . '/lib/private/Repair/InnoDB.php',
'OC\\Repair\\MoveUpdaterStepFile' => __DIR__ . '/../../..' . '/lib/private/Repair/MoveUpdaterStepFile.php',
'OC\\Repair\\NC11\\CleanPreviews' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/CleanPreviews.php',
'OC\\Repair\\NC11\\CleanPreviewsBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/CleanPreviewsBackgroundJob.php',
@ -723,18 +718,10 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Repair\\NC11\\MoveAvatars' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/MoveAvatars.php',
'OC\\Repair\\NC11\\MoveAvatarsBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/MoveAvatarsBackgroundJob.php',
'OC\\Repair\\OldGroupMembershipShares' => __DIR__ . '/../../..' . '/lib/private/Repair/OldGroupMembershipShares.php',
'OC\\Repair\\Preview' => __DIR__ . '/../../..' . '/lib/private/Repair/Preview.php',
'OC\\Repair\\RemoveGetETagEntries' => __DIR__ . '/../../..' . '/lib/private/Repair/RemoveGetETagEntries.php',
'OC\\Repair\\RemoveOldShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RemoveOldShares.php',
'OC\\Repair\\RemoveRootShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RemoveRootShares.php',
'OC\\Repair\\RepairInvalidShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairInvalidShares.php',
'OC\\Repair\\RepairMimeTypes' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairMimeTypes.php',
'OC\\Repair\\RepairUnmergedShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairUnmergedShares.php',
'OC\\Repair\\SearchLuceneTables' => __DIR__ . '/../../..' . '/lib/private/Repair/SearchLuceneTables.php',
'OC\\Repair\\SharePropagation' => __DIR__ . '/../../..' . '/lib/private/Repair/SharePropagation.php',
'OC\\Repair\\SqliteAutoincrement' => __DIR__ . '/../../..' . '/lib/private/Repair/SqliteAutoincrement.php',
'OC\\Repair\\UpdateCertificateStore' => __DIR__ . '/../../..' . '/lib/private/Repair/UpdateCertificateStore.php',
'OC\\Repair\\UpdateOutdatedOcsIds' => __DIR__ . '/../../..' . '/lib/private/Repair/UpdateOutdatedOcsIds.php',
'OC\\RichObjectStrings\\Validator' => __DIR__ . '/../../..' . '/lib/private/RichObjectStrings/Validator.php',
'OC\\Route\\CachingRouter' => __DIR__ . '/../../..' . '/lib/private/Route/CachingRouter.php',
'OC\\Route\\Route' => __DIR__ . '/../../..' . '/lib/private/Route/Route.php',

View File

@ -30,28 +30,17 @@
namespace OC;
use OC\Repair\AssetCache;
use OC\Repair\CleanTags;
use OC\Repair\Collation;
use OC\Repair\DropOldJobs;
use OC\Repair\MoveUpdaterStepFile;
use OC\Repair\NC11\CleanPreviews;
use OC\Repair\NC11\FixMountStorages;
use OC\Repair\NC11\MoveAvatars;
use OC\Repair\OldGroupMembershipShares;
use OC\Repair\RemoveGetETagEntries;
use OC\Repair\RemoveOldShares;
use OC\Repair\RemoveRootShares;
use OC\Repair\SharePropagation;
use OC\Repair\SqliteAutoincrement;
use OC\Repair\DropOldTables;
use OC\Repair\FillETags;
use OC\Repair\InnoDB;
use OC\Repair\RepairMimeTypes;
use OC\Repair\SearchLuceneTables;
use OC\Repair\UpdateOutdatedOcsIds;
use OC\Repair\RepairInvalidShares;
use OC\Repair\RepairUnmergedShares;
use OCP\AppFramework\QueryException;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
@ -131,23 +120,9 @@ class Repair implements IOutput{
return [
new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), \OC::$server->getDatabaseConnection(), false),
new RepairMimeTypes(\OC::$server->getConfig()),
new AssetCache(),
new FillETags(\OC::$server->getDatabaseConnection()),
new CleanTags(\OC::$server->getDatabaseConnection(), \OC::$server->getUserManager()),
new DropOldTables(\OC::$server->getDatabaseConnection()),
new DropOldJobs(\OC::$server->getJobList()),
new RemoveGetETagEntries(\OC::$server->getDatabaseConnection()),
new UpdateOutdatedOcsIds(\OC::$server->getConfig()),
new RepairInvalidShares(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
new SharePropagation(\OC::$server->getConfig()),
new RemoveOldShares(\OC::$server->getDatabaseConnection()),
new RemoveRootShares(\OC::$server->getDatabaseConnection(), \OC::$server->getUserManager(), \OC::$server->getLazyRootFolder()),
new RepairUnmergedShares(
\OC::$server->getConfig(),
\OC::$server->getDatabaseConnection(),
\OC::$server->getUserManager(),
\OC::$server->getGroupManager()
),
new MoveUpdaterStepFile(\OC::$server->getConfig()),
new MoveAvatars(
\OC::$server->getJobList(),
@ -183,20 +158,10 @@ class Repair implements IOutput{
public static function getBeforeUpgradeRepairSteps() {
$connection = \OC::$server->getDatabaseConnection();
$steps = [
new InnoDB(),
new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), $connection, true),
new SqliteAutoincrement($connection),
new SearchLuceneTables(),
];
//There is no need to delete all previews on every single update
//only 7.0.0 through 7.0.2 generated broken previews
$currentVersion = \OC::$server->getConfig()->getSystemValue('version');
if (version_compare($currentVersion, '7.0.0.0', '>=') &&
version_compare($currentVersion, '7.0.3.4', '<=')) {
$steps[] = new \OC\Repair\Preview();
}
return $steps;
}

View File

@ -1,43 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Adam Williamson <awilliam@redhat.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @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 OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class AssetCache implements IRepairStep {
public function getName() {
return 'Remove asset cache';
}
public function run(IOutput $output) {
$assetDir = \OC::$server->getConfig()->getSystemValue('assetdirectory', \OC::$SERVERROOT) . '/assets';
\OC_Helper::rmdirr($assetDir, false);
$output->info('Asset cache cleared.');
}
}

View File

@ -1,88 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Joas Schilling <coding@schilljs.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @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 OCP\BackgroundJob\IJobList;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class DropOldJobs implements IRepairStep {
/** @var IJobList */
protected $jobList;
/**
* @param IJobList $jobList
*/
public function __construct(IJobList $jobList) {
$this->jobList = $jobList;
}
/**
* Returns the step's name
*
* @return string
*/
public function getName() {
return 'Drop old background jobs';
}
/**
* Run repair step.
* Must throw exception on error.
*
* @throws \Exception in case of failure
*/
public function run(IOutput $output) {
$oldJobs = $this->oldJobs();
foreach($oldJobs as $job) {
if($this->jobList->has($job['class'], $job['arguments'])) {
$this->jobList->remove($job['class'], $job['arguments']);
}
}
}
/**
* returns a list of old jobs as an associative array with keys 'class' and
* 'arguments'.
*
* @return array
*/
public function oldJobs() {
return [
['class' => 'OC_Cache_FileGlobalGC', 'arguments' => null],
['class' => 'OC\Cache\FileGlobalGC', 'arguments' => null],
['class' => 'OCA\Files\BackgroundJob\DeleteOrphanedTagsJob', 'arguments' => null],
['class' => 'OCA\Files_sharing\Lib\DeleteOrphanedSharesJob', 'arguments' => null],
['class' => 'OCA\Files_sharing\ExpireSharesJob', 'arguments' => null],
['class' => 'OCA\user_ldap\lib\Jobs', 'arguments' => null],
['class' => '\OCA\User_LDAP\Jobs\CleanUp', 'arguments' => null],
];
}
}

View File

@ -1,111 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Florian Preinstorfer <nblock@archlinux.us>
* @author Joas Schilling <coding@schilljs.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @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 OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class DropOldTables implements IRepairStep {
/** @var IDBConnection */
protected $connection;
/**
* @param IDBConnection $connection
*/
public function __construct(IDBConnection $connection) {
$this->connection = $connection;
}
/**
* Returns the step's name
*
* @return string
*/
public function getName() {
return 'Drop old database tables';
}
/**
* Run repair step.
* Must throw exception on error.
*
* @throws \Exception in case of failure
*/
public function run(IOutput $output) {
$tables = $this->oldDatabaseTables();
$output->startProgress(count($tables));
foreach ($this->oldDatabaseTables() as $tableName) {
if ($this->connection->tableExists($tableName)){
$this->connection->dropTable($tableName);
}
$output->advance(1, "Drop old database table: $tableName");
}
$output->finishProgress();
}
/**
* Returns a list of outdated tables which are not used anymore
* @return array
*/
protected function oldDatabaseTables() {
return [
'calendar_calendars',
'calendar_objects',
'calendar_share_calendar',
'calendar_share_event',
'file_map',
'foldersize',
'fscache',
'gallery_sharing',
'locks',
'log',
'media_albums',
'media_artists',
'media_sessions',
'media_songs',
'media_users',
'permissions',
'pictures_images_cache',
'principalgroups',
'principals',
'queuedtasks',
'sharing',
'clndr_calendars',
'clndr_objects',
'clndr_share_event',
'clndr_share_calendar',
'clndr_repeat',
'contacts_addressbooks',
'contacts_cards',
'contacts_cards_properties',
'gallery_albums',
'gallery_photos'
];
}
}

View File

@ -1,57 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Joas Schilling <coding@schilljs.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @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 OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class FillETags implements IRepairStep {
/** @var \OCP\IDBConnection */
protected $connection;
/**
* @param \OCP\IDBConnection $connection
*/
public function __construct($connection) {
$this->connection = $connection;
}
public function getName() {
return 'Generate ETags for file where no ETag is present.';
}
public function run(IOutput $output) {
$qb = $this->connection->getQueryBuilder();
$qb->update('filecache')
->set('etag', $qb->expr()->literal('xxx'))
->where($qb->expr()->eq('etag', $qb->expr()->literal('')))
->orWhere($qb->expr()->isNull('etag'));
$result = $qb->execute();
$output->info("ETags have been fixed for $result files/folders.");
}
}

View File

@ -1,70 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @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 Doctrine\DBAL\Platforms\MySqlPlatform;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class InnoDB implements IRepairStep {
public function getName() {
return 'Repair MySQL database engine';
}
/**
* Fix mime types
*/
public function run(IOutput $output) {
$connection = \OC::$server->getDatabaseConnection();
if (!$connection->getDatabasePlatform() instanceof MySqlPlatform) {
$output->info('Not a mysql database -> nothing to do');
return;
}
$tables = $this->getAllMyIsamTables($connection);
if (is_array($tables)) {
foreach ($tables as $table) {
$connection->exec("ALTER TABLE $table ENGINE=InnoDB;");
$output->info("Fixed $table");
}
}
}
/**
* @param \Doctrine\DBAL\Connection $connection
* @return string[]
*/
private function getAllMyIsamTables($connection) {
$dbName = \OC::$server->getConfig()->getSystemValue("dbname");
$result = $connection->fetchArray(
"SELECT table_name FROM information_schema.tables WHERE table_schema = ? AND engine = 'MyISAM' AND TABLE_NAME LIKE \"*PREFIX*%\"",
array($dbName)
);
return $result;
}
}

View File

@ -1,48 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Georg Ehrke <georg@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @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\Files\View;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class Preview implements IRepairStep {
public function getName() {
return 'Cleaning-up broken previews';
}
public function run(IOutput $out) {
$view = new View('/');
$children = $view->getDirectoryContent('/');
foreach ($children as $child) {
if ($view->is_dir($child->getPath())) {
$thumbnailsFolder = $child->getPath() . '/thumbnails';
if ($view->is_dir($thumbnailsFolder)) {
$view->rmdir($thumbnailsFolder);
}
}
}
}
}

View File

@ -1,58 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @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 OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class RemoveGetETagEntries implements IRepairStep {
/**
* @var IDBConnection
*/
protected $connection;
/**
* @param IDBConnection $connection
*/
public function __construct(IDBConnection $connection) {
$this->connection = $connection;
}
public function getName() {
return 'Remove getetag entries in properties table';
}
/**
* Removes all entries with the key "{DAV:}getetag" from the table properties
*/
public function run(IOutput $out) {
$sql = 'DELETE FROM `*PREFIX*properties`'
. ' WHERE `propertyname` = ?';
$deletedRows = $this->connection->executeUpdate($sql, ['{DAV:}getetag']);
$out->info('Removed ' . $deletedRows . ' unneeded "{DAV:}getetag" entries from properties table.');
}
}

View File

@ -1,104 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @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 OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
/**
* Class RemoveOldShares
*
* @package OC\Repair
*/
class RemoveOldShares implements IRepairStep {
/** @var IDBConnection */
protected $connection;
/**
* RemoveOldCalendarShares constructor.
*
* @param IDBConnection $db
*/
public function __construct(IDBConnection $connection) {
$this->connection = $connection;
}
/**
* @return string
*/
public function getName() {
return 'Remove old (< 9.0) calendar/contact shares';
}
/**
* @param IOutput $output
*/
public function run(IOutput $output) {
$output->startProgress(4);
$this->removeCalendarShares($output);
$this->removeContactShares($output);
$output->finishProgress();
}
/**
* @param IOutput $output
*/
private function removeCalendarShares(IOutput $output) {
$qb = $this->connection->getQueryBuilder();
$qb->delete('share')
->where($qb->expr()->eq('item_type', $qb->createNamedParameter('calendar')));
$qb->execute();
$output->advance();
$qb = $this->connection->getQueryBuilder();
$qb->delete('share')
->where($qb->expr()->eq('item_type', $qb->createNamedParameter('event')));
$qb->execute();
$output->advance();
}
/**
* @param IOutput $output
*/
private function removeContactShares(IOutput $output) {
$qb = $this->connection->getQueryBuilder();
$qb->delete('share')
->where($qb->expr()->eq('item_type', $qb->createNamedParameter('contact')));
$qb->execute();
$output->advance();
$qb = $this->connection->getQueryBuilder();
$qb->delete('share')
->where($qb->expr()->eq('item_type', $qb->createNamedParameter('addressbook')));
$qb->execute();
$output->advance();
}
}

View File

@ -55,43 +55,6 @@ class RepairInvalidShares implements IRepairStep {
return 'Repair invalid shares';
}
/**
* Past bugs would make it possible to set an expiration date on user shares even
* though it is not supported. This functions removes the expiration date from such entries.
*/
private function removeExpirationDateFromNonLinkShares(IOutput $out) {
$builder = $this->connection->getQueryBuilder();
$builder
->update('share')
->set('expiration', 'null')
->where($builder->expr()->isNotNull('expiration'))
->andWhere($builder->expr()->neq('share_type', $builder->expr()->literal(\OC\Share\Constants::SHARE_TYPE_LINK)));
$updatedEntries = $builder->execute();
if ($updatedEntries > 0) {
$out->info('Removed invalid expiration date from ' . $updatedEntries . ' shares');
}
}
/**
* In the past link shares with public upload enabled were missing the delete permission.
*/
private function addShareLinkDeletePermission(IOutput $out) {
$oldPerms = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE;
$newPerms = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
$builder = $this->connection->getQueryBuilder();
$builder
->update('share')
->set('permissions', $builder->expr()->literal($newPerms))
->where($builder->expr()->eq('share_type', $builder->expr()->literal(\OC\Share\Constants::SHARE_TYPE_LINK)))
->andWhere($builder->expr()->eq('permissions', $builder->expr()->literal($oldPerms)));
$updatedEntries = $builder->execute();
if ($updatedEntries > 0) {
$out->info('Fixed link share permissions for ' . $updatedEntries . ' shares');
}
}
/**
* Adjust file share permissions
*/
@ -150,14 +113,6 @@ class RepairInvalidShares implements IRepairStep {
public function run(IOutput $out) {
$ocVersionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
if (version_compare($ocVersionFromBeforeUpdate, '8.2.0.7', '<')) {
// this situation was only possible before 8.2
$this->removeExpirationDateFromNonLinkShares($out);
}
if (version_compare($ocVersionFromBeforeUpdate, '9.1.0.9', '<')) {
// this situation was only possible before 9.1
$this->addShareLinkDeletePermission($out);
}
if (version_compare($ocVersionFromBeforeUpdate, '12.0.0.11', '<')) {
$this->adjustFileSharePermissions($out);
}

View File

@ -78,24 +78,6 @@ class RepairMimeTypes implements IRepairStep {
');
}
private static function updateWrongStmt() {
return \OC_DB::prepare('
UPDATE `*PREFIX*filecache`
SET `mimetype` = (
SELECT `id`
FROM `*PREFIX*mimetypes`
WHERE `mimetype` = ?
) WHERE `mimetype` = ?
');
}
private static function deleteStmt() {
return \OC_DB::prepare('
DELETE FROM `*PREFIX*mimetypes`
WHERE `id` = ?
');
}
private static function updateByNameStmt() {
return \OC_DB::prepare('
UPDATE `*PREFIX*filecache`
@ -104,34 +86,6 @@ class RepairMimeTypes implements IRepairStep {
');
}
private function repairMimetypes($wrongMimetypes) {
foreach ($wrongMimetypes as $wrong => $correct) {
// do we need to remove a wrong mimetype?
$result = \OC_DB::executeAudited(self::getIdStmt(), array($wrong));
$wrongId = $result->fetchOne();
if ($wrongId !== false) {
// do we need to insert the correct mimetype?
$result = \OC_DB::executeAudited(self::existsStmt(), array($correct));
$exists = $result->fetchOne();
if (!is_null($correct)) {
if (!$exists) {
// insert mimetype
\OC_DB::executeAudited(self::insertStmt(), array($correct));
}
// change wrong mimetype to correct mimetype in filecache
\OC_DB::executeAudited(self::updateWrongStmt(), array($correct, $wrongId));
}
// delete wrong mimetype
\OC_DB::executeAudited(self::deleteStmt(), array($wrongId));
}
}
}
private function updateMimetypes($updatedMimetypes) {
if (empty($this->folderMimeTypeId)) {
$result = \OC_DB::executeAudited(self::getIdStmt(), array('httpd/unix-directory'));
@ -156,158 +110,6 @@ class RepairMimeTypes implements IRepairStep {
}
}
private function fixOfficeMimeTypes() {
// update wrong mimetypes
$wrongMimetypes = array(
'application/mspowerpoint' => 'application/vnd.ms-powerpoint',
'application/msexcel' => 'application/vnd.ms-excel',
);
self::repairMimetypes($wrongMimetypes);
$updatedMimetypes = array(
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
);
// separate doc from docx etc
self::updateMimetypes($updatedMimetypes);
}
private function fixApkMimeType() {
$updatedMimetypes = array(
'apk' => 'application/vnd.android.package-archive',
);
self::updateMimetypes($updatedMimetypes);
}
private function fixFontsMimeTypes() {
// update wrong mimetypes
$wrongMimetypes = array(
'font' => null,
'font/opentype' => 'application/font-sfnt',
'application/x-font-ttf' => 'application/font-sfnt',
);
self::repairMimetypes($wrongMimetypes);
$updatedMimetypes = array(
'ttf' => 'application/font-sfnt',
'otf' => 'application/font-sfnt',
'pfb' => 'application/x-font',
);
self::updateMimetypes($updatedMimetypes);
}
private function fixPostscriptMimeType() {
$updatedMimetypes = array(
'eps' => 'application/postscript',
'ps' => 'application/postscript',
);
self::updateMimetypes($updatedMimetypes);
}
private function introduceRawMimeType() {
$updatedMimetypes = array(
'arw' => 'image/x-dcraw',
'cr2' => 'image/x-dcraw',
'dcr' => 'image/x-dcraw',
'dng' => 'image/x-dcraw',
'erf' => 'image/x-dcraw',
'iiq' => 'image/x-dcraw',
'k25' => 'image/x-dcraw',
'kdc' => 'image/x-dcraw',
'mef' => 'image/x-dcraw',
'nef' => 'image/x-dcraw',
'orf' => 'image/x-dcraw',
'pef' => 'image/x-dcraw',
'raf' => 'image/x-dcraw',
'rw2' => 'image/x-dcraw',
'srf' => 'image/x-dcraw',
'sr2' => 'image/x-dcraw',
'xrf' => 'image/x-dcraw',
);
self::updateMimetypes($updatedMimetypes);
}
private function introduce3dImagesMimeType() {
$updatedMimetypes = array(
'jps' => 'image/jpeg',
'mpo' => 'image/jpeg',
);
self::updateMimetypes($updatedMimetypes);
}
private function introduceConfMimeType() {
$updatedMimetypes = array(
'conf' => 'text/plain',
'cnf' => 'text/plain',
);
self::updateMimetypes($updatedMimetypes);
}
private function introduceYamlMimeType() {
$updatedMimetypes = array(
'yaml' => 'application/yaml',
'yml' => 'application/yaml',
);
self::updateMimetypes($updatedMimetypes);
}
private function introduceJavaMimeType() {
$updatedMimetypes = array(
'class' => 'application/java',
'java' => 'text/x-java-source',
);
self::updateMimetypes($updatedMimetypes);
}
private function introduceHppMimeType() {
$updatedMimetypes = array(
'hpp' => 'text/x-h',
);
self::updateMimetypes($updatedMimetypes);
}
private function introduceRssMimeType() {
$updatedMimetypes = array(
'rss' => 'application/rss+xml',
);
self::updateMimetypes($updatedMimetypes);
}
private function introduceRtfMimeType() {
$updatedMimetypes = array(
'rtf' => 'text/rtf',
);
self::updateMimetypes($updatedMimetypes);
}
private function introduceRichDocumentsMimeTypes() {
$updatedMimetypes = array(
'lwp' => 'application/vnd.lotus-wordpro',
'one' => 'application/msonenote',
'vsd' => 'application/vnd.visio',
'wpd' => 'application/vnd.wordperfect',
);
self::updateMimetypes($updatedMimetypes);
}
private function introduceWindowsProgramTypes() {
$updatedMimetypes = array(
'htaccess' => 'text/plain',
@ -328,66 +130,6 @@ class RepairMimeTypes implements IRepairStep {
// NOTE TO DEVELOPERS: when adding new mime types, please make sure to
// add a version comparison to avoid doing it every time
// only update mime types if necessary as it can be expensive
if (version_compare($ocVersionFromBeforeUpdate, '8.2.0', '<')) {
if ($this->fixOfficeMimeTypes()) {
$out->info('Fixed office mime types');
}
if ($this->fixApkMimeType()) {
$out->info('Fixed APK mime type');
}
if ($this->fixFontsMimeTypes()) {
$out->info('Fixed fonts mime types');
}
if ($this->fixPostscriptMimeType()) {
$out->info('Fixed Postscript mime types');
}
if ($this->introduceRawMimeType()) {
$out->info('Fixed Raw mime types');
}
if ($this->introduce3dImagesMimeType()) {
$out->info('Fixed 3D images mime types');
}
if ($this->introduceConfMimeType()) {
$out->info('Fixed Conf/cnf mime types');
}
if ($this->introduceYamlMimeType()) {
$out->info('Fixed Yaml/Yml mime types');
}
}
// Mimetype updates from #19272
if (version_compare($ocVersionFromBeforeUpdate, '8.2.0.8', '<')) {
if ($this->introduceJavaMimeType()) {
$out->info('Fixed java/class mime types');
}
if ($this->introduceHppMimeType()) {
$out->info('Fixed hpp mime type');
}
if ($this->introduceRssMimeType()) {
$out->info('Fixed rss mime type');
}
if ($this->introduceRtfMimeType()) {
$out->info('Fixed rtf mime type');
}
}
if (version_compare($ocVersionFromBeforeUpdate, '9.0.0.10', '<')) {
if ($this->introduceRichDocumentsMimeTypes()) {
$out->info('Fixed richdocuments additional office mime types');
}
}
if (version_compare($ocVersionFromBeforeUpdate, '12.0.0.13', '<') && $this->introduceWindowsProgramTypes()) {
$out->info('Fixed windows program mime types');
}

View File

@ -1,357 +0,0 @@
<?php
/**
* @author Vincent Petry <pvince81@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\Repair;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
use OC\Share\Constants;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IUserManager;
use OCP\IUser;
use OCP\IGroupManager;
use OC\Share20\DefaultShareProvider;
/**
* Repairs shares for which the received folder was not properly deduplicated.
*
* An unmerged share can for example happen when sharing a folder with the same
* user through multiple ways, like several groups and also directly, additionally
* to group shares. Since 9.0.0 these would create duplicate entries "folder (2)",
* one for every share. This repair step rearranges them so they only appear as a single
* folder.
*/
class RepairUnmergedShares implements IRepairStep {
/** @var \OCP\IConfig */
protected $config;
/** @var \OCP\IDBConnection */
protected $connection;
/** @var IUserManager */
protected $userManager;
/** @var IGroupManager */
protected $groupManager;
/** @var IQueryBuilder */
private $queryGetSharesWithUsers;
/** @var IQueryBuilder */
private $queryUpdateSharePermissionsAndTarget;
/** @var IQueryBuilder */
private $queryUpdateShareInBatch;
/**
* @param \OCP\IConfig $config
* @param \OCP\IDBConnection $connection
*/
public function __construct(
IConfig $config,
IDBConnection $connection,
IUserManager $userManager,
IGroupManager $groupManager
) {
$this->connection = $connection;
$this->config = $config;
$this->userManager = $userManager;
$this->groupManager = $groupManager;
}
public function getName() {
return 'Repair unmerged shares';
}
/**
* Builds prepared queries for reuse
*/
private function buildPreparedQueries() {
/**
* Retrieve shares for a given user/group and share type
*/
$query = $this->connection->getQueryBuilder();
$query
->select('item_source', 'id', 'file_target', 'permissions', 'parent', 'share_type', 'stime')
->from('share')
->where($query->expr()->eq('share_type', $query->createParameter('shareType')))
->andWhere($query->expr()->in('share_with', $query->createParameter('shareWiths')))
->andWhere($query->expr()->in('item_type', $query->createParameter('itemTypes')))
->orderBy('item_source', 'ASC')
->addOrderBy('stime', 'ASC');
$this->queryGetSharesWithUsers = $query;
/**
* Updates the file_target to the given value for all given share ids.
*
* This updates several shares in bulk which is faster than individually.
*/
$query = $this->connection->getQueryBuilder();
$query->update('share')
->set('file_target', $query->createParameter('file_target'))
->where($query->expr()->in('id', $query->createParameter('ids')));
$this->queryUpdateShareInBatch = $query;
/**
* Updates the share permissions and target path of a single share.
*/
$query = $this->connection->getQueryBuilder();
$query->update('share')
->set('permissions', $query->createParameter('permissions'))
->set('file_target', $query->createParameter('file_target'))
->where($query->expr()->eq('id', $query->createParameter('shareid')));
$this->queryUpdateSharePermissionsAndTarget = $query;
}
private function getSharesWithUser($shareType, $shareWiths) {
$groupedShares = [];
$query = $this->queryGetSharesWithUsers;
$query->setParameter('shareWiths', $shareWiths, IQueryBuilder::PARAM_STR_ARRAY);
$query->setParameter('shareType', $shareType);
$query->setParameter('itemTypes', ['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY);
$shares = $query->execute()->fetchAll();
// group by item_source
foreach ($shares as $share) {
if (!isset($groupedShares[$share['item_source']])) {
$groupedShares[$share['item_source']] = [];
}
$groupedShares[$share['item_source']][] = $share;
}
return $groupedShares;
}
private function isPotentialDuplicateName($name) {
return (preg_match('/\(\d+\)(\.[^\.]+)?$/', $name) === 1);
}
/**
* Decide on the best target name based on all group shares and subshares,
* goal is to increase the likeliness that the chosen name matches what
* the user is expecting.
*
* For this, we discard the entries with parenthesis "(2)".
* In case the user also renamed the duplicates to a legitimate name, this logic
* will still pick the most recent one as it's the one the user is most likely to
* remember renaming.
*
* If no suitable subshare is found, use the least recent group share instead.
*
* @param array $groupShares group share entries
* @param array $subShares sub share entries
*
* @return string chosen target name
*/
private function findBestTargetName($groupShares, $subShares) {
$pickedShare = null;
// sort by stime, this also properly sorts the direct user share if any
@usort($subShares, function($a, $b) {
return ((int)$a['stime'] - (int)$b['stime']);
});
foreach ($subShares as $subShare) {
// skip entries that have parenthesis with numbers
if ($this->isPotentialDuplicateName($subShare['file_target'])) {
continue;
}
// pick any share found that would match, the last being the most recent
$pickedShare = $subShare;
}
// no suitable subshare found
if ($pickedShare === null) {
// use least recent group share target instead
$pickedShare = $groupShares[0];
}
return $pickedShare['file_target'];
}
/**
* Fix the given received share represented by the set of group shares
* and matching sub shares
*
* @param array $groupShares group share entries
* @param array $subShares sub share entries
*
* @return boolean false if the share was not repaired, true if it was
*/
private function fixThisShare($groupShares, $subShares) {
if (empty($subShares)) {
return false;
}
$groupSharesById = [];
foreach ($groupShares as $groupShare) {
$groupSharesById[$groupShare['id']] = $groupShare;
}
if ($this->isThisShareValid($groupSharesById, $subShares)) {
return false;
}
$targetPath = $this->findBestTargetName($groupShares, $subShares);
// check whether the user opted out completely of all subshares
$optedOut = true;
foreach ($subShares as $subShare) {
if ((int)$subShare['permissions'] !== 0) {
$optedOut = false;
break;
}
}
$shareIds = [];
foreach ($subShares as $subShare) {
// only if the user deleted some subshares but not all, adjust the permissions of that subshare
if (!$optedOut && (int)$subShare['permissions'] === 0 && (int)$subShare['share_type'] === DefaultShareProvider::SHARE_TYPE_USERGROUP) {
// set permissions from parent group share
$permissions = $groupSharesById[$subShare['parent']]['permissions'];
// fix permissions and target directly
$query = $this->queryUpdateSharePermissionsAndTarget;
$query->setParameter('shareid', $subShare['id']);
$query->setParameter('file_target', $targetPath);
$query->setParameter('permissions', $permissions);
$query->execute();
} else {
// gather share ids for bulk target update
if ($subShare['file_target'] !== $targetPath) {
$shareIds[] = (int)$subShare['id'];
}
}
}
if (!empty($shareIds)) {
$query = $this->queryUpdateShareInBatch;
$query->setParameter('ids', $shareIds, IQueryBuilder::PARAM_INT_ARRAY);
$query->setParameter('file_target', $targetPath);
$query->execute();
}
return true;
}
/**
* Checks whether the number of group shares is balanced with the child subshares.
* If all group shares have exactly one subshare, and the target of every subshare
* is the same, then the share is valid.
* If however there is a group share entry that has no matching subshare, it means
* we're in the bogus situation and the whole share must be repaired
*
* @param array $groupSharesById
* @param array $subShares
*
* @return true if the share is valid, false if it needs repair
*/
private function isThisShareValid($groupSharesById, $subShares) {
$foundTargets = [];
// every group share needs to have exactly one matching subshare
foreach ($subShares as $subShare) {
$foundTargets[$subShare['file_target']] = true;
if (count($foundTargets) > 1) {
// not all the same target path value => invalid
return false;
}
if (isset($groupSharesById[$subShare['parent']])) {
// remove it from the list as we found it
unset($groupSharesById[$subShare['parent']]);
}
}
// if we found one subshare per group entry, the set will be empty.
// If not empty, it means that one of the group shares did not have
// a matching subshare entry.
return empty($groupSharesById);
}
/**
* Detect unmerged received shares and merge them properly
*/
private function fixUnmergedShares(IOutput $out, IUser $user) {
$groups = $this->groupManager->getUserGroupIds($user);
if (empty($groups)) {
// user is in no groups, so can't have received group shares
return;
}
// get all subshares grouped by item source
$subSharesByItemSource = $this->getSharesWithUser(DefaultShareProvider::SHARE_TYPE_USERGROUP, [$user->getUID()]);
// because sometimes one wants to give the user more permissions than the group share
$userSharesByItemSource = $this->getSharesWithUser(Constants::SHARE_TYPE_USER, [$user->getUID()]);
if (empty($subSharesByItemSource) && empty($userSharesByItemSource)) {
// nothing to repair for this user, no need to do extra queries
return;
}
$groupSharesByItemSource = $this->getSharesWithUser(Constants::SHARE_TYPE_GROUP, $groups);
if (empty($groupSharesByItemSource) && empty($userSharesByItemSource)) {
// nothing to repair for this user
return;
}
foreach ($groupSharesByItemSource as $itemSource => $groupShares) {
$subShares = [];
if (isset($subSharesByItemSource[$itemSource])) {
$subShares = $subSharesByItemSource[$itemSource];
}
if (isset($userSharesByItemSource[$itemSource])) {
// add it to the subshares to get a similar treatment
$subShares = array_merge($subShares, $userSharesByItemSource[$itemSource]);
}
$this->fixThisShare($groupShares, $subShares);
}
}
public function run(IOutput $output) {
$ocVersionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
if (version_compare($ocVersionFromBeforeUpdate, '9.1.0.16', '<')) {
// this situation was only possible between 9.0.0 and 9.0.3 included
$function = function(IUser $user) use ($output) {
$this->fixUnmergedShares($output, $user);
$output->advance();
};
$this->buildPreparedQueries();
$output->startProgress($this->userManager->countUsers());
$this->userManager->callForAllUsers($function);
$output->finishProgress();
}
}
}

View File

@ -1,80 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @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 OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class SearchLuceneTables implements IRepairStep {
public function getName() {
return 'Repair duplicate entries in oc_lucene_status';
}
/**
* Fix duplicate entries in oc_lucene_status
*
* search_lucene prior to v0.5.0 did not have a primary key on the lucene_status table. Newer versions do, which
* causes the migration check to fail because it tries to insert duplicate rows into the new schema.
*
* FIXME Currently, apps don't have a way of repairing anything before the migration check:
* @link https://github.com/owncloud/core/issues/10980
*
* As a result this repair step needs to live in the core repo, although it belongs into search_lucene:
* @link https://github.com/owncloud/core/issues/10205#issuecomment-54957557
*
* It will completely remove any rows that make a file id have more than one status:
* fileid | status fileid | status
* --------+-------- will become --------+--------
* 2 | E 3 | E
* 2 | I
* 3 | E
*
* search_lucene will then reindex the fileids without a status when the next indexing job is executed
*/
public function run(IOutput $out) {
$connection = \OC::$server->getDatabaseConnection();
if ($connection->tableExists('lucene_status')) {
$out->info('removing duplicate entries from lucene_status');
$query = $connection->prepare('
DELETE FROM `*PREFIX*lucene_status`
WHERE `fileid` IN (
SELECT `fileid`
FROM (
SELECT `fileid`
FROM `*PREFIX*lucene_status`
GROUP BY `fileid`
HAVING count(`fileid`) > 1
) AS `mysqlerr1093hack`
)');
$query->execute();
} else {
$out->info('lucene_status table does not exist -> nothing to do');
}
}
}

View File

@ -1,56 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Robin Appelman <robin@icewind.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @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 OCP\IConfig;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class SharePropagation implements IRepairStep {
/** @var IConfig */
private $config;
/**
* SharePropagation constructor.
*
* @param IConfig $config
*/
public function __construct(IConfig $config) {
$this->config = $config;
}
public function getName() {
return 'Remove old share propagation app entries';
}
public function run(IOutput $out ) {
$keys = $this->config->getAppKeys('files_sharing');
foreach ($keys as $key) {
if (is_numeric($key)) {
$this->config->deleteAppValue('files_sharing', $key);
}
}
}
}

View File

@ -1,90 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @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\Files\View;
use OC\Server;
use OCP\IConfig;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
/**
* Class UpdateCertificateStore rewrites the user specific certificate store after
* an update has been performed. This is done because a new root certificate file
* might have been added.
*
* @package OC\Repair
*/
class UpdateCertificateStore implements IRepairStep {
/**
* FIXME: The certificate manager does only allow specifying the user
* within the constructor. This makes DI impossible.
* @var Server
*/
protected $server;
/** @var IConfig */
protected $config;
/**
* @param Server $server
* @param IConfig $config
*/
public function __construct(Server $server,
IConfig $config) {
$this->server = $server;
$this->config = $config;
}
/** {@inheritDoc} */
public function getName() {
return 'Update user certificate stores with new root certificates';
}
/** {@inheritDoc} */
public function run(IOutput $out) {
$rootView = new View();
$dataDirectory = $this->config->getSystemValue('datadirectory', null);
if(is_null($dataDirectory)) {
throw new \Exception('No data directory specified');
}
$pathToRootCerts = '/files_external/rootcerts.crt';
foreach($rootView->getDirectoryContent('', 'httpd/unix-directory') as $fileInfo) {
$uid = trim($fileInfo->getPath(), '/');
if($rootView->file_exists($uid . $pathToRootCerts)) {
// Delete the existing root certificate
$rootView->unlink($uid . $pathToRootCerts);
/**
* FIXME: The certificate manager does only allow specifying the user
* within the constructor. This makes DI impossible.
*/
// Regenerate the certificates
$certificateManager = $this->server->getCertificateManager($uid);
$certificateManager->createCertificateBundle();
}
}
}
}

View File

@ -1,106 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @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 OCP\IConfig;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
/**
* Class UpdateOutdatedOcsIds is used to update invalid outdated OCS IDs, this is
* for example the case when an application has had another OCS ID in the past such
* as for contacts and calendar when apps.owncloud.com migrated to a unified identifier
* for multiple versions.
*
* @package OC\Repair
*/
class UpdateOutdatedOcsIds implements IRepairStep {
/** @var IConfig */
private $config;
/**
* @param IConfig $config
*/
public function __construct(IConfig $config) {
$this->config = $config;
}
/**
* {@inheritdoc}
*/
public function getName() {
return 'Repair outdated OCS IDs';
}
/**
* @param string $appName
* @param string $oldId
* @param string $newId
* @return bool True if updated, false otherwise
*/
public function fixOcsId($appName, $oldId, $newId) {
$existingId = $this->config->getAppValue($appName, 'ocsid');
if($existingId === $oldId) {
$this->config->setAppValue($appName, 'ocsid', $newId);
return true;
}
return false;
}
/**
* {@inheritdoc}
*/
public function run(IOutput $output) {
$appsToUpdate = [
'contacts' => [
'old' => '166044',
'new' => '168708',
],
'calendar' => [
'old' => '166043',
'new' => '168707',
],
'bookmarks' => [
'old' => '166042',
'new' => '168710',
],
'search_lucene' => [
'old' => '166057',
'new' => '168709',
],
'documents' => [
'old' => '166045',
'new' => '168711',
]
];
foreach($appsToUpdate as $appName => $ids) {
if ($this->fixOcsId($appName, $ids['old'], $ids['new'])) {
$output->info("Fixed invalid $appName OCS id");
}
}
}
}

View File

@ -1,48 +0,0 @@
<?php
/**
* Copyright (c) 2015 Arthur Schiwon <blizzz@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 OCP\BackgroundJob\IJobList;
use OCP\Migration\IOutput;
/**
* Tests for the dropping old tables
*
* @group DB
*
* @see \OC\Repair\DropOldTables
*/
class DropOldJobsTest extends \Test\TestCase {
/** @var IJobList */
protected $jobList;
protected function setUp() {
parent::setUp();
$this->jobList = \OC::$server->getJobList();
$this->jobList->add('OC\Cache\FileGlobalGC');
$this->jobList->add('OC_Cache_FileGlobalGC');
}
public function testRun() {
$this->assertTrue($this->jobList->has('OC\Cache\FileGlobalGC', null), 'Asserting that the job OC\Cache\FileGlobalGC exists before repairing');
$this->assertTrue($this->jobList->has('OC_Cache_FileGlobalGC', null), 'Asserting that the job OC_Cache_FileGlobalGC exists before repairing');
/** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */
$outputMock = $this->getMockBuilder('\OCP\Migration\IOutput')
->disableOriginalConstructor()
->getMock();
$repair = new \OC\Repair\DropOldJobs($this->jobList);
$repair->run($outputMock);
$this->assertFalse($this->jobList->has('OC\Cache\FileGlobalGC', null), 'Asserting that the job OC\Cache\FileGlobalGC does not exist after repairing');
$this->assertFalse($this->jobList->has('OC_Cache_FileGlobalGC', null), 'Asserting that the job OC_Cache_FileGlobalGC does not exist after repairing');
}
}

View File

@ -1,46 +0,0 @@
<?php
/**
* Copyright (c) 2015 Joas Schilling <nickvergessen@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 OCP\Migration\IOutput;
/**
* Tests for the dropping old tables
*
* @group DB
*
* @see \OC\Repair\DropOldTables
*/
class DropOldTablesTest extends \Test\TestCase {
/** @var \OCP\IDBConnection */
protected $connection;
protected function setUp() {
parent::setUp();
$this->connection = \OC::$server->getDatabaseConnection();
$manager = new \OC\DB\MDB2SchemaManager($this->connection);
$manager->createDbFromStructure(__DIR__ . '/fixtures/dropoldtables.xml');
}
public function testRun() {
$this->assertFalse($this->connection->tableExists('sharing'), 'Asserting that the table oc_sharing does not exist before repairing');
$this->assertTrue($this->connection->tableExists('permissions'), 'Asserting that the table oc_permissions does exist before repairing');
/** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */
$outputMock = $this->getMockBuilder('\OCP\Migration\IOutput')
->disableOriginalConstructor()
->getMock();
$repair = new \OC\Repair\DropOldTables($this->connection);
$repair->run($outputMock);
$this->assertFalse($this->connection->tableExists('sharing'), 'Asserting that the table oc_sharing does not exist after repairing');
$this->assertFalse($this->connection->tableExists('permissions'), 'Asserting that the table oc_permissions does not exist after repairing');
}
}

View File

@ -1,90 +0,0 @@
<?php
/**
* @author Morris Jobke <hey@morrisjobke.de>
*
* @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 Test\Repair;
use OC\Repair\RemoveGetETagEntries;
use OCP\Migration\IOutput;
use Test\TestCase;
/**
* Class RemoveGetETagEntriesTest
*
* @group DB
*
* @package Test\Repair
*/
class RemoveGetETagEntriesTest extends TestCase {
/** @var \OCP\IDBConnection */
protected $connection;
protected function setUp() {
parent::setUp();
$this->connection = \OC::$server->getDatabaseConnection();
}
public function testRun() {
$userName = 'removePropertiesUser';
$data = [
[$userName, '/abc.def.txt', '{DAV:}getetag', 'abcdef'],
[$userName, '/abc.def.txt', '{DAV:}anotherRandomProperty', 'ghi'],
];
// insert test data
$sqlToInsertProperties = 'INSERT INTO `*PREFIX*properties` (`userid`, `propertypath`, `propertyname`, `propertyvalue`) VALUES (?, ?, ? ,?)';
foreach ($data as $entry) {
$this->connection->executeUpdate($sqlToInsertProperties, $entry);
}
// check if test data is written to DB
$sqlToFetchProperties = 'SELECT `userid`, `propertypath`, `propertyname`, `propertyvalue` FROM `*PREFIX*properties` WHERE `userid` = ?';
$stmt = $this->connection->executeQuery($sqlToFetchProperties, [$userName]);
$entries = $stmt->fetchAll(\PDO::FETCH_NUM);
$this->assertCount(2, $entries, 'Asserts that two entries are returned as we have inserted two');
foreach($entries as $entry) {
$this->assertTrue(in_array($entry, $data), 'Asserts that the entries are the ones from the test data set');
}
/** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */
$outputMock = $this->getMockBuilder('\OCP\Migration\IOutput')
->disableOriginalConstructor()
->getMock();
// run repair step
$repair = new RemoveGetETagEntries($this->connection);
$repair->run($outputMock);
// check if test data is correctly modified in DB
$stmt = $this->connection->executeQuery($sqlToFetchProperties, [$userName]);
$entries = $stmt->fetchAll(\PDO::FETCH_NUM);
$this->assertCount(1, $entries, 'Asserts that only one entry is returned after the repair step - the other one has to be removed');
$this->assertSame($data[1], $entries[0], 'Asserts that the returned entry is the correct one from the test data set');
// remove test data
$sqlToRemoveProperties = 'DELETE FROM `*PREFIX*properties` WHERE `userid` = ?';
$this->connection->executeUpdate($sqlToRemoveProperties, [$userName]);
}
}

View File

@ -1,160 +0,0 @@
<?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 Test\Repair;
use OC\Repair\RemoveOldShares;
use OCP\IDBConnection;
use OCP\Migration\IOutput;
/**
* Class RemoveOldSharesTest
*
* @package Test\Repair
* @group DB
*/
class RemoveOldSharesTest extends \Test\TestCase {
/** @var RemoveOldShares */
protected $repair;
/** @var IDBConnection */
protected $connection;
/** @var IOutput */
private $outputMock;
protected function setUp() {
parent::setUp();
$this->outputMock = $this->getMockBuilder('\OCP\Migration\IOutput')
->disableOriginalConstructor()
->getMock();
$this->connection = \OC::$server->getDatabaseConnection();
$this->repair = new RemoveOldShares($this->connection);
}
protected function tearDown() {
$qb = $this->connection->getQueryBuilder();
$qb->delete('share');
$qb->execute();
return parent::tearDown();
}
public function testRun() {
$qb = $this->connection->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->createNamedParameter(0),
'share_with' => $qb->createNamedParameter('foo'),
'uid_owner' => $qb->createNamedParameter('owner'),
'item_type' => $qb->createNamedParameter('file'),
'item_source' => $qb->createNamedParameter(42),
'item_target' => $qb->createNamedParameter('/target'),
'file_source' => $qb->createNamedParameter(42),
'file_target' => $qb->createNamedParameter('/target'),
'permissions' => $qb->createNamedParameter(1),
]);
$qb->execute();
$qb = $this->connection->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->createNamedParameter(0),
'share_with' => $qb->createNamedParameter('foo'),
'uid_owner' => $qb->createNamedParameter('owner'),
'item_type' => $qb->createNamedParameter('calendar'),
'item_source' => $qb->createNamedParameter(42),
'item_target' => $qb->createNamedParameter('/target'),
'file_source' => $qb->createNamedParameter(42),
'file_target' => $qb->createNamedParameter('/target'),
'permissions' => $qb->createNamedParameter(1),
]);
$qb->execute();
$qb = $this->connection->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->createNamedParameter(0),
'share_with' => $qb->createNamedParameter('foo'),
'uid_owner' => $qb->createNamedParameter('owner'),
'item_type' => $qb->createNamedParameter('event'),
'item_source' => $qb->createNamedParameter(42),
'item_target' => $qb->createNamedParameter('/target'),
'file_source' => $qb->createNamedParameter(42),
'file_target' => $qb->createNamedParameter('/target'),
'permissions' => $qb->createNamedParameter(1),
]);
$qb->execute();
$qb = $this->connection->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->createNamedParameter(0),
'share_with' => $qb->createNamedParameter('foo'),
'uid_owner' => $qb->createNamedParameter('owner'),
'item_type' => $qb->createNamedParameter('contact'),
'item_source' => $qb->createNamedParameter(42),
'item_target' => $qb->createNamedParameter('/target'),
'file_source' => $qb->createNamedParameter(42),
'file_target' => $qb->createNamedParameter('/target'),
'permissions' => $qb->createNamedParameter(1),
]);
$qb->execute();
$qb = $this->connection->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->createNamedParameter(0),
'share_with' => $qb->createNamedParameter('foo'),
'uid_owner' => $qb->createNamedParameter('owner'),
'item_type' => $qb->createNamedParameter('addressbook'),
'item_source' => $qb->createNamedParameter(42),
'item_target' => $qb->createNamedParameter('/target'),
'file_source' => $qb->createNamedParameter(42),
'file_target' => $qb->createNamedParameter('/target'),
'permissions' => $qb->createNamedParameter(1),
]);
$qb->execute();
$qb = $this->connection->getQueryBuilder();
$qb->selectAlias($qb->createFunction('COUNT(*)'), 'count')
->from('share');
$cursor = $qb->execute();
$data = $cursor->fetchAll();
$cursor->closeCursor();
$this->assertEquals(5, $data[0]['count']);
$this->repair->run($this->outputMock);
$qb = $this->connection->getQueryBuilder();
$qb->select('*')
->from('share');
$cursor = $qb->execute();
$data = $cursor->fetchAll();
$cursor->closeCursor();
$this->assertCount(1, $data);
$this->assertEquals('file', $data[0]['item_type']);
}
}

View File

@ -1,78 +0,0 @@
<?php
/**
* Copyright (c) 2014 Thomas Müller <deepdiver@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 OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
/**
* Tests for the converting of MySQL tables to InnoDB engine
*
* @group DB
*
* @see \OC\Repair\RepairMimeTypes
*/
class RepairInnoDBTest extends \Test\TestCase {
/** @var IRepairStep */
private $repair;
/** @var \Doctrine\DBAL\Connection */
private $connection;
/** @var string */
private $tableName;
protected function setUp() {
parent::setUp();
$this->connection = \OC::$server->getDatabaseConnection();
if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\MySqlPlatform) {
$this->markTestSkipped("Test only relevant on MySql");
}
$dbPrefix = \OC::$server->getConfig()->getSystemValue("dbtableprefix");
$this->tableName = $this->getUniqueID($dbPrefix . "_innodb_test");
$this->connection->exec("CREATE TABLE $this->tableName(id INT) ENGINE MyISAM");
$this->repair = new \OC\Repair\InnoDB();
}
protected function tearDown() {
$this->connection->getSchemaManager()->dropTable($this->tableName);
parent::tearDown();
}
public function testInnoDBConvert() {
$result = $this->countMyIsamTables();
$this->assertEquals(1, $result);
/** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */
$outputMock = $this->getMockBuilder('\OCP\Migration\IOutput')
->disableOriginalConstructor()
->getMock();
$this->repair->run($outputMock);
$result = $this->countMyIsamTables();
$this->assertEquals(0, $result);
}
/**
* @param $dbName
* @return mixed
*/
private function countMyIsamTables() {
$dbName = \OC::$server->getConfig()->getSystemValue("dbname");
$result = $this->connection->fetchColumn(
"SELECT count(*) FROM information_schema.tables WHERE table_schema = ? and table_name = ? AND engine = 'MyISAM'",
array($dbName, $this->tableName)
);
return $result;
}
}

View File

@ -39,7 +39,7 @@ class RepairInvalidSharesTest extends TestCase {
$config->expects($this->any())
->method('getSystemValue')
->with('version')
->will($this->returnValue('8.0.0.0'));
->will($this->returnValue('12.0.0.0'));
$this->connection = \OC::$server->getDatabaseConnection();
$this->deleteAllShares();
@ -59,157 +59,6 @@ class RepairInvalidSharesTest extends TestCase {
$qb->delete('share')->execute();
}
/**
* Test remove expiration date for non-link shares
*/
public function testRemoveExpirationDateForNonLinkShares() {
// user share with bogus expiration date
$qb = $this->connection->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->expr()->literal(Constants::SHARE_TYPE_USER),
'share_with' => $qb->expr()->literal('recipientuser1'),
'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')
])
->execute();
$bogusShareId = $this->getLastShareId();
// link share with expiration date
$qb = $this->connection->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->expr()->literal(Constants::SHARE_TYPE_LINK),
'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'),
'token' => $qb->expr()->literal('abcdefg')
])->execute();
/** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */
$outputMock = $this->getMockBuilder('\OCP\Migration\IOutput')
->disableOriginalConstructor()
->getMock();
$this->repair->run($outputMock);
$results = $this->connection->getQueryBuilder()
->select('*')
->from('share')
->orderBy('share_type', 'ASC')
->execute()
->fetchAll();
$this->assertCount(2, $results);
$userShare = $results[0];
$linkShare = $results[1];
$this->assertEquals($bogusShareId, $userShare['id'], 'sanity check');
$this->assertNull($userShare['expiration'], 'bogus expiration date was removed');
$this->assertNotNull($linkShare['expiration'], 'valid link share expiration date still there');
}
/**
* Test remove expiration date for non-link shares
*/
public function testAddShareLinkDeletePermission() {
$oldPerms = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE;
$newPerms = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
// share with old permissions
$qb = $this->connection->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->expr()->literal(Constants::SHARE_TYPE_LINK),
'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($oldPerms),
'stime' => $qb->expr()->literal(time()),
])
->execute();
$bogusShareId = $this->getLastShareId();
// share with read-only permissions
$qb = $this->connection->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->expr()->literal(Constants::SHARE_TYPE_LINK),
'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(\OCP\Constants::PERMISSION_READ),
'stime' => $qb->expr()->literal(time()),
])
->execute();
$keepThisShareId = $this->getLastShareId();
// user share to keep
$qb = $this->connection->getQueryBuilder();
$qb->insert('share')
->values([
'share_type' => $qb->expr()->literal(Constants::SHARE_TYPE_USER),
'share_with' => $qb->expr()->literal('recipientuser1'),
'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(3),
'stime' => $qb->expr()->literal(time()),
])
->execute();
$keepThisShareId2 = $this->getLastShareId();
/** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */
$outputMock = $this->getMockBuilder('\OCP\Migration\IOutput')
->disableOriginalConstructor()
->getMock();
$this->repair->run($outputMock);
$results = $this->connection->getQueryBuilder()
->select('*')
->from('share')
->orderBy('permissions', 'ASC')
->execute()
->fetchAll();
$this->assertCount(3, $results);
$untouchedShare = $results[0];
$untouchedShare2 = $results[1];
$updatedShare = $results[2];
$this->assertEquals($keepThisShareId, $untouchedShare['id'], 'sanity check');
$this->assertEquals($keepThisShareId2, $untouchedShare2['id'], 'sanity check');
$this->assertEquals($bogusShareId, $updatedShare['id'], 'sanity check');
$this->assertEquals($newPerms, $updatedShare['permissions'], 'delete permission was added');
}
/**
* Test remove shares where the parent share does not exist anymore
*/

View File

@ -45,7 +45,7 @@ class RepairMimeTypesTest extends \Test\TestCase {
$config->expects($this->any())
->method('getSystemValue')
->with('version')
->will($this->returnValue('8.0.0.0'));
->will($this->returnValue('11.0.0.0'));
$this->storage = new \OC\Files\Storage\Temporary([]);
@ -90,20 +90,6 @@ class RepairMimeTypesTest extends \Test\TestCase {
}
}
/**
* Returns the id of a given mime type or null
* if it does not exist.
*/
private function getMimeTypeIdFromDB($mimeType) {
$sql = 'SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?';
$results = \OC_DB::executeAudited($sql, [$mimeType]);
$result = $results->fetchOne();
if ($result) {
return $result['id'];
}
return null;
}
private function renameMimeTypes($currentMimeTypes, $fixedMimeTypes) {
$this->addEntries($currentMimeTypes);
@ -120,344 +106,27 @@ class RepairMimeTypesTest extends \Test\TestCase {
$this->checkEntries($fixedMimeTypes);
}
/**
* Test renaming and splitting old office mime types
*/
public function testRenameOfficeMimeTypes() {
$currentMimeTypes = [
['test.doc', 'application/msword'],
['test.docx', 'application/msword'],
['test.xls', 'application/msexcel'],
['test.xlsx', 'application/msexcel'],
['test.ppt', 'application/mspowerpoint'],
['test.pptx', 'application/mspowerpoint'],
];
$fixedMimeTypes = [
['test.doc', 'application/msword'],
['test.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
['test.xls', 'application/vnd.ms-excel'],
['test.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
['test.ppt', 'application/vnd.ms-powerpoint'],
['test.pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming old fonts mime types
*/
public function testRenameFontsMimeTypes() {
$currentMimeTypes = [
['test.ttf', 'application/x-font-ttf'],
['test.otf', 'font/opentype'],
['test.pfb', 'application/octet-stream'],
];
$fixedMimeTypes = [
['test.ttf', 'application/font-sfnt'],
['test.otf', 'application/font-sfnt'],
['test.pfb', 'application/x-font'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming the APK mime type
*/
public function testRenameAPKMimeType() {
$currentMimeTypes = [
['test.apk', 'application/octet-stream'],
['bogus.apk', 'application/vnd.android.package-archive'],
['bogus2.apk', 'application/wrong'],
];
$fixedMimeTypes = [
['test.apk', 'application/vnd.android.package-archive'],
['bogus.apk', 'application/vnd.android.package-archive'],
['bogus2.apk', 'application/vnd.android.package-archive'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming the postscript mime types
*/
public function testRenamePostscriptMimeType() {
$currentMimeTypes = [
['test.eps', 'application/octet-stream'],
['test.ps', 'application/octet-stream'],
];
$fixedMimeTypes = [
['test.eps', 'application/postscript'],
['test.ps', 'application/postscript'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming the Raw mime types
*/
public function testRenameRawMimeType() {
$currentMimeTypes = [
['test.arw', 'application/octet-stream'],
['test.cr2', 'application/octet-stream'],
['test.dcr', 'application/octet-stream'],
['test.dng', 'application/octet-stream'],
['test.erf', 'application/octet-stream'],
['test.iiq', 'application/octet-stream'],
['test.k25', 'application/octet-stream'],
['test.kdc', 'application/octet-stream'],
['test.mef', 'application/octet-stream'],
['test.nef', 'application/octet-stream'],
['test.orf', 'application/octet-stream'],
['test.pef', 'application/octet-stream'],
['test.raf', 'application/octet-stream'],
['test.rw2', 'application/octet-stream'],
['test.srf', 'application/octet-stream'],
['test.sr2', 'application/octet-stream'],
['test.xrf', 'application/octet-stream'],
['CapitalExtension.DNG', 'application/octet-stream'],
];
$fixedMimeTypes = [
['test.arw', 'image/x-dcraw'],
['test.cr2', 'image/x-dcraw'],
['test.dcr', 'image/x-dcraw'],
['test.dng', 'image/x-dcraw'],
['test.erf', 'image/x-dcraw'],
['test.iiq', 'image/x-dcraw'],
['test.k25', 'image/x-dcraw'],
['test.kdc', 'image/x-dcraw'],
['test.mef', 'image/x-dcraw'],
['test.nef', 'image/x-dcraw'],
['test.orf', 'image/x-dcraw'],
['test.pef', 'image/x-dcraw'],
['test.raf', 'image/x-dcraw'],
['test.rw2', 'image/x-dcraw'],
['test.srf', 'image/x-dcraw'],
['test.sr2', 'image/x-dcraw'],
['test.xrf', 'image/x-dcraw'],
['CapitalExtension.DNG', 'image/x-dcraw'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming the 3D image media type
*/
public function testRename3dImagesMimeType() {
$currentMimeTypes = [
['test.jps', 'application/octet-stream'],
['test.mpo', 'application/octet-stream'],
];
$fixedMimeTypes = [
['test.jps', 'image/jpeg'],
['test.mpo', 'image/jpeg'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming the conf/cnf media type
*/
public function testRenameConfMimeType() {
$currentMimeTypes = [
['test.conf', 'application/octet-stream'],
['test.cnf', 'application/octet-stream'],
];
$fixedMimeTypes = [
['test.conf', 'text/plain'],
['test.cnf', 'text/plain'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming the yaml media type
*/
public function testRenameYamlMimeType() {
$currentMimeTypes = [
['test.yaml', 'application/octet-stream'],
['test.yml', 'application/octet-stream'],
];
$fixedMimeTypes = [
['test.yaml', 'application/yaml'],
['test.yml', 'application/yaml'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming the java mime types
*/
public function testRenameJavaMimeType() {
$currentMimeTypes = [
['test.java', 'application/octet-stream'],
['test.class', 'application/octet-stream'],
];
$fixedMimeTypes = [
['test.java', 'text/x-java-source'],
['test.class', 'application/java'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming the hpp mime type
*/
public function testRenameHppMimeType() {
$currentMimeTypes = [
['test.hpp', 'application/octet-stream'],
];
$fixedMimeTypes = [
['test.hpp', 'text/x-h'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming the rss mime type
*/
public function testRenameRssMimeType() {
$currentMimeTypes = [
['test.rss', 'application/octet-stream'],
];
$fixedMimeTypes = [
['test.rss', 'application/rss+xml'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming the hpp mime type
*/
public function testRenameRtfMimeType() {
$currentMimeTypes = [
['test.rtf', 'application/octet-stream'],
];
$fixedMimeTypes = [
['test.rtf', 'text/rtf'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming the richdocuments additional office mime types
*/
public function testRenameRichDocumentsMimeTypes() {
public function testRenameWindowsProgramTypes() {
$currentMimeTypes = [
['test.lwp', 'application/octet-stream'],
['test.one', 'application/octet-stream'],
['test.vsd', 'application/octet-stream'],
['test.wpd', 'application/octet-stream'],
['test.htaccess', 'application/octet-stream'],
['.htaccess', 'application/octet-stream'],
['test.bat', 'application/octet-stream'],
['test.cmd', 'application/octet-stream'],
];
$fixedMimeTypes = [
['test.lwp', 'application/vnd.lotus-wordpro'],
['test.one', 'application/msonenote'],
['test.vsd', 'application/vnd.visio'],
['test.wpd', 'application/vnd.wordperfect'],
['test.htaccess', 'text/plain'],
['.htaccess', 'text/plain'],
['test.bat', 'application/x-msdos-program'],
['test.cmd', 'application/cmd'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
}
/**
* Test renaming and splitting old office mime types when
* new ones already exist
*/
public function testRenameOfficeMimeTypesWhenExist() {
$currentMimeTypes = [
['test.doc', 'application/msword'],
['test.docx', 'application/msword'],
['test.xls', 'application/msexcel'],
['test.xlsx', 'application/msexcel'],
['test.ppt', 'application/mspowerpoint'],
['test.pptx', 'application/mspowerpoint'],
// make it so that the new mimetypes already exist
['bogus.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
['bogus.xlsx', 'application/vnd.ms-excel'],
['bogus.pptx', 'application/vnd.ms-powerpoint'],
['bogus2.docx', 'application/wrong'],
['bogus2.xlsx', 'application/wrong'],
['bogus2.pptx', 'application/wrong'],
];
$fixedMimeTypes = [
['test.doc', 'application/msword'],
['test.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
['test.xls', 'application/vnd.ms-excel'],
['test.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
['test.ppt', 'application/vnd.ms-powerpoint'],
['test.pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'],
['bogus.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
['bogus.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
['bogus.pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'],
['bogus2.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
['bogus2.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
['bogus2.pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
// wrong mimetypes are gone
$this->assertNull($this->getMimeTypeIdFromDB('application/msexcel'));
$this->assertNull($this->getMimeTypeIdFromDB('application/mspowerpoint'));
}
/**
* Test renaming old fonts mime types when
* new ones already exist
*/
public function testRenameFontsMimeTypesWhenExist() {
$currentMimeTypes = [
['test.ttf', 'application/x-font-ttf'],
['test.otf', 'font/opentype'],
// make it so that the new mimetypes already exist
['bogus.ttf', 'application/font-sfnt'],
['bogus.otf', 'application/font-sfnt'],
['bogus2.ttf', 'application/wrong'],
['bogus2.otf', 'application/wrong'],
];
$fixedMimeTypes = [
['test.ttf', 'application/font-sfnt'],
['test.otf', 'application/font-sfnt'],
['bogus.ttf', 'application/font-sfnt'],
['bogus.otf', 'application/font-sfnt'],
['bogus2.ttf', 'application/font-sfnt'],
['bogus2.otf', 'application/font-sfnt'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);
// wrong mimetypes are gone
$this->assertNull($this->getMimeTypeIdFromDB('application/x-font-ttf'));
$this->assertNull($this->getMimeTypeIdFromDB('font'));
$this->assertNull($this->getMimeTypeIdFromDB('font/opentype'));
}
/**
* Test that nothing happens and no error happens when all mimetypes are
* already correct and no old ones exist..
@ -509,6 +178,10 @@ class RepairMimeTypesTest extends \Test\TestCase {
['test.one', 'application/msonenote'],
['test.vsd', 'application/vnd.visio'],
['test.wpd', 'application/vnd.wordperfect'],
['test.htaccess', 'text/plain'],
['.htaccess', 'text/plain'],
['test.bat', 'application/x-msdos-program'],
['test.cmd', 'application/cmd'],
];
$fixedMimeTypes = [
@ -557,6 +230,10 @@ class RepairMimeTypesTest extends \Test\TestCase {
['test.one', 'application/msonenote'],
['test.vsd', 'application/vnd.visio'],
['test.wpd', 'application/vnd.wordperfect'],
['test.htaccess', 'text/plain'],
['.htaccess', 'text/plain'],
['test.bat', 'application/x-msdos-program'],
['test.cmd', 'application/cmd'],
];
$this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes);

View File

@ -1,58 +0,0 @@
<?php
/**
* Copyright (c) 2016 Robin Appelman <icewind@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\SharePropagation;
use OCP\IConfig;
use OCP\Migration\IOutput;
class RepairSharePropagationTest extends \Test\TestCase {
public function keyProvider() {
return [
[['1', '2'], ['1', '2']],
[['1', '2', 'foo'], ['1', '2']],
[['foo'], []],
];
}
/**
* @dataProvider keyProvider
* @param array $startKeys
* @param array $expectedRemovedKeys
*/
public function testRemovePropagationEntries(array $startKeys, array $expectedRemovedKeys) {
/** @var \PHPUnit_Framework_MockObject_MockObject|\OCP\IConfig $config */
$config = $this->createMock(IConfig::class);
$config->expects($this->once())
->method('getAppKeys')
->with('files_sharing')
->will($this->returnValue($startKeys));
$removedKeys = [];
$config->expects($this->any())
->method('deleteAppValue')
->will($this->returnCallback(function ($app, $key) use (&$removedKeys) {
$removedKeys[] = $key;
}));
/** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */
$outputMock = $this->getMockBuilder('\OCP\Migration\IOutput')
->disableOriginalConstructor()
->getMock();
$step = new SharePropagation($config);
$step->run($outputMock);
sort($expectedRemovedKeys);
sort($removedKeys);
$this->assertEquals($expectedRemovedKeys, $removedKeys);
}
}

View File

@ -1,575 +0,0 @@
<?php
/**
* @author Vincent Petry <pvince81@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 Test\Repair;
use OC\Repair\RepairUnmergedShares;
use OC\Share\Constants;
use OCP\IUser;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
use Test\TestCase;
use OC\Share20\DefaultShareProvider;
use OCP\IUserManager;
use OCP\IGroupManager;
/**
* Tests for repairing invalid shares
*
* @group DB
*
* @see \OC\Repair\RepairUnmergedShares
*/
class RepairUnmergedSharesTest extends TestCase {
/** @var IRepairStep */
private $repair;
/** @var \OCP\IDBConnection */
private $connection;
/** @var int */
private $lastShareTime;
/** @var IUserManager */
private $userManager;
/** @var IGroupManager */
private $groupManager;
protected function setUp() {
parent::setUp();
$config = $this->getMockBuilder('OCP\IConfig')
->disableOriginalConstructor()
->getMock();
$config->expects($this->any())
->method('getSystemValue')
->with('version')
->will($this->returnValue('9.0.3.0'));
$this->connection = \OC::$server->getDatabaseConnection();
$this->deleteAllShares();
$this->userManager = $this->createMock(IUserManager::class);
$this->groupManager = $this->createMock(IGroupManager::class);
// used to generate incremental stimes
$this->lastShareTime = time();
/** @var \OCP\IConfig $config */
$this->repair = new RepairUnmergedShares($config, $this->connection, $this->userManager, $this->groupManager);
}
protected function tearDown() {
$this->deleteAllShares();
parent::tearDown();
}
protected function deleteAllShares() {
$qb = $this->connection->getQueryBuilder();
$qb->delete('share')->execute();
}
private function createShare($type, $sourceId, $recipient, $targetName, $permissions, $parentId = null) {
$this->lastShareTime += 100;
$qb = $this->connection->getQueryBuilder();
$values = [
'share_type' => $qb->expr()->literal($type),
'share_with' => $qb->expr()->literal($recipient),
'uid_owner' => $qb->expr()->literal('user1'),
'item_type' => $qb->expr()->literal('folder'),
'item_source' => $qb->expr()->literal($sourceId),
'item_target' => $qb->expr()->literal('/' . $sourceId),
'file_source' => $qb->expr()->literal($sourceId),
'file_target' => $qb->expr()->literal($targetName),
'permissions' => $qb->expr()->literal($permissions),
'stime' => $qb->expr()->literal($this->lastShareTime),
];
if ($parentId !== null) {
$values['parent'] = $qb->expr()->literal($parentId);
}
$qb->insert('share')
->values($values)
->execute();
return $this->connection->lastInsertId('*PREFIX*share');
}
private function getShareById($id) {
$query = $this->connection->getQueryBuilder();
$results = $query
->select('*')
->from('share')
->where($query->expr()->eq('id', $query->expr()->literal($id)))
->execute()
->fetchAll();
if (!empty($results)) {
return $results[0];
}
return null;
}
public function sharesDataProvider() {
/**
* For all these test cases we have the following situation:
*
* - "user1" is the share owner
* - "user2" is the recipient, and member of "recipientgroup1" and "recipientgroup2"
* - "user1" is member of "samegroup1", "samegroup2" for same group tests
*/
return [
[
// #0 legitimate share:
// - outsider shares with group1, group2
// - recipient renamed, resulting in subshares
// - one subshare for each group share
// - targets of subshare all match
[
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 31],
// child of the previous ones
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test renamed', 31, 0],
// child of the previous ones
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test renamed', 31, 1],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
],
[
['/test', 31],
['/test', 31],
// leave them alone
['/test renamed', 31],
['/test renamed', 31],
// leave unrelated alone
['/test (4)', 31],
]
],
[
// #1 broken share:
// - outsider shares with group1, group2
// - only one subshare for two group shares
[
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 31],
// child of the previous one
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 31, 1],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
],
[
['/test', 31],
['/test', 31],
['/test', 31],
// leave unrelated alone
['/test (4)', 31],
]
],
[
// #2 bogus share
// - outsider shares with group1, group2
// - one subshare for each group share, both with parenthesis
// - but the targets do not match when grouped
[
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 31],
// child of the previous ones
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 31, 0],
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (3)', 31, 1],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
],
[
['/test', 31],
['/test', 31],
// reset to original name as the sub-names have parenthesis
['/test', 31],
['/test', 31],
// leave unrelated alone
['/test (4)', 31],
]
],
[
// #3 bogus share
// - outsider shares with group1, group2
// - one subshare for each group share, both renamed manually
// - but the targets do not match when grouped
[
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 31],
// child of the previous ones
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test_renamed (1 legit paren)', 31, 0],
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test_renamed (2 legit paren)', 31, 1],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
],
[
['/test', 31],
['/test', 31],
// reset to less recent subshare name
['/test_renamed (2 legit paren)', 31],
['/test_renamed (2 legit paren)', 31],
// leave unrelated alone
['/test (4)', 31],
]
],
[
// #4 bogus share
// - outsider shares with group1, group2
// - one subshare for each group share, one with parenthesis
// - but the targets do not match when grouped
[
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 31],
// child of the previous ones
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 31, 0],
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test_renamed', 31, 1],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
],
[
['/test', 31],
['/test', 31],
// reset to less recent subshare name but without parenthesis
['/test_renamed', 31],
['/test_renamed', 31],
// leave unrelated alone
['/test (4)', 31],
]
],
[
// #5 bogus share
// - outsider shares with group1, group2
// - one subshare for each group share
// - first subshare not renamed (as in real world scenario)
// - but the targets do not match when grouped
[
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 31],
// child of the previous ones
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test', 31, 0],
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 31, 1],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
],
[
['/test', 31],
['/test', 31],
// reset to original name
['/test', 31],
['/test', 31],
// leave unrelated alone
['/test (4)', 31],
]
],
[
// #6 bogus share:
// - outsider shares with group1, group2
// - one subshare for each group share
// - non-matching targets
// - recipient deletes one duplicate (unshare from self, permissions 0)
[
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 15],
// child of the previous ones
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 0, 0],
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (3)', 15, 1],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
],
[
['/test', 31],
['/test', 15],
// subshares repaired and permissions restored to the max allowed
['/test', 31],
['/test', 15],
// leave unrelated alone
['/test (4)', 31],
]
],
[
// #7 bogus share:
// - outsider shares with group1, group2
// - one subshare for each group share
// - non-matching targets
// - recipient deletes ALL duplicates (unshare from self, permissions 0)
[
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 15],
// child of the previous ones
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 0, 0],
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (3)', 0, 1],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
],
[
['/test', 31],
['/test', 15],
// subshares target repaired but left "deleted" as it was the user's choice
['/test', 0],
['/test', 0],
// leave unrelated alone
['/test (4)', 31],
]
],
[
// #8 bogus share:
// - outsider shares with group1, group2 and also user2
// - one subshare for each group share
// - one extra share entry for direct share to user2
// - non-matching targets
// - user share has more permissions
[
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 1],
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 15],
// child of the previous ones
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 1, 0],
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (3)', 15, 1],
[Constants::SHARE_TYPE_USER, 123, 'user2', '/test (4)', 31],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (5)', 31],
],
[
['/test', 1],
['/test', 15],
// subshares repaired
['/test', 1],
['/test', 15],
['/test', 31],
// leave unrelated alone
['/test (5)', 31],
]
],
[
// #9 bogus share:
// - outsider shares with group1 and also user2
// - no subshare at all
// - one extra share entry for direct share to user2
// - non-matching targets
// - user share has more permissions
[
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 1],
[Constants::SHARE_TYPE_USER, 123, 'user2', '/test (2)', 31],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (5)', 31],
],
[
['/test', 1],
// user share repaired
['/test', 31],
// leave unrelated alone
['/test (5)', 31],
]
],
[
// #10 legitimate share with own group:
// - insider shares with both groups the user is already in
// - no subshares in this case
[
[Constants::SHARE_TYPE_GROUP, 123, 'samegroup1', '/test', 31],
[Constants::SHARE_TYPE_GROUP, 123, 'samegroup2', '/test', 31],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
],
[
// leave all alone
['/test', 31],
['/test', 31],
// leave unrelated alone
['/test (4)', 31],
]
],
[
// #11 legitimate shares:
// - group share with same group
// - group share with other group
// - user share where recipient renamed
// - user share where recipient did not rename
[
[Constants::SHARE_TYPE_GROUP, 123, 'samegroup1', '/test', 31],
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
[Constants::SHARE_TYPE_USER, 123, 'user3', '/test legit rename', 31],
[Constants::SHARE_TYPE_USER, 123, 'user4', '/test', 31],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
],
[
// leave all alone
['/test', 31],
['/test', 31],
['/test legit rename', 31],
['/test', 31],
// leave unrelated alone
['/test (4)', 31],
]
],
[
// #12 legitimate share:
// - outsider shares with group and user directly with different permissions
// - no subshares
// - same targets
[
[Constants::SHARE_TYPE_GROUP, 123, 'samegroup1', '/test', 1],
[Constants::SHARE_TYPE_USER, 123, 'user3', '/test', 31],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
],
[
// leave all alone
['/test', 1],
['/test', 31],
// leave unrelated alone
['/test (4)', 31],
]
],
[
// #13 bogus share:
// - outsider shares with group1, user2 and then group2
// - user renamed share as soon as it arrived before the next share (order)
// - one subshare for each group share
// - one extra share entry for direct share to user2
// - non-matching targets
[
// first share with group
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
// recipient renames
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/first', 31, 0],
// then direct share, user renames too
[Constants::SHARE_TYPE_USER, 123, 'user2', '/second', 31],
// another share with the second group
[Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 31],
// use renames it
[DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/third', 31, 1],
// different unrelated share
[Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (5)', 31],
],
[
// group share with group1 left alone
['/test', 31],
// first subshare repaired
['/third', 31],
// direct user share repaired
['/third', 31],
// group share with group2 left alone
['/test', 31],
// second subshare repaired
['/third', 31],
// leave unrelated alone
['/test (5)', 31],
]
],
];
}
/**
* Test merge shares from group shares
*
* @dataProvider sharesDataProvider
*/
public function testMergeGroupShares($shares, $expectedShares) {
$user1 = $this->createMock(IUser::class);
$user1->expects($this->any())
->method('getUID')
->will($this->returnValue('user1'));
$user2 = $this->createMock(IUser::class);
$user2->expects($this->any())
->method('getUID')
->will($this->returnValue('user2'));
$users = [$user1, $user2];
$this->groupManager->expects($this->any())
->method('getUserGroupIds')
->will($this->returnValueMap([
// owner
[$user1, ['samegroup1', 'samegroup2']],
// recipient
[$user2, ['recipientgroup1', 'recipientgroup2']],
]));
$this->userManager->expects($this->once())
->method('countUsers')
->will($this->returnValue([2]));
$this->userManager->expects($this->once())
->method('callForAllUsers')
->will($this->returnCallback(function(\Closure $closure) use ($users) {
foreach ($users as $user) {
$closure($user);
}
}));
$shareIds = [];
foreach ($shares as $share) {
// if parent
if (isset($share[5])) {
// adjust to real id
$share[5] = $shareIds[$share[5]];
} else {
$share[5] = null;
}
$shareIds[] = $this->createShare($share[0], $share[1], $share[2], $share[3], $share[4], $share[5]);
}
/** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */
$outputMock = $this->getMockBuilder('\OCP\Migration\IOutput')
->disableOriginalConstructor()
->getMock();
$this->repair->run($outputMock);
foreach ($expectedShares as $index => $expectedShare) {
$share = $this->getShareById($shareIds[$index]);
$this->assertEquals($expectedShare[0], $share['file_target']);
$this->assertEquals($expectedShare[1], $share['permissions']);
}
}
public function duplicateNamesProvider() {
return [
// matching
['filename (1).txt', true],
['folder (2)', true],
['filename (1)(2).txt', true],
// non-matching
['filename ().txt', false],
['folder ()', false],
['folder (1x)', false],
['folder (x1)', false],
['filename (a)', false],
['filename (1).', false],
['filename (1).txt.txt', false],
['filename (1)..txt', false],
];
}
/**
* @dataProvider duplicateNamesProvider
*/
public function testIsPotentialDuplicateName($name, $expectedResult) {
$this->assertEquals($expectedResult, $this->invokePrivate($this->repair, 'isPotentialDuplicateName', [$name]));
}
}

View File

@ -1,80 +0,0 @@
<?php
/**
* @author Lukas Reschke <l8kas@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 Test\Repair;
use OCP\IConfig;
use Test\TestCase;
/**
* Class UpdateOutdatedOcsIds
*
* @package Test\Repair
*/
class UpdateOutdatedOcsIdsTest extends TestCase {
/** @var IConfig | \PHPUnit_Framework_MockObject_MockObject */
private $config;
/** @var \OC\Repair\UpdateOutdatedOcsIds */
private $updateOutdatedOcsIds;
public function setUp() {
parent::setUp();
$this->config = $this->getMockBuilder('\\OCP\\IConfig')->getMock();
$this->updateOutdatedOcsIds = new \OC\Repair\UpdateOutdatedOcsIds($this->config);
}
public function testGetName() {
$this->assertSame('Repair outdated OCS IDs', $this->updateOutdatedOcsIds->getName());
}
public function testFixOcsIdNoOcsId() {
$this->config
->expects($this->once())
->method('getAppValue')
->with('MyNotInstalledApp', 'ocsid')
->will($this->returnValue(''));
$this->assertFalse($this->updateOutdatedOcsIds->fixOcsId('MyNotInstalledApp', '1337', '0815'));
}
public function testFixOcsIdUpdateOcsId() {
$this->config
->expects($this->at(0))
->method('getAppValue')
->with('MyInstalledApp', 'ocsid')
->will($this->returnValue('1337'));
$this->config
->expects($this->at(1))
->method('setAppValue')
->with('MyInstalledApp', 'ocsid', '0815');
$this->assertTrue($this->updateOutdatedOcsIds->fixOcsId('MyInstalledApp', '1337', '0815'));
}
public function testFixOcsIdAlreadyFixed() {
$this->config
->expects($this->once())
->method('getAppValue')
->with('MyAlreadyFixedAppId', 'ocsid')
->will($this->returnValue('0815'));
$this->assertFalse($this->updateOutdatedOcsIds->fixOcsId('MyAlreadyFixedAppId', '1337', '0815'));
}
}

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<database>
<name>*dbname*</name>
<create>true</create>
<overwrite>false</overwrite>
<charset>utf8</charset>
<table>
<name>*dbprefix*permissions</name>
<declaration>
<field>
<name>textfield</name>
<type>text</type>
<default>foo</default>
<notnull>true</notnull>
<length>32</length>
</field>
</declaration>
</table>
</database>