aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/Repair
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/Repair')
-rw-r--r--lib/private/Repair/AddCleanupDeletedUsersBackgroundJob.php30
-rw-r--r--lib/private/Repair/AddCleanupUpdaterBackupsJob.php1
-rw-r--r--lib/private/Repair/AddMetadataGenerationJob.php1
-rw-r--r--lib/private/Repair/CleanTags.php41
-rw-r--r--lib/private/Repair/ClearFrontendCaches.php1
-rw-r--r--lib/private/Repair/ClearGeneratedAvatarCache.php1
-rw-r--r--lib/private/Repair/ClearGeneratedAvatarCacheJob.php1
-rw-r--r--lib/private/Repair/Collation.php29
-rw-r--r--lib/private/Repair/ConfigKeyMigration.php29
-rw-r--r--lib/private/Repair/Events/RepairAdvanceEvent.php2
-rw-r--r--lib/private/Repair/Events/RepairErrorEvent.php2
-rw-r--r--lib/private/Repair/Events/RepairInfoEvent.php2
-rw-r--r--lib/private/Repair/Events/RepairStartEvent.php2
-rw-r--r--lib/private/Repair/Events/RepairStepEvent.php2
-rw-r--r--lib/private/Repair/Events/RepairWarningEvent.php2
-rw-r--r--lib/private/Repair/MoveUpdaterStepFile.php4
-rw-r--r--lib/private/Repair/NC11/FixMountStorages.php60
-rw-r--r--lib/private/Repair/NC13/AddLogRotateJob.php1
-rw-r--r--lib/private/Repair/NC16/CleanupCardDAVPhotoCache.php24
-rw-r--r--lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php1
-rw-r--r--lib/private/Repair/NC21/ValidatePhoneNumber.php70
-rw-r--r--lib/private/Repair/NC25/AddMissingSecretJob.php4
-rw-r--r--lib/private/Repair/NC29/SanitizeAccountProperties.php30
-rw-r--r--lib/private/Repair/NC29/SanitizeAccountPropertiesJob.php75
-rw-r--r--lib/private/Repair/NC30/RemoveLegacyDatadirFile.php32
-rw-r--r--lib/private/Repair/OldGroupMembershipShares.php25
-rw-r--r--lib/private/Repair/Owncloud/CleanPreviews.php1
-rw-r--r--lib/private/Repair/Owncloud/DropAccountTermsTable.php1
-rw-r--r--lib/private/Repair/Owncloud/MigrateOauthTables.php138
-rw-r--r--lib/private/Repair/Owncloud/MoveAvatars.php1
-rw-r--r--lib/private/Repair/Owncloud/SaveAccountsTableData.php3
-rw-r--r--lib/private/Repair/Owncloud/UpdateLanguageCodes.php1
-rw-r--r--lib/private/Repair/RemoveBrokenProperties.php68
-rw-r--r--lib/private/Repair/RemoveLinkShares.php40
-rw-r--r--lib/private/Repair/RepairDavShares.php20
-rw-r--r--lib/private/Repair/RepairInvalidShares.php29
-rw-r--r--lib/private/Repair/RepairLogoDimension.php82
-rw-r--r--lib/private/Repair/RepairMimeTypes.php285
38 files changed, 791 insertions, 350 deletions
diff --git a/lib/private/Repair/AddCleanupDeletedUsersBackgroundJob.php b/lib/private/Repair/AddCleanupDeletedUsersBackgroundJob.php
new file mode 100644
index 00000000000..9713d8595e7
--- /dev/null
+++ b/lib/private/Repair/AddCleanupDeletedUsersBackgroundJob.php
@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OC\Repair;
+
+use OC\User\BackgroundJobs\CleanupDeletedUsers;
+use OCP\BackgroundJob\IJobList;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class AddCleanupDeletedUsersBackgroundJob implements IRepairStep {
+ private IJobList $jobList;
+
+ public function __construct(IJobList $jobList) {
+ $this->jobList = $jobList;
+ }
+
+ public function getName(): string {
+ return 'Add cleanup-deleted-users background job';
+ }
+
+ public function run(IOutput $output) {
+ $this->jobList->add(CleanupDeletedUsers::class);
+ }
+}
diff --git a/lib/private/Repair/AddCleanupUpdaterBackupsJob.php b/lib/private/Repair/AddCleanupUpdaterBackupsJob.php
index 8bd938b7e3a..e631a3303f1 100644
--- a/lib/private/Repair/AddCleanupUpdaterBackupsJob.php
+++ b/lib/private/Repair/AddCleanupUpdaterBackupsJob.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/lib/private/Repair/AddMetadataGenerationJob.php b/lib/private/Repair/AddMetadataGenerationJob.php
index 4535fb0c9e0..76c60f303a7 100644
--- a/lib/private/Repair/AddMetadataGenerationJob.php
+++ b/lib/private/Repair/AddMetadataGenerationJob.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/lib/private/Repair/CleanTags.php b/lib/private/Repair/CleanTags.php
index f2fc8156f29..ad8fa6235e6 100644
--- a/lib/private/Repair/CleanTags.php
+++ b/lib/private/Repair/CleanTags.php
@@ -19,11 +19,6 @@ use OCP\Migration\IRepairStep;
* @package OC\Repair
*/
class CleanTags implements IRepairStep {
- /** @var IDBConnection */
- protected $connection;
-
- /** @var IUserManager */
- protected $userManager;
protected $deletedTags = 0;
@@ -31,9 +26,10 @@ class CleanTags implements IRepairStep {
* @param IDBConnection $connection
* @param IUserManager $userManager
*/
- public function __construct(IDBConnection $connection, IUserManager $userManager) {
- $this->connection = $connection;
- $this->userManager = $userManager;
+ public function __construct(
+ protected IDBConnection $connection,
+ protected IUserManager $userManager,
+ ) {
}
/**
@@ -73,7 +69,7 @@ class CleanTags implements IRepairStep {
->orderBy('uid')
->setMaxResults(50)
->setFirstResult($offset);
- $result = $query->execute();
+ $result = $query->executeQuery();
$users = [];
$hadResults = false;
@@ -94,7 +90,7 @@ class CleanTags implements IRepairStep {
$query = $this->connection->getQueryBuilder();
$query->delete('vcategory')
->where($query->expr()->in('uid', $query->createNamedParameter($users, IQueryBuilder::PARAM_STR_ARRAY)));
- $this->deletedTags += $query->execute();
+ $this->deletedTags += $query->executeStatement();
}
return true;
}
@@ -107,7 +103,7 @@ class CleanTags implements IRepairStep {
$output,
'%d tags for delete files have been removed.',
'vcategory_to_object', 'objid',
- 'filecache', 'fileid', 'path_hash'
+ 'filecache', 'fileid', 'fileid'
);
}
@@ -147,8 +143,8 @@ class CleanTags implements IRepairStep {
* @param string $deleteId
* @param string $sourceTable
* @param string $sourceId
- * @param string $sourceNullColumn If this column is null in the source table,
- * the entry is deleted in the $deleteTable
+ * @param string $sourceNullColumn If this column is null in the source table,
+ * the entry is deleted in the $deleteTable
*/
protected function deleteOrphanEntries(IOutput $output, $repairInfo, $deleteTable, $deleteId, $sourceTable, $sourceId, $sourceNullColumn) {
$qb = $this->connection->getQueryBuilder();
@@ -162,23 +158,24 @@ class CleanTags implements IRepairStep {
->andWhere(
$qb->expr()->isNull('s.' . $sourceNullColumn)
);
- $result = $qb->execute();
+ $result = $qb->executeQuery();
$orphanItems = [];
while ($row = $result->fetch()) {
- $orphanItems[] = (int) $row[$deleteId];
+ $orphanItems[] = (int)$row[$deleteId];
}
+ $deleteQuery = $this->connection->getQueryBuilder();
+ $deleteQuery->delete($deleteTable)
+ ->where(
+ $deleteQuery->expr()->eq('type', $deleteQuery->expr()->literal('files'))
+ )
+ ->andWhere($deleteQuery->expr()->in($deleteId, $deleteQuery->createParameter('ids')));
if (!empty($orphanItems)) {
$orphanItemsBatch = array_chunk($orphanItems, 200);
foreach ($orphanItemsBatch as $items) {
- $qb->delete($deleteTable)
- ->where(
- $qb->expr()->eq('type', $qb->expr()->literal('files'))
- )
- ->andWhere($qb->expr()->in($deleteId, $qb->createParameter('ids')));
- $qb->setParameter('ids', $items, IQueryBuilder::PARAM_INT_ARRAY);
- $qb->execute();
+ $deleteQuery->setParameter('ids', $items, IQueryBuilder::PARAM_INT_ARRAY);
+ $deleteQuery->executeStatement();
}
}
diff --git a/lib/private/Repair/ClearFrontendCaches.php b/lib/private/Repair/ClearFrontendCaches.php
index 77a3df5598a..5c57a63379d 100644
--- a/lib/private/Repair/ClearFrontendCaches.php
+++ b/lib/private/Repair/ClearFrontendCaches.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/lib/private/Repair/ClearGeneratedAvatarCache.php b/lib/private/Repair/ClearGeneratedAvatarCache.php
index 2dea4bd2d61..0f743afbb4c 100644
--- a/lib/private/Repair/ClearGeneratedAvatarCache.php
+++ b/lib/private/Repair/ClearGeneratedAvatarCache.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/lib/private/Repair/ClearGeneratedAvatarCacheJob.php b/lib/private/Repair/ClearGeneratedAvatarCacheJob.php
index 38cf03b731a..524a470e62a 100644
--- a/lib/private/Repair/ClearGeneratedAvatarCacheJob.php
+++ b/lib/private/Repair/ClearGeneratedAvatarCacheJob.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/lib/private/Repair/Collation.php b/lib/private/Repair/Collation.php
index 0affb3b1ca9..43229792217 100644
--- a/lib/private/Repair/Collation.php
+++ b/lib/private/Repair/Collation.php
@@ -8,7 +8,6 @@
namespace OC\Repair;
use Doctrine\DBAL\Exception\DriverException;
-use Doctrine\DBAL\Platforms\MySQLPlatform;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\Migration\IOutput;
@@ -16,7 +15,7 @@ use OCP\Migration\IRepairStep;
use Psr\Log\LoggerInterface;
class Collation implements IRepairStep {
- /** @var IConfig */
+ /** @var IConfig */
protected $config;
protected LoggerInterface $logger;
@@ -34,7 +33,7 @@ class Collation implements IRepairStep {
IConfig $config,
LoggerInterface $logger,
IDBConnection $connection,
- $ignoreFailures
+ $ignoreFailures,
) {
$this->connection = $connection;
$this->config = $config;
@@ -50,7 +49,7 @@ class Collation implements IRepairStep {
* Fix mime types
*/
public function run(IOutput $output) {
- if (!$this->connection->getDatabasePlatform() instanceof MySQLPlatform) {
+ if ($this->connection->getDatabaseProvider() !== IDBConnection::PLATFORM_MYSQL) {
$output->info('Not a mysql database -> nothing to do');
return;
}
@@ -93,16 +92,16 @@ class Collation implements IRepairStep {
* @return string[]
*/
protected function getAllNonUTF8BinTables(IDBConnection $connection) {
- $dbName = $this->config->getSystemValueString("dbname");
+ $dbName = $this->config->getSystemValueString('dbname');
$characterSet = $this->config->getSystemValueBool('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
// fetch tables by columns
$statement = $connection->executeQuery(
- "SELECT DISTINCT(TABLE_NAME) AS `table`" .
- " FROM INFORMATION_SCHEMA . COLUMNS" .
- " WHERE TABLE_SCHEMA = ?" .
- " AND (COLLATION_NAME <> '" . $characterSet . "_bin' OR CHARACTER_SET_NAME <> '" . $characterSet . "')" .
- " AND TABLE_NAME LIKE '*PREFIX*%'",
+ 'SELECT DISTINCT(TABLE_NAME) AS `table`'
+ . ' FROM INFORMATION_SCHEMA . COLUMNS'
+ . ' WHERE TABLE_SCHEMA = ?'
+ . " AND (COLLATION_NAME <> '" . $characterSet . "_bin' OR CHARACTER_SET_NAME <> '" . $characterSet . "')"
+ . " AND TABLE_NAME LIKE '*PREFIX*%'",
[$dbName]
);
$rows = $statement->fetchAll();
@@ -113,11 +112,11 @@ class Collation implements IRepairStep {
// fetch tables by collation
$statement = $connection->executeQuery(
- "SELECT DISTINCT(TABLE_NAME) AS `table`" .
- " FROM INFORMATION_SCHEMA . TABLES" .
- " WHERE TABLE_SCHEMA = ?" .
- " AND TABLE_COLLATION <> '" . $characterSet . "_bin'" .
- " AND TABLE_NAME LIKE '*PREFIX*%'",
+ 'SELECT DISTINCT(TABLE_NAME) AS `table`'
+ . ' FROM INFORMATION_SCHEMA . TABLES'
+ . ' WHERE TABLE_SCHEMA = ?'
+ . " AND TABLE_COLLATION <> '" . $characterSet . "_bin'"
+ . " AND TABLE_NAME LIKE '*PREFIX*%'",
[$dbName]
);
$rows = $statement->fetchAll();
diff --git a/lib/private/Repair/ConfigKeyMigration.php b/lib/private/Repair/ConfigKeyMigration.php
new file mode 100644
index 00000000000..da4aa153dc5
--- /dev/null
+++ b/lib/private/Repair/ConfigKeyMigration.php
@@ -0,0 +1,29 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\Repair;
+
+use OC\Config\ConfigManager;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class ConfigKeyMigration implements IRepairStep {
+ public function __construct(
+ private ConfigManager $configManager,
+ ) {
+ }
+
+ public function getName(): string {
+ return 'Migrate config keys';
+ }
+
+ public function run(IOutput $output) {
+ $this->configManager->migrateConfigLexiconKeys();
+ }
+}
diff --git a/lib/private/Repair/Events/RepairAdvanceEvent.php b/lib/private/Repair/Events/RepairAdvanceEvent.php
index c4be72ce530..476db9e4702 100644
--- a/lib/private/Repair/Events/RepairAdvanceEvent.php
+++ b/lib/private/Repair/Events/RepairAdvanceEvent.php
@@ -16,7 +16,7 @@ class RepairAdvanceEvent extends Event {
public function __construct(
int $increment,
- string $description
+ string $description,
) {
$this->increment = $increment;
$this->description = $description;
diff --git a/lib/private/Repair/Events/RepairErrorEvent.php b/lib/private/Repair/Events/RepairErrorEvent.php
index 8cd5d41b1b4..e5be8a5a031 100644
--- a/lib/private/Repair/Events/RepairErrorEvent.php
+++ b/lib/private/Repair/Events/RepairErrorEvent.php
@@ -14,7 +14,7 @@ class RepairErrorEvent extends Event {
private string $message;
public function __construct(
- string $message
+ string $message,
) {
$this->message = $message;
}
diff --git a/lib/private/Repair/Events/RepairInfoEvent.php b/lib/private/Repair/Events/RepairInfoEvent.php
index c48b295a9a9..ce8eb2f99e6 100644
--- a/lib/private/Repair/Events/RepairInfoEvent.php
+++ b/lib/private/Repair/Events/RepairInfoEvent.php
@@ -14,7 +14,7 @@ class RepairInfoEvent extends Event {
private string $message;
public function __construct(
- string $message
+ string $message,
) {
$this->message = $message;
}
diff --git a/lib/private/Repair/Events/RepairStartEvent.php b/lib/private/Repair/Events/RepairStartEvent.php
index e154df5e6e1..47e713d57d9 100644
--- a/lib/private/Repair/Events/RepairStartEvent.php
+++ b/lib/private/Repair/Events/RepairStartEvent.php
@@ -16,7 +16,7 @@ class RepairStartEvent extends Event {
public function __construct(
int $max,
- string $current
+ string $current,
) {
$this->max = $max;
$this->current = $current;
diff --git a/lib/private/Repair/Events/RepairStepEvent.php b/lib/private/Repair/Events/RepairStepEvent.php
index 7140d13687d..27e1efbdb08 100644
--- a/lib/private/Repair/Events/RepairStepEvent.php
+++ b/lib/private/Repair/Events/RepairStepEvent.php
@@ -14,7 +14,7 @@ class RepairStepEvent extends Event {
private string $stepName;
public function __construct(
- string $stepName
+ string $stepName,
) {
$this->stepName = $stepName;
}
diff --git a/lib/private/Repair/Events/RepairWarningEvent.php b/lib/private/Repair/Events/RepairWarningEvent.php
index 403eec87158..6893a7212ec 100644
--- a/lib/private/Repair/Events/RepairWarningEvent.php
+++ b/lib/private/Repair/Events/RepairWarningEvent.php
@@ -14,7 +14,7 @@ class RepairWarningEvent extends Event {
private string $message;
public function __construct(
- string $message
+ string $message,
) {
$this->message = $message;
}
diff --git a/lib/private/Repair/MoveUpdaterStepFile.php b/lib/private/Repair/MoveUpdaterStepFile.php
index c9b51b308c4..bb8f9d3acfc 100644
--- a/lib/private/Repair/MoveUpdaterStepFile.php
+++ b/lib/private/Repair/MoveUpdaterStepFile.php
@@ -1,10 +1,12 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Repair;
+use OCP\Files;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
@@ -40,7 +42,7 @@ class MoveUpdaterStepFile implements IRepairStep {
// cleanup
if (file_exists($previousStepFile)) {
- if (\OC_Helper::rmdirr($previousStepFile)) {
+ if (Files::rmdirr($previousStepFile)) {
$output->info('.step-previous-update removed');
} else {
$output->info('.step-previous-update can\'t be removed - abort move of .step file');
diff --git a/lib/private/Repair/NC11/FixMountStorages.php b/lib/private/Repair/NC11/FixMountStorages.php
deleted file mode 100644
index b1663102d2f..00000000000
--- a/lib/private/Repair/NC11/FixMountStorages.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-/**
- * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-namespace OC\Repair\NC11;
-
-use OCP\DB\QueryBuilder\IQueryBuilder;
-use OCP\IDBConnection;
-use OCP\Migration\IOutput;
-use OCP\Migration\IRepairStep;
-
-class FixMountStorages implements IRepairStep {
- /** @var IDBConnection */
- private $db;
-
- /**
- * @param IDBConnection $db
- */
- public function __construct(IDBConnection $db) {
- $this->db = $db;
- }
-
- /**
- * @return string
- */
- public function getName() {
- return 'Fix potential broken mount points';
- }
-
- public function run(IOutput $output) {
- $query = $this->db->getQueryBuilder();
- $query->select('m.id', 'f.storage')
- ->from('mounts', 'm')
- ->leftJoin('m', 'filecache', 'f', $query->expr()->eq('m.root_id', 'f.fileid'))
- ->where($query->expr()->neq('m.storage_id', 'f.storage'));
-
- $update = $this->db->getQueryBuilder();
- $update->update('mounts')
- ->set('storage_id', $update->createParameter('storage'))
- ->where($query->expr()->eq('id', $update->createParameter('mount')));
-
- $result = $query->execute();
- $entriesUpdated = 0;
- while ($row = $result->fetch()) {
- $update->setParameter('storage', $row['storage'], IQueryBuilder::PARAM_INT)
- ->setParameter('mount', $row['id'], IQueryBuilder::PARAM_INT);
- $update->execute();
- $entriesUpdated++;
- }
- $result->closeCursor();
-
- if ($entriesUpdated > 0) {
- $output->info($entriesUpdated . ' mounts updated');
- return;
- }
-
- $output->info('No mounts updated');
- }
-}
diff --git a/lib/private/Repair/NC13/AddLogRotateJob.php b/lib/private/Repair/NC13/AddLogRotateJob.php
index 8fe68a42819..bd6c510785f 100644
--- a/lib/private/Repair/NC13/AddLogRotateJob.php
+++ b/lib/private/Repair/NC13/AddLogRotateJob.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/lib/private/Repair/NC16/CleanupCardDAVPhotoCache.php b/lib/private/Repair/NC16/CleanupCardDAVPhotoCache.php
index a9cbbb4cbbf..646dd2c5e83 100644
--- a/lib/private/Repair/NC16/CleanupCardDAVPhotoCache.php
+++ b/lib/private/Repair/NC16/CleanupCardDAVPhotoCache.php
@@ -6,9 +6,10 @@ declare(strict_types=1);
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
+
namespace OC\Repair\NC16;
-use OCP\Files\IAppData;
+use OCP\Files\AppData\IAppDataFactory;
use OCP\Files\NotFoundException;
use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\IConfig;
@@ -27,18 +28,11 @@ use RuntimeException;
* photo could be returned for this vcard. These invalid files are removed by this migration step.
*/
class CleanupCardDAVPhotoCache implements IRepairStep {
- /** @var IConfig */
- private $config;
-
- /** @var IAppData */
- private $appData;
-
- private LoggerInterface $logger;
-
- public function __construct(IConfig $config, IAppData $appData, LoggerInterface $logger) {
- $this->config = $config;
- $this->appData = $appData;
- $this->logger = $logger;
+ public function __construct(
+ private IConfig $config,
+ private IAppDataFactory $appDataFactory,
+ private LoggerInterface $logger,
+ ) {
}
public function getName(): string {
@@ -46,8 +40,10 @@ class CleanupCardDAVPhotoCache implements IRepairStep {
}
private function repair(IOutput $output): void {
+ $photoCacheAppData = $this->appDataFactory->get('dav-photocache');
+
try {
- $folders = $this->appData->getDirectoryListing();
+ $folders = $photoCacheAppData->getDirectoryListing();
} catch (NotFoundException $e) {
return;
} catch (RuntimeException $e) {
diff --git a/lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php b/lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php
index 4f80b3809e8..5cee33b381c 100644
--- a/lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php
+++ b/lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/lib/private/Repair/NC21/ValidatePhoneNumber.php b/lib/private/Repair/NC21/ValidatePhoneNumber.php
deleted file mode 100644
index 3a6ace37bd2..00000000000
--- a/lib/private/Repair/NC21/ValidatePhoneNumber.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-namespace OC\Repair\NC21;
-
-use OCP\Accounts\IAccountManager;
-use OCP\IConfig;
-use OCP\IUser;
-use OCP\IUserManager;
-use OCP\Migration\IOutput;
-use OCP\Migration\IRepairStep;
-
-class ValidatePhoneNumber implements IRepairStep {
- /** @var IConfig */
- protected $config;
- /** @var IUserManager */
- protected $userManager;
- /** @var IAccountManager */
- private $accountManager;
-
- public function __construct(IUserManager $userManager,
- IAccountManager $accountManager,
- IConfig $config) {
- $this->config = $config;
- $this->userManager = $userManager;
- $this->accountManager = $accountManager;
- }
-
- public function getName(): string {
- return 'Validate the phone number and store it in a known format for search';
- }
-
- public function run(IOutput $output): void {
- if ($this->config->getSystemValueString('default_phone_region', '') === '') {
- $output->warning('Can not validate phone numbers without `default_phone_region` being set in the config file');
- return;
- }
-
- $numUpdated = 0;
- $numRemoved = 0;
-
- $this->userManager->callForSeenUsers(function (IUser $user) use (&$numUpdated, &$numRemoved) {
- $account = $this->accountManager->getAccount($user);
- $property = $account->getProperty(IAccountManager::PROPERTY_PHONE);
-
- if ($property->getValue() !== '') {
- $this->accountManager->updateAccount($account);
- $updatedAccount = $this->accountManager->getAccount($user);
- $updatedProperty = $updatedAccount->getProperty(IAccountManager::PROPERTY_PHONE);
-
- if ($property->getValue() !== $updatedProperty->getValue()) {
- if ($updatedProperty->getValue() === '') {
- $numRemoved++;
- } else {
- $numUpdated++;
- }
- }
- }
- });
-
- if ($numRemoved > 0 || $numUpdated > 0) {
- $output->info('Updated ' . $numUpdated . ' entries and cleaned ' . $numRemoved . ' invalid phone numbers');
- }
- }
-}
diff --git a/lib/private/Repair/NC25/AddMissingSecretJob.php b/lib/private/Repair/NC25/AddMissingSecretJob.php
index b407ef2a2a9..46b89d5f6f7 100644
--- a/lib/private/Repair/NC25/AddMissingSecretJob.php
+++ b/lib/private/Repair/NC25/AddMissingSecretJob.php
@@ -33,7 +33,7 @@ class AddMissingSecretJob implements IRepairStep {
try {
$this->config->setSystemValue('passwordsalt', $this->random->generate(30));
} catch (HintException $e) {
- $output->warning("passwordsalt is missing from your config.php and your config.php is read only. Please fix it manually.");
+ $output->warning('passwordsalt is missing from your config.php and your config.php is read only. Please fix it manually.');
}
}
@@ -42,7 +42,7 @@ class AddMissingSecretJob implements IRepairStep {
try {
$this->config->setSystemValue('secret', $this->random->generate(48));
} catch (HintException $e) {
- $output->warning("secret is missing from your config.php and your config.php is read only. Please fix it manually.");
+ $output->warning('secret is missing from your config.php and your config.php is read only. Please fix it manually.');
}
}
}
diff --git a/lib/private/Repair/NC29/SanitizeAccountProperties.php b/lib/private/Repair/NC29/SanitizeAccountProperties.php
new file mode 100644
index 00000000000..412570ba71d
--- /dev/null
+++ b/lib/private/Repair/NC29/SanitizeAccountProperties.php
@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OC\Repair\NC29;
+
+use OCP\BackgroundJob\IJobList;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class SanitizeAccountProperties implements IRepairStep {
+
+ public function __construct(
+ private IJobList $jobList,
+ ) {
+ }
+
+ public function getName(): string {
+ return 'Validate account properties and store phone numbers in a known format for search';
+ }
+
+ public function run(IOutput $output): void {
+ $this->jobList->add(SanitizeAccountPropertiesJob::class, null);
+ $output->info('Queued background to validate account properties.');
+ }
+}
diff --git a/lib/private/Repair/NC29/SanitizeAccountPropertiesJob.php b/lib/private/Repair/NC29/SanitizeAccountPropertiesJob.php
new file mode 100644
index 00000000000..55ec445e9da
--- /dev/null
+++ b/lib/private/Repair/NC29/SanitizeAccountPropertiesJob.php
@@ -0,0 +1,75 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OC\Repair\NC29;
+
+use InvalidArgumentException;
+use OCP\Accounts\IAccountManager;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\QueuedJob;
+use OCP\IUser;
+use OCP\IUserManager;
+use Psr\Log\LoggerInterface;
+
+class SanitizeAccountPropertiesJob extends QueuedJob {
+
+ private const PROPERTIES_TO_CHECK = [
+ IAccountManager::PROPERTY_PHONE,
+ IAccountManager::PROPERTY_WEBSITE,
+ IAccountManager::PROPERTY_TWITTER,
+ IAccountManager::PROPERTY_FEDIVERSE,
+ ];
+
+ public function __construct(
+ ITimeFactory $timeFactory,
+ private IUserManager $userManager,
+ private IAccountManager $accountManager,
+ private LoggerInterface $logger,
+ ) {
+ parent::__construct($timeFactory);
+ $this->setAllowParallelRuns(false);
+ }
+
+ protected function run(mixed $argument): void {
+ $numRemoved = 0;
+
+ $this->userManager->callForSeenUsers(function (IUser $user) use (&$numRemoved) {
+ $account = $this->accountManager->getAccount($user);
+ $properties = array_keys($account->jsonSerialize());
+
+ // Check if there are some properties we can sanitize - reduces number of db queries
+ if (empty(array_intersect($properties, self::PROPERTIES_TO_CHECK))) {
+ return;
+ }
+
+ // Limit the loop to the properties we check to ensure there are no infinite loops
+ // we add one additional loop (+ 1) as we need 1 loop for checking + 1 for update.
+ $iteration = count(self::PROPERTIES_TO_CHECK) + 1;
+ while ($iteration-- > 0) {
+ try {
+ $this->accountManager->updateAccount($account);
+ return;
+ } catch (InvalidArgumentException $e) {
+ if (in_array($e->getMessage(), IAccountManager::ALLOWED_PROPERTIES)) {
+ $numRemoved++;
+ $property = $account->getProperty($e->getMessage());
+ $account->setProperty($property->getName(), '', $property->getScope(), IAccountManager::NOT_VERIFIED);
+ } else {
+ $this->logger->error('Error while sanitizing account property', ['exception' => $e, 'user' => $user->getUID()]);
+ return;
+ }
+ }
+ }
+ $this->logger->error('Iteration limit exceeded while cleaning account properties', ['user' => $user->getUID()]);
+ });
+
+ if ($numRemoved > 0) {
+ $this->logger->info('Cleaned ' . $numRemoved . ' invalid account property entries');
+ }
+ }
+}
diff --git a/lib/private/Repair/NC30/RemoveLegacyDatadirFile.php b/lib/private/Repair/NC30/RemoveLegacyDatadirFile.php
new file mode 100644
index 00000000000..623163927bd
--- /dev/null
+++ b/lib/private/Repair/NC30/RemoveLegacyDatadirFile.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OC\Repair\NC30;
+
+use OCP\IConfig;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class RemoveLegacyDatadirFile implements IRepairStep {
+
+ public function __construct(
+ private IConfig $config,
+ ) {
+ }
+
+ public function getName(): string {
+ return 'Remove legacy ".ocdata" file';
+ }
+
+ public function run(IOutput $output): void {
+ $ocdata = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata';
+ if (file_exists($ocdata)) {
+ unlink($ocdata);
+ }
+ }
+}
diff --git a/lib/private/Repair/OldGroupMembershipShares.php b/lib/private/Repair/OldGroupMembershipShares.php
index 54f2078395e..003c15cfb88 100644
--- a/lib/private/Repair/OldGroupMembershipShares.php
+++ b/lib/private/Repair/OldGroupMembershipShares.php
@@ -14,12 +14,6 @@ use OCP\Migration\IRepairStep;
use OCP\Share\IShare;
class OldGroupMembershipShares implements IRepairStep {
- /** @var \OCP\IDBConnection */
- protected $connection;
-
- /** @var \OCP\IGroupManager */
- protected $groupManager;
-
/**
* @var array [gid => [uid => (bool)]]
*/
@@ -29,9 +23,10 @@ class OldGroupMembershipShares implements IRepairStep {
* @param IDBConnection $connection
* @param IGroupManager $groupManager
*/
- public function __construct(IDBConnection $connection, IGroupManager $groupManager) {
- $this->connection = $connection;
- $this->groupManager = $groupManager;
+ public function __construct(
+ protected IDBConnection $connection,
+ protected IGroupManager $groupManager,
+ ) {
}
/**
@@ -57,20 +52,20 @@ class OldGroupMembershipShares implements IRepairStep {
->from('share', 's1')
->where($query->expr()->isNotNull('s1.parent'))
// \OC\Share\Constant::$shareTypeGroupUserUnique === 2
- ->andWhere($query->expr()->eq('s1.share_type', $query->expr()->literal(2)))
- ->andWhere($query->expr()->isNotNull('s2.id'))
- ->andWhere($query->expr()->eq('s2.share_type', $query->expr()->literal(IShare::TYPE_GROUP)))
+ ->andWhere($query->expr()->eq('s1.share_type', $query->expr()->literal(2)))
+ ->andWhere($query->expr()->isNotNull('s2.id'))
+ ->andWhere($query->expr()->eq('s2.share_type', $query->expr()->literal(IShare::TYPE_GROUP)))
->leftJoin('s1', 'share', 's2', $query->expr()->eq('s1.parent', 's2.id'));
$deleteQuery = $this->connection->getQueryBuilder();
$deleteQuery->delete('share')
->where($query->expr()->eq('id', $deleteQuery->createParameter('share')));
- $result = $query->execute();
+ $result = $query->executeQuery();
while ($row = $result->fetch()) {
if (!$this->isMember($row['group'], $row['user'])) {
- $deletedEntries += $deleteQuery->setParameter('share', (int) $row['id'])
- ->execute();
+ $deletedEntries += $deleteQuery->setParameter('share', (int)$row['id'])
+ ->executeStatement();
}
}
$result->closeCursor();
diff --git a/lib/private/Repair/Owncloud/CleanPreviews.php b/lib/private/Repair/Owncloud/CleanPreviews.php
index 86e173cf402..50ee965e087 100644
--- a/lib/private/Repair/Owncloud/CleanPreviews.php
+++ b/lib/private/Repair/Owncloud/CleanPreviews.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/lib/private/Repair/Owncloud/DropAccountTermsTable.php b/lib/private/Repair/Owncloud/DropAccountTermsTable.php
index 18f169c9b49..534825c146a 100644
--- a/lib/private/Repair/Owncloud/DropAccountTermsTable.php
+++ b/lib/private/Repair/Owncloud/DropAccountTermsTable.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/lib/private/Repair/Owncloud/MigrateOauthTables.php b/lib/private/Repair/Owncloud/MigrateOauthTables.php
index e8728cd2f66..de26a907e02 100644
--- a/lib/private/Repair/Owncloud/MigrateOauthTables.php
+++ b/lib/private/Repair/Owncloud/MigrateOauthTables.php
@@ -1,25 +1,37 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
+
namespace OC\Repair\Owncloud;
+use OC\Authentication\Token\IProvider as ITokenProvider;
use OC\DB\Connection;
use OC\DB\SchemaWrapper;
+use OCA\OAuth2\Db\AccessToken;
+use OCA\OAuth2\Db\AccessTokenMapper;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Authentication\Token\IToken;
use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IConfig;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
+use OCP\Security\ICrypto;
+use OCP\Security\ISecureRandom;
class MigrateOauthTables implements IRepairStep {
- /** @var Connection */
- protected $db;
- /**
- * @param Connection $db
- */
- public function __construct(Connection $db) {
- $this->db = $db;
+ public function __construct(
+ protected Connection $db,
+ private AccessTokenMapper $accessTokenMapper,
+ private ITokenProvider $tokenProvider,
+ private ISecureRandom $random,
+ private ITimeFactory $timeFactory,
+ private ICrypto $crypto,
+ private IConfig $config,
+ ) {
}
/**
@@ -32,19 +44,27 @@ class MigrateOauthTables implements IRepairStep {
public function run(IOutput $output) {
$schema = new SchemaWrapper($this->db);
if (!$schema->hasTable('oauth2_clients')) {
- $output->info("oauth2_clients table does not exist.");
+ $output->info('oauth2_clients table does not exist.');
return;
}
- $output->info("Update the oauth2_access_tokens table schema.");
- $schema = new SchemaWrapper($this->db);
+ // Create column and then migrate before handling unique index.
+ // So that we can distinguish between legacy (from oc) and new rows (from nc).
$table = $schema->getTable('oauth2_access_tokens');
if (!$table->hasColumn('hashed_code')) {
+ $output->info('Prepare the oauth2_access_tokens table schema.');
$table->addColumn('hashed_code', 'string', [
'notnull' => true,
'length' => 128,
]);
+
+ // Regenerate schema after migrating to it
+ $this->db->migrateToSchema($schema->getWrappedSchema());
+ $schema = new SchemaWrapper($this->db);
}
+
+ $output->info('Update the oauth2_access_tokens table schema.');
+ $table = $schema->getTable('oauth2_access_tokens');
if (!$table->hasColumn('encrypted_token')) {
$table->addColumn('encrypted_token', 'string', [
'notnull' => true,
@@ -52,14 +72,33 @@ class MigrateOauthTables implements IRepairStep {
]);
}
if (!$table->hasIndex('oauth2_access_hash_idx')) {
+ // Drop legacy access codes first to prevent integrity constraint violations
+ $qb = $this->db->getQueryBuilder();
+ $qb->delete('oauth2_access_tokens')
+ ->where($qb->expr()->eq('hashed_code', $qb->createNamedParameter('')));
+ $qb->executeStatement();
+
$table->addUniqueIndex(['hashed_code'], 'oauth2_access_hash_idx');
}
if (!$table->hasIndex('oauth2_access_client_id_idx')) {
$table->addIndex(['client_id'], 'oauth2_access_client_id_idx');
}
+ if (!$table->hasColumn('token_id')) {
+ $table->addColumn('token_id', 'integer', [
+ 'notnull' => true,
+ ]);
+ }
+ if ($table->hasColumn('expires')) {
+ $table->dropColumn('expires');
+ }
+ if ($table->hasColumn('user_id')) {
+ $table->dropColumn('user_id');
+ }
+ if ($table->hasColumn('token')) {
+ $table->dropColumn('token');
+ }
- $output->info("Update the oauth2_clients table schema.");
- $schema = new SchemaWrapper($this->db);
+ $output->info('Update the oauth2_clients table schema.');
$table = $schema->getTable('oauth2_clients');
if ($table->getColumn('name')->getLength() !== 64) {
// shorten existing values before resizing the column
@@ -101,8 +140,9 @@ class MigrateOauthTables implements IRepairStep {
$table->addIndex(['client_identifier'], 'oauth2_client_id_idx');
}
+ // Regenerate schema after migrating to it
$this->db->migrateToSchema($schema->getWrappedSchema());
-
+ $schema = new SchemaWrapper($this->db);
if ($schema->getTable('oauth2_clients')->hasColumn('identifier')) {
$output->info("Move identifier column's data to the new client_identifier column.");
@@ -114,7 +154,7 @@ class MigrateOauthTables implements IRepairStep {
$result->closeCursor();
// 2. Insert them into the client_identifier column.
- foreach ($identifiers as ["id" => $id, "identifier" => $clientIdentifier]) {
+ foreach ($identifiers as ['id' => $id, 'identifier' => $clientIdentifier]) {
$insertQuery = $this->db->getQueryBuilder();
$insertQuery->update('oauth2_clients')
->set('client_identifier', $insertQuery->createNamedParameter($clientIdentifier, IQueryBuilder::PARAM_STR))
@@ -122,14 +162,21 @@ class MigrateOauthTables implements IRepairStep {
->executeStatement();
}
- $output->info("Drop the identifier column.");
- $schema = new SchemaWrapper($this->db);
+ $output->info('Drop the identifier column.');
$table = $schema->getTable('oauth2_clients');
$table->dropColumn('identifier');
+
+ // Regenerate schema after migrating to it
$this->db->migrateToSchema($schema->getWrappedSchema());
+ $schema = new SchemaWrapper($this->db);
}
- $output->info('Delete clients (and their related access tokens) with the redirect_uri starting with oc:// or ending with *');
+ $enableOcClients = $this->config->getSystemValueBool('oauth2.enable_oc_clients', false);
+ if ($enableOcClients) {
+ $output->info('Delete clients (and their related access tokens) with the redirect_uri starting with oc://');
+ } else {
+ $output->info('Delete clients (and their related access tokens) with the redirect_uri starting with oc:// or ending with *');
+ }
// delete the access tokens
$qbDeleteAccessTokens = $this->db->getQueryBuilder();
@@ -138,10 +185,12 @@ class MigrateOauthTables implements IRepairStep {
->from('oauth2_clients')
->where(
$qbSelectClientId->expr()->iLike('redirect_uri', $qbDeleteAccessTokens->createNamedParameter('oc://%', IQueryBuilder::PARAM_STR))
- )
- ->orWhere(
+ );
+ if (!$enableOcClients) {
+ $qbSelectClientId->orWhere(
$qbSelectClientId->expr()->iLike('redirect_uri', $qbDeleteAccessTokens->createNamedParameter('%*', IQueryBuilder::PARAM_STR))
);
+ }
$qbDeleteAccessTokens->delete('oauth2_access_tokens')
->where(
@@ -154,10 +203,57 @@ class MigrateOauthTables implements IRepairStep {
$qbDeleteClients->delete('oauth2_clients')
->where(
$qbDeleteClients->expr()->iLike('redirect_uri', $qbDeleteClients->createNamedParameter('oc://%', IQueryBuilder::PARAM_STR))
- )
- ->orWhere(
+ );
+ if (!$enableOcClients) {
+ $qbDeleteClients->orWhere(
$qbDeleteClients->expr()->iLike('redirect_uri', $qbDeleteClients->createNamedParameter('%*', IQueryBuilder::PARAM_STR))
);
+ }
$qbDeleteClients->executeStatement();
+
+ // Migrate legacy refresh tokens from oc
+ if ($schema->hasTable('oauth2_refresh_tokens')) {
+ $output->info('Migrate legacy oauth2 refresh tokens.');
+
+ $qbSelect = $this->db->getQueryBuilder();
+ $qbSelect->select('*')
+ ->from('oauth2_refresh_tokens');
+ $result = $qbSelect->executeQuery();
+ $now = $this->timeFactory->now()->getTimestamp();
+ $index = 0;
+ while ($row = $result->fetch()) {
+ $clientId = $row['client_id'];
+ $refreshToken = $row['token'];
+
+ // Insert expired token so that it can be rotated on the next refresh
+ $accessToken = $this->random->generate(72, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS);
+ $authToken = $this->tokenProvider->generateToken(
+ $accessToken,
+ $row['user_id'],
+ $row['user_id'],
+ null,
+ "oc_migrated_client{$clientId}_t{$now}_i$index",
+ IToken::PERMANENT_TOKEN,
+ IToken::DO_NOT_REMEMBER,
+ );
+ $authToken->setExpires($now - 3600);
+ $this->tokenProvider->updateToken($authToken);
+
+ $accessTokenEntity = new AccessToken();
+ $accessTokenEntity->setTokenId($authToken->getId());
+ $accessTokenEntity->setClientId($clientId);
+ $accessTokenEntity->setHashedCode(hash('sha512', $refreshToken));
+ $accessTokenEntity->setEncryptedToken($this->crypto->encrypt($accessToken, $refreshToken));
+ $accessTokenEntity->setCodeCreatedAt($now);
+ $accessTokenEntity->setTokenCount(1);
+ $this->accessTokenMapper->insert($accessTokenEntity);
+
+ $index++;
+ }
+ $result->closeCursor();
+
+ $schema->dropTable('oauth2_refresh_tokens');
+ $schema->performDropTableCalls();
+ }
}
}
diff --git a/lib/private/Repair/Owncloud/MoveAvatars.php b/lib/private/Repair/Owncloud/MoveAvatars.php
index 7fdabae7a66..9e3f4b89b13 100644
--- a/lib/private/Repair/Owncloud/MoveAvatars.php
+++ b/lib/private/Repair/Owncloud/MoveAvatars.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/lib/private/Repair/Owncloud/SaveAccountsTableData.php b/lib/private/Repair/Owncloud/SaveAccountsTableData.php
index 1b6da7c858f..ab1560ddb8d 100644
--- a/lib/private/Repair/Owncloud/SaveAccountsTableData.php
+++ b/lib/private/Repair/Owncloud/SaveAccountsTableData.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -150,7 +151,7 @@ class SaveAccountsTableData implements IRepairStep {
* @throws \UnexpectedValueException
*/
protected function migrateUserInfo(IQueryBuilder $update, $userdata) {
- $state = (int) $userdata['state'];
+ $state = (int)$userdata['state'];
if ($state === 3) {
// Deleted user, ignore
return;
diff --git a/lib/private/Repair/Owncloud/UpdateLanguageCodes.php b/lib/private/Repair/Owncloud/UpdateLanguageCodes.php
index e27ab06b2f3..8d9046ad49f 100644
--- a/lib/private/Repair/Owncloud/UpdateLanguageCodes.php
+++ b/lib/private/Repair/Owncloud/UpdateLanguageCodes.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/lib/private/Repair/RemoveBrokenProperties.php b/lib/private/Repair/RemoveBrokenProperties.php
new file mode 100644
index 00000000000..85939b39e5e
--- /dev/null
+++ b/lib/private/Repair/RemoveBrokenProperties.php
@@ -0,0 +1,68 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OC\Repair;
+
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class RemoveBrokenProperties implements IRepairStep {
+ /**
+ * RemoveBrokenProperties constructor.
+ *
+ * @param IDBConnection $db
+ */
+ public function __construct(
+ private IDBConnection $db,
+ ) {
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getName() {
+ return 'Remove broken DAV object properties';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function run(IOutput $output) {
+ // retrieve all object properties
+ $qb = $this->db->getQueryBuilder();
+ $qb->select('id', 'propertyvalue')
+ ->from('properties')
+ ->where($qb->expr()->eq('valuetype', $qb->createNamedParameter('3', IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT));
+ $result = $qb->executeQuery();
+ // find broken object properties
+ $brokenIds = [];
+ while ($entry = $result->fetch()) {
+ if (!empty($entry['propertyvalue'])) {
+ $object = @unserialize(str_replace('\x00', chr(0), $entry['propertyvalue']));
+ if ($object === false) {
+ $brokenIds[] = $entry['id'];
+ }
+ } else {
+ $brokenIds[] = $entry['id'];
+ }
+ }
+ $result->closeCursor();
+ // delete broken object properties
+ $qb = $this->db->getQueryBuilder();
+ $qb->delete('properties')
+ ->where($qb->expr()->in('id', $qb->createParameter('ids'), IQueryBuilder::PARAM_STR_ARRAY));
+ foreach (array_chunk($brokenIds, 1000) as $chunkIds) {
+ $qb->setParameter('ids', $chunkIds, IQueryBuilder::PARAM_STR_ARRAY);
+ $qb->executeStatement();
+ }
+ $total = count($brokenIds);
+ $output->info("$total broken object properties removed");
+ }
+}
diff --git a/lib/private/Repair/RemoveLinkShares.php b/lib/private/Repair/RemoveLinkShares.php
index f128b6f731b..a07ebdb72c3 100644
--- a/lib/private/Repair/RemoveLinkShares.php
+++ b/lib/private/Repair/RemoveLinkShares.php
@@ -19,31 +19,17 @@ use OCP\Migration\IRepairStep;
use OCP\Notification\IManager;
class RemoveLinkShares implements IRepairStep {
- /** @var IDBConnection */
- private $connection;
- /** @var IConfig */
- private $config;
/** @var string[] */
private $userToNotify = [];
- /** @var IGroupManager */
- private $groupManager;
- /** @var IManager */
- private $notificationManager;
- /** @var ITimeFactory */
- private $timeFactory;
-
- public function __construct(IDBConnection $connection,
- IConfig $config,
- IGroupManager $groupManager,
- IManager $notificationManager,
- ITimeFactory $timeFactory) {
- $this->connection = $connection;
- $this->config = $config;
- $this->groupManager = $groupManager;
- $this->notificationManager = $notificationManager;
- $this->timeFactory = $timeFactory;
- }
+ public function __construct(
+ private IDBConnection $connection,
+ private IConfig $config,
+ private IGroupManager $groupManager,
+ private IManager $notificationManager,
+ private ITimeFactory $timeFactory,
+ ) {
+ }
public function getName(): string {
return 'Remove potentially over exposing share links';
@@ -74,7 +60,7 @@ class RemoveLinkShares implements IRepairStep {
$qb = $this->connection->getQueryBuilder();
$qb->delete('share')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
- $qb->execute();
+ $qb->executeStatement();
}
/**
@@ -107,11 +93,11 @@ class RemoveLinkShares implements IRepairStep {
->from('share')
->where($query->expr()->in('id', $query->createFunction($subQuery->getSQL())));
- $result = $query->execute();
+ $result = $query->executeQuery();
$data = $result->fetch();
$result->closeCursor();
- return (int) $data['total'];
+ return (int)$data['total'];
}
/**
@@ -137,7 +123,7 @@ class RemoveLinkShares implements IRepairStep {
))
->andWhere($query->expr()->eq('s1.item_source', 's2.item_source'));
/** @var IResult $result */
- $result = $query->execute();
+ $result = $query->executeQuery();
return $result;
}
@@ -180,7 +166,7 @@ class RemoveLinkShares implements IRepairStep {
$users = array_keys($this->userToNotify);
foreach ($users as $user) {
- $notification->setUser((string) $user);
+ $notification->setUser((string)$user);
$this->notificationManager->notify($notification);
}
}
diff --git a/lib/private/Repair/RepairDavShares.php b/lib/private/Repair/RepairDavShares.php
index 792fdd4033e..557e2c080ca 100644
--- a/lib/private/Repair/RepairDavShares.php
+++ b/lib/private/Repair/RepairDavShares.php
@@ -23,27 +23,15 @@ use function urlencode;
class RepairDavShares implements IRepairStep {
protected const GROUP_PRINCIPAL_PREFIX = 'principals/groups/';
- /** @var IConfig */
- private $config;
- /** @var IDBConnection */
- private $dbc;
- /** @var IGroupManager */
- private $groupManager;
- /** @var LoggerInterface */
- private $logger;
/** @var bool */
private $hintInvalidShares = false;
public function __construct(
- IConfig $config,
- IDBConnection $dbc,
- IGroupManager $groupManager,
- LoggerInterface $logger
+ private IConfig $config,
+ private IDBConnection $dbc,
+ private IGroupManager $groupManager,
+ private LoggerInterface $logger,
) {
- $this->config = $config;
- $this->dbc = $dbc;
- $this->groupManager = $groupManager;
- $this->logger = $logger;
}
/**
diff --git a/lib/private/Repair/RepairInvalidShares.php b/lib/private/Repair/RepairInvalidShares.php
index f28ae1c45fb..9553f25ee70 100644
--- a/lib/private/Repair/RepairInvalidShares.php
+++ b/lib/private/Repair/RepairInvalidShares.php
@@ -7,6 +7,8 @@
*/
namespace OC\Repair;
+use OCP\IConfig;
+use OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
@@ -16,19 +18,10 @@ use OCP\Migration\IRepairStep;
class RepairInvalidShares implements IRepairStep {
public const CHUNK_SIZE = 200;
- /** @var \OCP\IConfig */
- protected $config;
-
- /** @var \OCP\IDBConnection */
- protected $connection;
-
- /**
- * @param \OCP\IConfig $config
- * @param \OCP\IDBConnection $connection
- */
- public function __construct($config, $connection) {
- $this->connection = $connection;
- $this->config = $config;
+ public function __construct(
+ protected IConfig $config,
+ protected IDBConnection $connection,
+ ) {
}
public function getName() {
@@ -49,7 +42,7 @@ class RepairInvalidShares implements IRepairStep {
->where($builder->expr()->eq('item_type', $builder->expr()->literal('file')))
->andWhere($builder->expr()->neq('permissions', $permsFunc));
- $updatedEntries = $builder->execute();
+ $updatedEntries = $builder->executeStatement();
if ($updatedEntries > 0) {
$out->info('Fixed file share permissions for ' . $updatedEntries . ' shares');
}
@@ -65,7 +58,7 @@ class RepairInvalidShares implements IRepairStep {
$query->select('s1.parent')
->from('share', 's1')
->where($query->expr()->isNotNull('s1.parent'))
- ->andWhere($query->expr()->isNull('s2.id'))
+ ->andWhere($query->expr()->isNull('s2.id'))
->leftJoin('s1', 'share', 's2', $query->expr()->eq('s1.parent', 's2.id'))
->groupBy('s1.parent')
->setMaxResults(self::CHUNK_SIZE);
@@ -77,11 +70,11 @@ class RepairInvalidShares implements IRepairStep {
$deletedInLastChunk = self::CHUNK_SIZE;
while ($deletedInLastChunk === self::CHUNK_SIZE) {
$deletedInLastChunk = 0;
- $result = $query->execute();
+ $result = $query->executeQuery();
while ($row = $result->fetch()) {
$deletedInLastChunk++;
- $deletedEntries += $deleteQuery->setParameter('parent', (int) $row['parent'])
- ->execute();
+ $deletedEntries += $deleteQuery->setParameter('parent', (int)$row['parent'])
+ ->executeStatement();
}
$result->closeCursor();
}
diff --git a/lib/private/Repair/RepairLogoDimension.php b/lib/private/Repair/RepairLogoDimension.php
new file mode 100644
index 00000000000..854aeb3ab07
--- /dev/null
+++ b/lib/private/Repair/RepairLogoDimension.php
@@ -0,0 +1,82 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OC\Repair;
+
+use OCA\Theming\ImageManager;
+use OCP\Files\NotFoundException;
+use OCP\Files\NotPermittedException;
+use OCP\IConfig;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+use OCP\Server;
+
+class RepairLogoDimension implements IRepairStep {
+ public function __construct(
+ protected IConfig $config,
+ ) {
+ }
+
+ public function getName(): string {
+ return 'Cache logo dimension to fix size in emails on Outlook';
+ }
+
+ public function run(IOutput $output): void {
+ $logoDimensions = $this->config->getAppValue('theming', 'logoDimensions');
+ if (preg_match('/^\d+x\d+$/', $logoDimensions)) {
+ $output->info('Logo dimensions are already known');
+ return;
+ }
+
+ try {
+ /** @var ImageManager $imageManager */
+ $imageManager = Server::get(ImageManager::class);
+ } catch (\Throwable) {
+ $output->info('Theming is disabled');
+ return;
+ }
+
+ if (!$imageManager->hasImage('logo')) {
+ $output->info('Theming is not used to provide a logo');
+ return;
+ }
+
+ try {
+ try {
+ $simpleFile = $imageManager->getImage('logo', false);
+ $image = @imagecreatefromstring($simpleFile->getContent());
+ } catch (NotFoundException|NotPermittedException) {
+ $simpleFile = $imageManager->getImage('logo');
+ $image = false;
+ }
+ } catch (NotFoundException|NotPermittedException) {
+ $output->info('Theming is not used to provide a logo');
+ return;
+ }
+
+ $dimensions = '';
+ if ($image !== false) {
+ $dimensions = imagesx($image) . 'x' . imagesy($image);
+ } elseif (str_starts_with($simpleFile->getMimeType(), 'image/svg')) {
+ $matched = preg_match('/viewbox=["\']\d* \d* (\d*\.?\d*) (\d*\.?\d*)["\']/i', $simpleFile->getContent(), $matches);
+ if ($matched) {
+ $dimensions = $matches[1] . 'x' . $matches[2];
+ }
+ }
+
+ if (!$dimensions) {
+ $output->warning('Failed to read dimensions from logo');
+ $this->config->deleteAppValue('theming', 'logoDimensions');
+ return;
+ }
+
+ $dimensions = imagesx($image) . 'x' . imagesy($image);
+ $this->config->setAppValue('theming', 'logoDimensions', $dimensions);
+ $output->info('Updated logo dimensions: ' . $dimensions);
+ }
+}
diff --git a/lib/private/Repair/RepairMimeTypes.php b/lib/private/Repair/RepairMimeTypes.php
index 103ce9c13fc..3c9720b9e91 100644
--- a/lib/private/Repair/RepairMimeTypes.php
+++ b/lib/private/Repair/RepairMimeTypes.php
@@ -1,38 +1,48 @@
<?php
/**
- * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
- * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OC\Repair;
+use OC\Migration\NullOutput;
+use OCP\DB\Exception;
+use OCP\DB\IResult;
use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class RepairMimeTypes implements IRepairStep {
- /** @var IConfig */
- protected $config;
- /** @var IDBConnection */
- protected $connection;
+ private bool $dryRun = false;
+ private int $changeCount = 0;
/** @var int */
- protected $folderMimeTypeId;
+ protected int $folderMimeTypeId;
- public function __construct(IConfig $config,
- IDBConnection $connection) {
- $this->config = $config;
- $this->connection = $connection;
+ public function __construct(
+ protected IConfig $config,
+ protected IAppConfig $appConfig,
+ protected IDBConnection $connection,
+ ) {
}
- public function getName() {
+ public function getName(): string {
return 'Repair mime types';
}
- private function updateMimetypes($updatedMimetypes) {
+ /**
+ * @throws Exception
+ */
+ private function updateMimetypes($updatedMimetypes): IResult|int|null {
+ if ($this->dryRun) {
+ $this->changeCount += count($updatedMimetypes);
+ return null;
+ }
+
$query = $this->connection->getQueryBuilder();
$query->select('id')
->from('mimetypes')
@@ -50,6 +60,7 @@ class RepairMimeTypes implements IRepairStep {
$update = $this->connection->getQueryBuilder();
$update->update('filecache')
+ ->runAcrossAllShards()
->set('mimetype', $update->createParameter('mimetype'))
->where($update->expr()->neq('mimetype', $update->createParameter('mimetype'), IQueryBuilder::PARAM_INT))
->andWhere($update->expr()->neq('mimetype', $update->createParameter('folder'), IQueryBuilder::PARAM_INT))
@@ -80,16 +91,11 @@ class RepairMimeTypes implements IRepairStep {
return $count;
}
- private function introduceAsciidocType() {
- $updatedMimetypes = [
- 'adoc' => 'text/asciidoc',
- 'asciidoc' => 'text/asciidoc',
- ];
-
- return $this->updateMimetypes($updatedMimetypes);
- }
-
- private function introduceImageTypes() {
+ /**
+ * @throws Exception
+ * @since 12.0.0.14
+ */
+ private function introduceImageTypes(): IResult|int|null {
$updatedMimetypes = [
'jp2' => 'image/jp2',
'webp' => 'image/webp',
@@ -98,7 +104,11 @@ class RepairMimeTypes implements IRepairStep {
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceWindowsProgramTypes() {
+ /**
+ * @throws Exception
+ * @since 12.0.0.13
+ */
+ private function introduceWindowsProgramTypes(): IResult|int|null {
$updatedMimetypes = [
'htaccess' => 'text/plain',
'bat' => 'application/x-msdos-program',
@@ -108,7 +118,11 @@ class RepairMimeTypes implements IRepairStep {
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceLocationTypes() {
+ /**
+ * @throws Exception
+ * @since 13.0.0.0
+ */
+ private function introduceLocationTypes(): IResult|int|null {
$updatedMimetypes = [
'gpx' => 'application/gpx+xml',
'kml' => 'application/vnd.google-earth.kml+xml',
@@ -119,7 +133,11 @@ class RepairMimeTypes implements IRepairStep {
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceInternetShortcutTypes() {
+ /**
+ * @throws Exception
+ * @since 13.0.0.3
+ */
+ private function introduceInternetShortcutTypes(): IResult|int|null {
$updatedMimetypes = [
'url' => 'application/internet-shortcut',
'webloc' => 'application/internet-shortcut'
@@ -128,7 +146,11 @@ class RepairMimeTypes implements IRepairStep {
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceStreamingTypes() {
+ /**
+ * @throws Exception
+ * @since 13.0.0.6
+ */
+ private function introduceStreamingTypes(): IResult|int|null {
$updatedMimetypes = [
'm3u' => 'audio/mpegurl',
'm3u8' => 'audio/mpegurl',
@@ -138,7 +160,11 @@ class RepairMimeTypes implements IRepairStep {
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceVisioTypes() {
+ /**
+ * @throws Exception
+ * @since 14.0.0.8
+ */
+ private function introduceVisioTypes(): IResult|int|null {
$updatedMimetypes = [
'vsdm' => 'application/vnd.visio',
'vsdx' => 'application/vnd.visio',
@@ -151,7 +177,11 @@ class RepairMimeTypes implements IRepairStep {
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceComicbookTypes() {
+ /**
+ * @throws Exception
+ * @since 14.0.0.10
+ */
+ private function introduceComicbookTypes(): IResult|int|null {
$updatedMimetypes = [
'cb7' => 'application/comicbook+7z',
'cba' => 'application/comicbook+ace',
@@ -164,7 +194,11 @@ class RepairMimeTypes implements IRepairStep {
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceOpenDocumentTemplates() {
+ /**
+ * @throws Exception
+ * @since 20.0.0.5
+ */
+ private function introduceOpenDocumentTemplates(): IResult|int|null {
$updatedMimetypes = [
'ott' => 'application/vnd.oasis.opendocument.text-template',
'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
@@ -175,35 +209,64 @@ class RepairMimeTypes implements IRepairStep {
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceFlatOpenDocumentType() {
+ /**
+ * @throws Exception
+ * @since 21.0.0.7
+ */
+ private function introduceOrgModeType(): IResult|int|null {
$updatedMimetypes = [
- "fodt" => "application/vnd.oasis.opendocument.text-flat-xml",
- "fods" => "application/vnd.oasis.opendocument.spreadsheet-flat-xml",
- "fodg" => "application/vnd.oasis.opendocument.graphics-flat-xml",
- "fodp" => "application/vnd.oasis.opendocument.presentation-flat-xml",
+ 'org' => 'text/org'
];
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceOrgModeType() {
+ /**
+ * @throws Exception
+ * @since 23.0.0.2
+ */
+ private function introduceFlatOpenDocumentType(): IResult|int|null {
$updatedMimetypes = [
- 'org' => 'text/org'
+ 'fodt' => 'application/vnd.oasis.opendocument.text-flat-xml',
+ 'fods' => 'application/vnd.oasis.opendocument.spreadsheet-flat-xml',
+ 'fodg' => 'application/vnd.oasis.opendocument.graphics-flat-xml',
+ 'fodp' => 'application/vnd.oasis.opendocument.presentation-flat-xml',
];
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceOnlyofficeFormType() {
+ /**
+ * @throws Exception
+ * @since 25.0.0.2
+ */
+ private function introduceOnlyofficeFormType(): IResult|int|null {
$updatedMimetypes = [
- "oform" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform",
- "docxf" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document.docxf",
+ 'oform' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform',
+ 'docxf' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.docxf',
];
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceEnhancedMetafileFormatType() {
+ /**
+ * @throws Exception
+ * @since 26.0.0.1
+ */
+ private function introduceAsciidocType(): IResult|int|null {
+ $updatedMimetypes = [
+ 'adoc' => 'text/asciidoc',
+ 'asciidoc' => 'text/asciidoc',
+ ];
+
+ return $this->updateMimetypes($updatedMimetypes);
+ }
+
+ /**
+ * @throws Exception
+ * @since 28.0.0.5
+ */
+ private function introduceEnhancedMetafileFormatType(): IResult|int|null {
$updatedMimetypes = [
'emf' => 'image/emf',
];
@@ -211,7 +274,11 @@ class RepairMimeTypes implements IRepairStep {
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceEmlAndMsgFormatType() {
+ /**
+ * @throws Exception
+ * @since 29.0.0.2
+ */
+ private function introduceEmlAndMsgFormatType(): IResult|int|null {
$updatedMimetypes = [
'eml' => 'message/rfc822',
'msg' => 'application/vnd.ms-outlook',
@@ -220,7 +287,11 @@ class RepairMimeTypes implements IRepairStep {
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceAacAudioType() {
+ /**
+ * @throws Exception
+ * @since 29.0.0.6
+ */
+ private function introduceAacAudioType(): IResult|int|null {
$updatedMimetypes = [
'aac' => 'audio/aac',
];
@@ -228,7 +299,11 @@ class RepairMimeTypes implements IRepairStep {
return $this->updateMimetypes($updatedMimetypes);
}
- private function introduceReStructuredTextFormatType() {
+ /**
+ * @throws Exception
+ * @since 29.0.10
+ */
+ private function introduceReStructuredTextFormatType(): IResult|int|null {
$updatedMimetypes = [
'rst' => 'text/x-rst',
];
@@ -237,76 +312,162 @@ class RepairMimeTypes implements IRepairStep {
}
/**
+ * @throws Exception
+ * @since 30.0.0
+ */
+ private function introduceExcalidrawType(): IResult|int|null {
+ $updatedMimetypes = [
+ 'excalidraw' => 'application/vnd.excalidraw+json',
+ ];
+
+ return $this->updateMimetypes($updatedMimetypes);
+ }
+
+
+ /**
+ * @throws Exception
+ * @since 31.0.0
+ */
+ private function introduceZstType(): IResult|int|null {
+ $updatedMimetypes = [
+ 'zst' => 'application/zstd',
+ 'nfo' => 'text/x-nfo',
+ ];
+
+ return $this->updateMimetypes($updatedMimetypes);
+ }
+
+ /**
+ * @throws Exception
+ * @since 32.0.0
+ */
+ private function introduceMusicxmlType(): IResult|int|null {
+ $updatedMimetypes = [
+ 'mxl' => 'application/vnd.recordare.musicxml',
+ 'musicxml' => 'application/vnd.recordare.musicxml+xml',
+ ];
+
+ return $this->updateMimetypes($updatedMimetypes);
+ }
+
+
+
+ /**
+ * Check if there are any migrations available
+ *
+ * @throws Exception
+ */
+ public function migrationsAvailable(): bool {
+ $this->dryRun = true;
+ $this->run(new NullOutput());
+ $this->dryRun = false;
+ return $this->changeCount > 0;
+ }
+
+ /**
+ * Get the current mimetype version
+ */
+ private function getMimeTypeVersion(): string {
+ $serverVersion = $this->config->getSystemValueString('version', '0.0.0');
+ // 29.0.0.10 is the last version with a mimetype migration before it was moved to a separate version number
+ if (version_compare($serverVersion, '29.0.0.10', '>')) {
+ return $this->appConfig->getValueString('files', 'mimetype_version', '29.0.0.10');
+ }
+
+ return $serverVersion;
+ }
+
+ /**
* Fix mime types
+ *
+ * @throws Exception
*/
- public function run(IOutput $out) {
- $ocVersionFromBeforeUpdate = $this->config->getSystemValueString('version', '0.0.0');
+ public function run(IOutput $out): void {
+ $serverVersion = $this->config->getSystemValueString('version', '0.0.0');
+ $mimeTypeVersion = $this->getMimeTypeVersion();
// NOTE TO DEVELOPERS: when adding new mime types, please make sure to
// add a version comparison to avoid doing it every time
+ // PLEASE ALSO KEEP THE LIST SORTED BY VERSION NUMBER
- if (version_compare($ocVersionFromBeforeUpdate, '12.0.0.14', '<') && $this->introduceImageTypes()) {
+ if (version_compare($mimeTypeVersion, '12.0.0.14', '<') && $this->introduceImageTypes()) {
$out->info('Fixed image mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '12.0.0.13', '<') && $this->introduceWindowsProgramTypes()) {
+ if (version_compare($mimeTypeVersion, '12.0.0.13', '<') && $this->introduceWindowsProgramTypes()) {
$out->info('Fixed windows program mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '13.0.0.0', '<') && $this->introduceLocationTypes()) {
+ if (version_compare($mimeTypeVersion, '13.0.0.0', '<') && $this->introduceLocationTypes()) {
$out->info('Fixed geospatial mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '13.0.0.3', '<') && $this->introduceInternetShortcutTypes()) {
+ if (version_compare($mimeTypeVersion, '13.0.0.3', '<') && $this->introduceInternetShortcutTypes()) {
$out->info('Fixed internet-shortcut mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '13.0.0.6', '<') && $this->introduceStreamingTypes()) {
+ if (version_compare($mimeTypeVersion, '13.0.0.6', '<') && $this->introduceStreamingTypes()) {
$out->info('Fixed streaming mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '14.0.0.8', '<') && $this->introduceVisioTypes()) {
+ if (version_compare($mimeTypeVersion, '14.0.0.8', '<') && $this->introduceVisioTypes()) {
$out->info('Fixed visio mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '14.0.0.10', '<') && $this->introduceComicbookTypes()) {
+ if (version_compare($mimeTypeVersion, '14.0.0.10', '<') && $this->introduceComicbookTypes()) {
$out->info('Fixed comicbook mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '20.0.0.5', '<') && $this->introduceOpenDocumentTemplates()) {
+ if (version_compare($mimeTypeVersion, '20.0.0.5', '<') && $this->introduceOpenDocumentTemplates()) {
$out->info('Fixed OpenDocument template mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '21.0.0.7', '<') && $this->introduceOrgModeType()) {
+ if (version_compare($mimeTypeVersion, '21.0.0.7', '<') && $this->introduceOrgModeType()) {
$out->info('Fixed orgmode mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '23.0.0.2', '<') && $this->introduceFlatOpenDocumentType()) {
+ if (version_compare($mimeTypeVersion, '23.0.0.2', '<') && $this->introduceFlatOpenDocumentType()) {
$out->info('Fixed Flat OpenDocument mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '25.0.0.2', '<') && $this->introduceOnlyofficeFormType()) {
+ if (version_compare($mimeTypeVersion, '25.0.0.2', '<') && $this->introduceOnlyofficeFormType()) {
$out->info('Fixed ONLYOFFICE Forms OpenXML mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '26.0.0.1', '<') && $this->introduceAsciidocType()) {
+ if (version_compare($mimeTypeVersion, '26.0.0.1', '<') && $this->introduceAsciidocType()) {
$out->info('Fixed AsciiDoc mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '28.0.0.5', '<') && $this->introduceEnhancedMetafileFormatType()) {
+ if (version_compare($mimeTypeVersion, '28.0.0.5', '<') && $this->introduceEnhancedMetafileFormatType()) {
$out->info('Fixed Enhanced Metafile Format mime types');
}
- if (version_compare($ocVersionFromBeforeUpdate, '29.0.0.2', '<') && $this->introduceEmlAndMsgFormatType()) {
+ if (version_compare($mimeTypeVersion, '29.0.0.2', '<') && $this->introduceEmlAndMsgFormatType()) {
$out->info('Fixed eml and msg mime type');
}
- if (version_compare($ocVersionFromBeforeUpdate, '29.0.0.6', '<') && $this->introduceAacAudioType()) {
+ if (version_compare($mimeTypeVersion, '29.0.0.6', '<') && $this->introduceAacAudioType()) {
$out->info('Fixed aac mime type');
}
- if (version_compare($ocVersionFromBeforeUpdate, '29.0.0.10', '<') && $this->introduceReStructuredTextFormatType()) {
+ if (version_compare($mimeTypeVersion, '29.0.0.10', '<') && $this->introduceReStructuredTextFormatType()) {
$out->info('Fixed ReStructured Text mime type');
}
+
+ if (version_compare($mimeTypeVersion, '30.0.0.0', '<') && $this->introduceExcalidrawType()) {
+ $out->info('Fixed Excalidraw mime type');
+ }
+
+ if (version_compare($mimeTypeVersion, '31.0.0.0', '<') && $this->introduceZstType()) {
+ $out->info('Fixed zst mime type');
+ }
+
+ if (version_compare($mimeTypeVersion, '32.0.0.0', '<') && $this->introduceMusicxmlType()) {
+ $out->info('Fixed musicxml mime type');
+ }
+
+ if (!$this->dryRun) {
+ $this->appConfig->setValueString('files', 'mimetype_version', $serverVersion);
+ }
}
}