diff --git a/core/Migrations/Version15000Date20180927120000.php b/core/Migrations/Version15000Date20180927120000.php index d5c4b3364f..5636811baa 100644 --- a/core/Migrations/Version15000Date20180927120000.php +++ b/core/Migrations/Version15000Date20180927120000.php @@ -38,9 +38,9 @@ class Version15000Date20180927120000 extends SimpleMigrationStep { $table = $schema->getTable('cards'); $table->addColumn('uid', Type::STRING, [ - 'notnull' => true, - 'length' => 255] - ); + 'notnull' => false, + 'length' => 255 + ]); return $schema; } diff --git a/lib/private/Repair/NC15/SetVcardDatabaseUID.php b/lib/private/Repair/NC15/SetVcardDatabaseUID.php new file mode 100644 index 0000000000..2fe50c7947 --- /dev/null +++ b/lib/private/Repair/NC15/SetVcardDatabaseUID.php @@ -0,0 +1,127 @@ + + * + * @author John Molakvoæ + * + * @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 . + * + */ + +namespace OC\Repair\NC13; + + +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class SetVcardDatabaseUID implements IRepairStep { + const MAX_ROWS = 1000; + + /** @var IDBConnection */ + private $connection; + private $updateQuery; + + public function __construct(IDBConnection $connection) { + $this->connection = $connection; + } + + + public function getName() { + return 'Extract the vcard uid and store it in the db'; + } + + /** + * @return \Generator + * @suppress SqlInjectionChecker + */ + private function getInvalidEntries() { + $builder = $this->connection->getQueryBuilder(); + + $builder->select('id', 'carddata') + ->from('cards') + ->where($builder->expr()->isNull('uid')) + ->setMaxResults(self::MAX_ROWS); + + do { + $result = $builder->execute(); + $rows = $result->fetchAll(); + foreach ($rows as $row) { + yield $row; + } + $result->closeCursor(); + } while (count($rows) > 0); + } + + private function getUid($carddata) { + preg_match('/^UID:(.*)$/m', $carddata, $matches); + if (count($matches > 1)) { + return $matches[1][0]; + } + return false; + } + + /** + * @param int $id + * @param string $uid + */ + private function update($id, $uid) { + if (!$this->updateQuery) { + $builder = $this->connection->getQueryBuilder(); + + $this->updateQuery = $builder->update('cards') + ->set('uid', $builder->createParameter('uid')) + ->where($builder->expr()->eq('id', $builder->createParameter('id'))); + } + + $this->updateQuery->setParameter('id', $id); + $this->updateQuery->setParameter('uid', $uid); + + $this->updateQuery->execute(); + } + + private function repair() { + $this->connection->beginTransaction(); + $entries = $this->getInvalidEntries(); + $count = 0; + foreach ($entries as $entry) { + $count++; + $uid = $this->getUid($entry['id']); + if ($uid !== false) { + $this->update($entry['id'], $uid); + } + } + $this->connection->commit(); + return $count; + } + + private function shouldRun() { + $versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0'); + + // was added to 15.0.0.0 + return version_compare($versionFromBeforeUpdate, '15.0.0.0', '<='); + } + + public function run(IOutput $output) { + if ($this->shouldRun()) { + $count = $this->repair(); + + $output->info('Fixed ' . $count . ' vcards'); + } + } +}