]> source.dussan.org Git - nextcloud-server.git/commitdiff
Add optional column oc_comments.reference_id
authorJoas Schilling <coding@schilljs.com>
Wed, 11 Mar 2020 11:29:52 +0000 (12:29 +0100)
committerJoas Schilling <coding@schilljs.com>
Tue, 31 Mar 2020 08:51:15 +0000 (10:51 +0200)
Signed-off-by: Joas Schilling <coding@schilljs.com>
apps/settings/lib/Controller/CheckSetupController.php
apps/settings/tests/Controller/CheckSetupControllerTest.php
core/Application.php
core/Command/Db/AddMissingColumns.php [new file with mode: 0644]
core/Command/Db/AddMissingIndices.php
core/Migrations/Version13000Date20170718121200.php
core/js/setupchecks.js
core/js/tests/specs/setupchecksSpec.js
core/register_command.php
lib/private/DB/MissingColumnInformation.php [new file with mode: 0644]
lib/public/IDBConnection.php

index 04711cf5308ad74761bddb516ac7ec7cff29f0ff..6f3bb539eff568e8cd5c0720bebfd9c7b0619fa5 100644 (file)
@@ -46,6 +46,7 @@ use GuzzleHttp\Exception\ClientException;
 use OC;
 use OC\AppFramework\Http;
 use OC\DB\Connection;
+use OC\DB\MissingColumnInformation;
 use OC\DB\MissingIndexInformation;
 use OC\DB\SchemaWrapper;
 use OC\IntegrityCheck\Checker;
@@ -445,6 +446,15 @@ Raw output
                return $indexInfo->getListOfMissingIndexes();
        }
 
+       protected function hasMissingColumns(): array {
+               $indexInfo = new MissingColumnInformation();
+               // Dispatch event so apps can also hint for pending index updates if needed
+               $event = new GenericEvent($indexInfo);
+               $this->dispatcher->dispatch(IDBConnection::CHECK_MISSING_COLUMNS_EVENT, $event);
+
+               return $indexInfo->getListOfMissingColumns();
+       }
+
        protected function isSqliteUsed() {
                return strpos($this->config->getSystemValue('dbtype'), 'sqlite') !== false;
        }
@@ -693,6 +703,7 @@ Raw output
                                'isSettimelimitAvailable' => $this->isSettimelimitAvailable(),
                                'hasFreeTypeSupport' => $this->hasFreeTypeSupport(),
                                'missingIndexes' => $this->hasMissingIndexes(),
+                               'missingColumns' => $this->hasMissingColumns(),
                                'isSqliteUsed' => $this->isSqliteUsed(),
                                'databaseConversionDocumentation' => $this->urlGenerator->linkToDocs('admin-db-conversion'),
                                'isPHPMailerUsed' => $this->isPHPMailerUsed(),
index 5e59bfe353aff382ba2193a6b925a8088d4ea564..c15f3b8f23ac57c0de26e1493ed3939ec361f3db 100644 (file)
@@ -583,6 +583,7 @@ class CheckSetupControllerTest extends TestCase {
                                'isSqliteUsed' => false,
                                'databaseConversionDocumentation' => 'http://docs.example.org/server/go.php?to=admin-db-conversion',
                                'missingIndexes' => [],
+                               'missingColumns' => [],
                                'isPHPMailerUsed' => false,
                                'mailSettingsDocumentation' => 'https://server/index.php/settings/admin',
                                'isMemoryLimitSufficient' => true,
index c2da7f8d19467b32e859b6ca0505a0bb79f98635..e4fc33b5402ceeb52d855efcbf6111d5ad789e00 100644 (file)
@@ -39,6 +39,7 @@ use OC\Authentication\Listeners\RemoteWipeNotificationsListener;
 use OC\Authentication\Listeners\UserDeletedStoreCleanupListener;
 use OC\Authentication\Notifications\Notifier as AuthenticationNotifier;
 use OC\Core\Notification\RemoveLinkSharesNotifier;
+use OC\DB\MissingColumnInformation;
 use OC\DB\MissingIndexInformation;
 use OC\DB\SchemaWrapper;
 use OCP\AppFramework\App;
@@ -167,6 +168,23 @@ class Application extends App {
                        }
                );
 
+               $eventDispatcher->addListener(IDBConnection::CHECK_MISSING_COLUMNS_EVENT,
+                       function (GenericEvent $event) use ($container) {
+                               /** @var MissingColumnInformation $subject */
+                               $subject = $event->getSubject();
+
+                               $schema = new SchemaWrapper($container->query(IDBConnection::class));
+
+                               if ($schema->hasTable('comments')) {
+                                       $table = $schema->getTable('comments');
+
+                                       if (!$table->hasColumn('reference_id')) {
+                                               $subject->addHintForMissingColumn($table->getName(), 'reference_id');
+                                       }
+                               }
+                       }
+               );
+
                $eventDispatcher->addServiceListener(RemoteWipeStarted::class, RemoteWipeActivityListener::class);
                $eventDispatcher->addServiceListener(RemoteWipeStarted::class, RemoteWipeNotificationsListener::class);
                $eventDispatcher->addServiceListener(RemoteWipeStarted::class, RemoteWipeEmailListener::class);
diff --git a/core/Command/Db/AddMissingColumns.php b/core/Command/Db/AddMissingColumns.php
new file mode 100644 (file)
index 0000000..4672770
--- /dev/null
@@ -0,0 +1,105 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020 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\Core\Command\Db;
+
+use OC\DB\SchemaWrapper;
+use OCP\IDBConnection;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\GenericEvent;
+
+/**
+ * Class AddMissingColumns
+ *
+ * if you added a new lazy column to the database, this is the right place to add
+ * your update routine for existing instances
+ *
+ * @package OC\Core\Command\Db
+ */
+class AddMissingColumns extends Command {
+
+       /** @var IDBConnection */
+       private $connection;
+
+       /** @var EventDispatcherInterface */
+       private $dispatcher;
+
+       public function __construct(IDBConnection $connection, EventDispatcherInterface $dispatcher) {
+               parent::__construct();
+
+               $this->connection = $connection;
+               $this->dispatcher = $dispatcher;
+       }
+
+       protected function configure() {
+               $this
+                       ->setName('db:add-missing-columns')
+                       ->setDescription('Add missing optional columns to the database tables');
+       }
+
+       protected function execute(InputInterface $input, OutputInterface $output) {
+               $this->addCoreColumns($output);
+
+               // Dispatch event so apps can also update columns if needed
+               $event = new GenericEvent($output);
+               $this->dispatcher->dispatch(IDBConnection::ADD_MISSING_COLUMNS_EVENT, $event);
+       }
+
+       /**
+        * add missing indices to the share table
+        *
+        * @param OutputInterface $output
+        * @throws \Doctrine\DBAL\Schema\SchemaException
+        */
+       private function addCoreColumns(OutputInterface $output) {
+
+               $output->writeln('<info>Check columns of the comments table.</info>');
+
+               $schema = new SchemaWrapper($this->connection);
+               $updated = false;
+
+               if ($schema->hasTable('comments')) {
+                       $table = $schema->getTable('comments');
+                       if (!$table->hasColumn('reference_id')) {
+                               $output->writeln('<info>Adding additional reference_id column to the comments table, this can take some time...</info>');
+                               $table->addColumn('reference_id', 'string', [
+                                       'notnull' => false,
+                                       'length' => 64,
+                               ]);
+                               $this->connection->migrateToSchema($schema->getWrappedSchema());
+                               $updated = true;
+                               $output->writeln('<info>Comments table updated successfully.</info>');
+                       }
+               }
+
+               if (!$updated) {
+                       $output->writeln('<info>Done.</info>');
+               }
+       }
+}
index 0152df21737554fb3d13e9f0554bce48bff8b4f6..c4006a2d7fa72839578bfdaa0540df7cf463a9ac 100644 (file)
@@ -43,7 +43,7 @@ use Symfony\Component\EventDispatcher\GenericEvent;
  * Class AddMissingIndices
  *
  * if you added any new indices to the database, this is the right place to add
- * it your update routine for existing instances
+ * your update routine for existing instances
  *
  * @package OC\Core\Command\Db
  */
index e9f376a7e424852ecdfa523eb1c929e310d083aa..757697e7e90a5ce9c198213866afc22cbd8a966b 100644 (file)
@@ -769,6 +769,10 @@ class Version13000Date20170718121200 extends SimpleMigrationStep {
                                'length' => 64,
                                'default' => '',
                        ]);
+                       $table->addColumn('reference_id', 'string', [
+                               'notnull' => false,
+                               'length' => 64,
+                       ]);
                        $table->setPrimaryKey(['id']);
                        $table->addIndex(['parent_id'], 'comments_parent_id_index');
                        $table->addIndex(['topmost_parent_id'], 'comments_topmost_parent_id_idx');
index 12d1104a6327b31c79073d7ef127b7705b5ad340..2e94c82486ceb335b61fa6f3c29b70f1a2234884 100644 (file)
                                                        type: OC.SetupChecks.MESSAGE_TYPE_INFO
                                                })
                                        }
+                                       if (data.missingColumns.length > 0) {
+                                               var listOfMissingColumns = "";
+                                               data.missingColumns.forEach(function(element){
+                                                       listOfMissingColumns += "<li>";
+                                                       listOfMissingColumns += t('core', 'Missing optional column "{columnName}" in table "{tableName}".', element);
+                                                       listOfMissingColumns += "</li>";
+                                               });
+                                               messages.push({
+                                                       msg: t(
+                                                               'core',
+                                                               'The database is missing some optional columns. Due to the fact that adding columns on big tables could take some time they were not added automatically when they can be optional. By running "occ db:add-missing-columns" those missing columns could be added manually while the instance keeps running. Once the columns are added some features might improve responsiveness or usability.'
+                                                       ) + "<ul>" + listOfMissingColumns + "</ul>",
+                                                       type: OC.SetupChecks.MESSAGE_TYPE_INFO
+                                               })
+                                       }
                                        if (data.recommendedPHPModules.length > 0) {
                                                var listOfRecommendedPHPModules = "";
                                                data.recommendedPHPModules.forEach(function(element){
index 5e93cbf7bdf868e9a70cb427e8efd3e3428e27d2..891b5fc84c896ea757da2795e4f1e039b7508c1d 100644 (file)
@@ -240,6 +240,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -293,6 +294,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -347,6 +349,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -399,6 +402,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -449,6 +453,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -499,6 +504,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -551,6 +557,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -601,6 +608,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: false,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -651,6 +659,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -722,6 +731,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -773,6 +783,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -824,6 +835,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -875,6 +887,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: false,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -925,6 +938,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
@@ -1026,6 +1040,7 @@ describe('OC.SetupChecks tests', function() {
                                        isSettimelimitAvailable: true,
                                        hasFreeTypeSupport: true,
                                        missingIndexes: [],
+                                       missingColumns: [],
                                        cronErrors: [],
                                        cronInfo: {
                                                diffInSeconds: 0
index efa3146c49223cad1f705766ce77dc163a4cf07a..e355d1429c1484221b234618bb959845ad697587 100644 (file)
@@ -99,6 +99,7 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) {
        $application->add(new OC\Core\Command\Db\ConvertMysqlToMB4(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection(), \OC::$server->getURLGenerator(), \OC::$server->getLogger()));
        $application->add(new OC\Core\Command\Db\ConvertFilecacheBigInt(\OC::$server->getDatabaseConnection()));
        $application->add(new OC\Core\Command\Db\AddMissingIndices(\OC::$server->getDatabaseConnection(), \OC::$server->getEventDispatcher()));
+       $application->add(new OC\Core\Command\Db\AddMissingColumns(\OC::$server->getDatabaseConnection(), \OC::$server->getEventDispatcher()));
        $application->add(new OC\Core\Command\Db\Migrations\StatusCommand(\OC::$server->getDatabaseConnection()));
        $application->add(new OC\Core\Command\Db\Migrations\MigrateCommand(\OC::$server->getDatabaseConnection()));
        $application->add(new OC\Core\Command\Db\Migrations\GenerateCommand(\OC::$server->getDatabaseConnection(), \OC::$server->getAppManager()));
diff --git a/lib/private/DB/MissingColumnInformation.php b/lib/private/DB/MissingColumnInformation.php
new file mode 100644 (file)
index 0000000..bcf5858
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020 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\DB;
+
+class MissingColumnInformation {
+
+       private $listOfMissingColumns = [];
+
+       public function addHintForMissingColumn(string $tableName, string $columnName): void {
+               $this->listOfMissingColumns[] = [
+                       'tableName' => $tableName,
+                       'columnName' => $columnName,
+               ];
+       }
+
+       public function getListOfMissingColumns(): array {
+               return $this->listOfMissingColumns;
+       }
+}
index 30010bb4cefa5dd4289170b38639d9b81c1ca1a0..eabd07e9a0375fe2c1f2181b810e40b61a7f9fa9 100644 (file)
@@ -50,6 +50,8 @@ interface IDBConnection {
 
        const ADD_MISSING_INDEXES_EVENT = self::class . '::ADD_MISSING_INDEXES';
        const CHECK_MISSING_INDEXES_EVENT = self::class . '::CHECK_MISSING_INDEXES';
+       const ADD_MISSING_COLUMNS_EVENT = self::class . '::ADD_MISSING_COLUMNS';
+       const CHECK_MISSING_COLUMNS_EVENT = self::class . '::CHECK_MISSING_COLUMNS';
 
        /**
         * Gets the QueryBuilder for the connection.