diff options
Diffstat (limited to 'lib/private/Repair/RepairMimeTypes.php')
-rw-r--r-- | lib/private/Repair/RepairMimeTypes.php | 285 |
1 files changed, 223 insertions, 62 deletions
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); + } } } |