summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukas Reschke <lukas@statuscode.ch>2017-05-18 22:31:36 +0200
committerGitHub <noreply@github.com>2017-05-18 22:31:36 +0200
commit10930c9ff29fb551d50a2dc29a61d18e61602d15 (patch)
tree7278a2f4d69f5ed6b2f212d65c52557b4b08b03d
parent879e11e7d1d9802647ade392f4ae317952bc6f8f (diff)
parent682a57d50e8ce3ef2307fe50eba9f91ff6537cc4 (diff)
downloadnextcloud-server-10930c9ff29fb551d50a2dc29a61d18e61602d15.tar.gz
nextcloud-server-10930c9ff29fb551d50a2dc29a61d18e61602d15.zip
Merge pull request #4813 from nextcloud/accounts-table-migration-from-owncloud
Add a migration step to save the data from the accounts table before …
-rw-r--r--lib/composer/composer/autoload_classmap.php1
-rw-r--r--lib/composer/composer/autoload_static.php1
-rw-r--r--lib/private/Repair.php3
-rw-r--r--lib/private/Repair/NC11/MoveAvatarsBackgroundJob.php72
-rw-r--r--lib/private/Repair/Owncloud/SaveAccountsTableData.php176
-rw-r--r--lib/private/Updater.php19
-rw-r--r--version.php1
7 files changed, 257 insertions, 16 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 10233f07a2a..8e65ca365e4 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -738,6 +738,7 @@ return array(
'OC\\Repair\\NC12\\InstallCoreBundle' => $baseDir . '/lib/private/Repair/NC12/InstallCoreBundle.php',
'OC\\Repair\\NC12\\UpdateLanguageCodes' => $baseDir . '/lib/private/Repair/NC12/UpdateLanguageCodes.php',
'OC\\Repair\\OldGroupMembershipShares' => $baseDir . '/lib/private/Repair/OldGroupMembershipShares.php',
+ 'OC\\Repair\\Owncloud\\SaveAccountsTableData' => $baseDir . '/lib/private/Repair/Owncloud/SaveAccountsTableData.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',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 9c0f0871133..b9a1545e6a3 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -768,6 +768,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Repair\\NC12\\InstallCoreBundle' => __DIR__ . '/../../..' . '/lib/private/Repair/NC12/InstallCoreBundle.php',
'OC\\Repair\\NC12\\UpdateLanguageCodes' => __DIR__ . '/../../..' . '/lib/private/Repair/NC12/UpdateLanguageCodes.php',
'OC\\Repair\\OldGroupMembershipShares' => __DIR__ . '/../../..' . '/lib/private/Repair/OldGroupMembershipShares.php',
+ 'OC\\Repair\\Owncloud\\SaveAccountsTableData' => __DIR__ . '/../../..' . '/lib/private/Repair/Owncloud/SaveAccountsTableData.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',
diff --git a/lib/private/Repair.php b/lib/private/Repair.php
index 65e0342905a..4d14bf2550c 100644
--- a/lib/private/Repair.php
+++ b/lib/private/Repair.php
@@ -40,6 +40,7 @@ use OC\Repair\NC11\MoveAvatars;
use OC\Repair\NC12\InstallCoreBundle;
use OC\Repair\NC12\UpdateLanguageCodes;
use OC\Repair\OldGroupMembershipShares;
+use OC\Repair\Owncloud\SaveAccountsTableData;
use OC\Repair\RemoveRootShares;
use OC\Repair\SqliteAutoincrement;
use OC\Repair\RepairMimeTypes;
@@ -166,9 +167,11 @@ class Repair implements IOutput{
*/
public static function getBeforeUpgradeRepairSteps() {
$connection = \OC::$server->getDatabaseConnection();
+ $config = \OC::$server->getConfig();
$steps = [
new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), $connection, true),
new SqliteAutoincrement($connection),
+ new SaveAccountsTableData($connection, $config),
];
return $steps;
diff --git a/lib/private/Repair/NC11/MoveAvatarsBackgroundJob.php b/lib/private/Repair/NC11/MoveAvatarsBackgroundJob.php
index f8c0d9b3abf..d46b6fec8fc 100644
--- a/lib/private/Repair/NC11/MoveAvatarsBackgroundJob.php
+++ b/lib/private/Repair/NC11/MoveAvatarsBackgroundJob.php
@@ -28,6 +28,7 @@ use OCP\Files\Folder;
use OCP\Files\IAppData;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\ILogger;
use OCP\IUser;
use OCP\IUserManager;
@@ -63,8 +64,14 @@ class MoveAvatarsBackgroundJob extends QueuedJob {
}
private function moveAvatars() {
+ try {
+ $ownCloudAvatars = $this->rootFolder->get('avatars');
+ } catch (NotFoundException $e) {
+ $ownCloudAvatars = null;
+ }
+
$counter = 0;
- $this->userManager->callForSeenUsers(function (IUser $user) use ($counter) {
+ $this->userManager->callForSeenUsers(function (IUser $user) use ($counter, $ownCloudAvatars) {
$uid = $user->getUID();
\OC\Files\Filesystem::initMountPoints($uid);
@@ -77,26 +84,61 @@ class MoveAvatarsBackgroundJob extends QueuedJob {
$userData = $this->appData->newFolder($uid);
}
+ $foundAvatars = $this->copyAvatarsFromFolder($userFolder, $userData);
- $regex = '/^avatar\.([0-9]+\.)?(jpg|png)$/';
- $avatars = $userFolder->getDirectoryListing();
-
- foreach ($avatars as $avatar) {
- /** @var File $avatar */
- if (preg_match($regex, $avatar->getName())) {
- /*
- * This is not the most effective but it is the most abstract way
- * to handle this. Avatars should be small anyways.
- */
- $newAvatar = $userData->newFile($avatar->getName());
- $newAvatar->putContent($avatar->getContent());
- $avatar->delete();
+ // ownCloud migration?
+ if ($foundAvatars === 0 && $ownCloudAvatars instanceof Folder) {
+ $parts = $this->buildOwnCloudAvatarPath($uid);
+ $userOwnCloudAvatar = $ownCloudAvatars;
+ foreach ($parts as $part) {
+ try {
+ $userOwnCloudAvatar = $userOwnCloudAvatar->get($part);
+ } catch (NotFoundException $e) {
+ return;
+ }
}
+
+ $this->copyAvatarsFromFolder($userOwnCloudAvatar, $userData);
}
+
$counter++;
- if ($counter % 100) {
+ if ($counter % 100 === 0) {
$this->logger->info('{amount} avatars migrated', ['amount' => $counter]);
}
});
}
+
+ /**
+ * @param Folder $source
+ * @param ISimpleFolder $target
+ * @return int
+ * @throws \OCP\Files\NotPermittedException
+ * @throws NotFoundException
+ */
+ protected function copyAvatarsFromFolder(Folder $source, ISimpleFolder $target) {
+ $foundAvatars = 0;
+ $avatars = $source->getDirectoryListing();
+ $regex = '/^avatar\.([0-9]+\.)?(jpg|png)$/';
+
+ foreach ($avatars as $avatar) {
+ /** @var File $avatar */
+ if (preg_match($regex, $avatar->getName())) {
+ /*
+ * This is not the most effective but it is the most abstract way
+ * to handle this. Avatars should be small anyways.
+ */
+ $newAvatar = $target->newFile($avatar->getName());
+ $newAvatar->putContent($avatar->getContent());
+ $avatar->delete();
+ $foundAvatars++;
+ }
+ }
+
+ return $foundAvatars;
+ }
+
+ protected function buildOwnCloudAvatarPath($userId) {
+ $avatar = substr_replace(substr_replace(md5($userId), '/', 4, 0), '/', 2, 0);
+ return explode('/', $avatar);
+ }
}
diff --git a/lib/private/Repair/Owncloud/SaveAccountsTableData.php b/lib/private/Repair/Owncloud/SaveAccountsTableData.php
new file mode 100644
index 00000000000..35e5560856b
--- /dev/null
+++ b/lib/private/Repair/Owncloud/SaveAccountsTableData.php
@@ -0,0 +1,176 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\Repair\Owncloud;
+
+use Doctrine\DBAL\Exception\InvalidFieldNameException;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+use OCP\PreConditionNotMetException;
+
+/**
+ * Copies the email address from the accounts table to the preference table,
+ * before the data structure is changed and the information is gone
+ */
+class SaveAccountsTableData implements IRepairStep {
+
+ const BATCH_SIZE = 75;
+
+ /** @var IDBConnection */
+ protected $db;
+
+ /** @var IConfig */
+ protected $config;
+
+ /**
+ * @param IDBConnection $db
+ * @param IConfig $config
+ */
+ public function __construct(IDBConnection $db, IConfig $config) {
+ $this->db = $db;
+ $this->config = $config;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName() {
+ return 'Copy data from accounts table when migrating from ownCloud';
+ }
+
+ /**
+ * @param IOutput $output
+ */
+ public function run(IOutput $output) {
+ if (!$this->shouldRun()) {
+ return;
+ }
+
+ $offset = 0;
+ $numUsers = $this->runStep($offset);
+
+ while ($numUsers === self::BATCH_SIZE) {
+ $offset += $numUsers;
+ $numUsers = $this->runStep($offset);
+ }
+
+ // Remove the table
+ $this->db->dropTable('accounts');
+ }
+
+ /**
+ * @return bool
+ */
+ protected function shouldRun() {
+ $query = $this->db->getQueryBuilder();
+ $query->select('*')
+ ->from('accounts')
+ ->where($query->expr()->isNotNull('user_id'))
+ ->setMaxResults(1);
+
+ try {
+ $query->execute();
+ return true;
+ } catch (InvalidFieldNameException $e) {
+ return false;
+ }
+ }
+
+ /**
+ * @param int $offset
+ * @return int Number of copied users
+ */
+ protected function runStep($offset) {
+ $query = $this->db->getQueryBuilder();
+ $query->select('*')
+ ->from('accounts')
+ ->orderBy('id')
+ ->setMaxResults(self::BATCH_SIZE);
+
+ if ($offset > 0) {
+ $query->setFirstResult($offset);
+ }
+
+ $result = $query->execute();
+
+ $update = $this->db->getQueryBuilder();
+ $update->update('users')
+ ->set('displayname', $update->createParameter('displayname'))
+ ->where($update->expr()->eq('uid', $update->createParameter('userid')));
+
+ $updatedUsers = 0;
+ while ($row = $result->fetch()) {
+ try {
+ $this->migrateUserInfo($update, $row);
+ } catch (PreConditionNotMetException $e) {
+ // Ignore and continue
+ } catch (\UnexpectedValueException $e) {
+ // Ignore and continue
+ }
+ $updatedUsers++;
+ }
+ $result->closeCursor();
+
+ return $updatedUsers;
+ }
+
+ /**
+ * @param IQueryBuilder $update
+ * @param array $userdata
+ * @throws PreConditionNotMetException
+ * @throws \UnexpectedValueException
+ */
+ protected function migrateUserInfo(IQueryBuilder $update, $userdata) {
+ $state = (int) $userdata['state'];
+ if ($state === 3) {
+ // Deleted user, ignore
+ return;
+ }
+
+ if ($userdata['email'] !== null) {
+ $this->config->setUserValue($userdata['user_id'], 'settings', 'email', $userdata['email']);
+ }
+ if ($userdata['quota'] !== null) {
+ $this->config->setUserValue($userdata['user_id'], 'files', 'quota', $userdata['quota']);
+ }
+ if ($userdata['last_login'] !== null) {
+ $this->config->setUserValue($userdata['user_id'], 'login', 'lastLogin', $userdata['last_login']);
+ }
+ if ($state === 1) {
+ $this->config->setUserValue($userdata['user_id'], 'core', 'enabled', 'true');
+ } else if ($state === 2) {
+ $this->config->setUserValue($userdata['user_id'], 'core', 'enabled', 'false');
+ }
+
+ if ($userdata['display_name'] !== null) {
+ $update->setParameter('displayname', $userdata['display_name'])
+ ->setParameter('userid', $userdata['user_id']);
+ $update->execute();
+ }
+
+ }
+}
+
diff --git a/lib/private/Updater.php b/lib/private/Updater.php
index 6f81e6175f3..6d08e5d4cc0 100644
--- a/lib/private/Updater.php
+++ b/lib/private/Updater.php
@@ -190,6 +190,22 @@ class Updater extends BasicEmitter {
$majorMinor = $version[0] . '.' . $version[1];
$currentVendor = $this->config->getAppValue('core', 'vendor', '');
+
+ // Vendor was not set correctly on install, so we have to white-list known versions
+ if ($currentVendor === '') {
+ if (in_array($oldVersion, [
+ '11.0.2.7',
+ '11.0.1.2',
+ '11.0.0.10',
+ ], true)) {
+ $currentVendor = 'nextcloud';
+ } else if (in_array($oldVersion, [
+ '10.0.0.12',
+ ], true)) {
+ $currentVendor = 'owncloud';
+ }
+ }
+
if ($currentVendor === 'nextcloud') {
return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
&& (version_compare($oldVersion, $newVersion, '<=') ||
@@ -197,7 +213,8 @@ class Updater extends BasicEmitter {
}
// Check if the instance can be migrated
- return isset($allowedPreviousVersions[$currentVendor][$majorMinor]);
+ return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
+ isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
}
/**
diff --git a/version.php b/version.php
index 37e15f35e1f..8673939044f 100644
--- a/version.php
+++ b/version.php
@@ -37,6 +37,7 @@ $OC_VersionCanBeUpgradedFrom = [
'12.0' => true,
],
'owncloud' => [
+ '10.0.0.12' => true,
],
];