diff --git a/composer/composer/autoload_classmap.php b/composer/composer/autoload_classmap.php index 361a322655..e1694103eb 100644 --- a/composer/composer/autoload_classmap.php +++ b/composer/composer/autoload_classmap.php @@ -30,6 +30,7 @@ 'OCA\\Richdocuments\\Controller\\TemplateFieldController' => $baseDir . '/../lib/Controller/TemplateFieldController.php', 'OCA\\Richdocuments\\Controller\\TemplatesController' => $baseDir . '/../lib/Controller/TemplatesController.php', 'OCA\\Richdocuments\\Controller\\WopiController' => $baseDir . '/../lib/Controller/WopiController.php', + 'OCA\\Richdocuments\\Conversion\\ConversionProvider' => $baseDir . '/../lib/Conversion/ConversionProvider.php', 'OCA\\Richdocuments\\Db\\Asset' => $baseDir . '/../lib/Db/Asset.php', 'OCA\\Richdocuments\\Db\\AssetMapper' => $baseDir . '/../lib/Db/AssetMapper.php', 'OCA\\Richdocuments\\Db\\Direct' => $baseDir . '/../lib/Db/Direct.php', diff --git a/composer/composer/autoload_static.php b/composer/composer/autoload_static.php index d773f0391e..c8786fb383 100644 --- a/composer/composer/autoload_static.php +++ b/composer/composer/autoload_static.php @@ -63,6 +63,7 @@ class ComposerStaticInitRichdocuments 'OCA\\Richdocuments\\Controller\\TemplateFieldController' => __DIR__ . '/..' . '/../lib/Controller/TemplateFieldController.php', 'OCA\\Richdocuments\\Controller\\TemplatesController' => __DIR__ . '/..' . '/../lib/Controller/TemplatesController.php', 'OCA\\Richdocuments\\Controller\\WopiController' => __DIR__ . '/..' . '/../lib/Controller/WopiController.php', + 'OCA\\Richdocuments\\Conversion\\ConversionProvider' => __DIR__ . '/..' . '/../lib/Conversion/ConversionProvider.php', 'OCA\\Richdocuments\\Db\\Asset' => __DIR__ . '/..' . '/../lib/Db/Asset.php', 'OCA\\Richdocuments\\Db\\AssetMapper' => __DIR__ . '/..' . '/../lib/Db/AssetMapper.php', 'OCA\\Richdocuments\\Db\\Direct' => __DIR__ . '/..' . '/../lib/Db/Direct.php', diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 1bf44468a9..87b3cf06c8 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -10,6 +10,7 @@ use OCA\Files_Sharing\Event\ShareLinkAccessedEvent; use OCA\Richdocuments\Capabilities; +use OCA\Richdocuments\Conversion\ConversionProvider; use OCA\Richdocuments\Db\WopiMapper; use OCA\Richdocuments\Listener\AddContentSecurityPolicyListener; use OCA\Richdocuments\Listener\AddFeaturePolicyListener; @@ -81,6 +82,7 @@ public function register(IRegistrationContext $context): void { $context->registerPreviewProvider(OOXML::class, OOXML::MIMETYPE_REGEX); $context->registerPreviewProvider(OpenDocument::class, OpenDocument::MIMETYPE_REGEX); $context->registerPreviewProvider(Pdf::class, Pdf::MIMETYPE_REGEX); + $context->registerFileConversionProvider(ConversionProvider::class); $context->registerNotifierService(Notifier::class); } diff --git a/lib/Conversion/ConversionProvider.php b/lib/Conversion/ConversionProvider.php new file mode 100644 index 0000000000..072a02f5f6 --- /dev/null +++ b/lib/Conversion/ConversionProvider.php @@ -0,0 +1,242 @@ + [ + 'doc' => 'application/msword', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'odt' => 'application/vnd.oasis.opendocument.text', + ], + 'sheets' => [ + 'xls' => 'application/vnd.ms-excel', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + ], + 'presentations' => [ + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + ], + 'drawings' => [ + 'vsdx' => 'application/vnd.visio', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + ], + ]; + + public function __construct( + private RemoteService $remoteService, + private LoggerInterface $logger, + IFactory $l10nFactory, + ) { + $this->l10n = $l10nFactory->get('richdocuments'); + } + + public function getSupportedMimeTypes(): array { + $documents = self::MIME_TYPES['documents']; + $sheets = self::MIME_TYPES['sheets']; + $presentations = self::MIME_TYPES['presentations']; + $drawings = self::MIME_TYPES['drawings']; + + $pdfConversions = array_merge( + [], + self::MIME_TYPES['documents'], + self::MIME_TYPES['sheets'], + self::MIME_TYPES['presentations'], + self::MIME_TYPES['drawings'], + ); + + $documentConversions = [ + // OpenDocument Text to Word Document + 'docx' => [$documents['odt']], + + // Word Document to OpenDocument Text + 'odt' => [$documents['doc'], $documents['docx']], + + // Documents to Rich Text Format + 'rtf' => [$documents['odt'], $documents['doc'], $documents['docx']], + + // Documents to text + 'txt' => [$documents['odt'], $documents['doc'], $documents['docx']], + ]; + + $spreadsheetConversions = [ + // OpenDocument Spreadsheet to Excel Workbook + 'xlsx' => [$sheets['ods']], + + // Excel Workbook to OpenDocument Spreadsheet + 'ods' => [$sheets['xls'], $sheets['xlsx']], + ]; + + $presentationConversions = [ + // OpenDocument Presentation to PowerPoint Presentation + 'pptx' => [$presentations['odp']], + + // PowerPoint Presentation to OpenDocument Presentation + 'odp' => [$presentations['ppt'], $presentations['pptx']], + ]; + + $drawingConversions = [ + // OpenDocument Drawing to Portable Network Graphics + 'png' => [$drawings['odg']], + + // OpenDocument Drawing to Scalable Vector Graphics + 'svg' => [$drawings['odg']], + ]; + + return [ + // PDF conversions + ...$this->getMimeProvidersFor($pdfConversions, 'application/pdf'), + + // Document conversions + ...$this->getMimeProvidersFor($documentConversions['docx'], $documents['docx']), + ...$this->getMimeProvidersFor($documentConversions['odt'], $documents['odt']), + ...$this->getMimeProvidersFor($documentConversions['rtf'], 'application/rtf'), + ...$this->getMimeProvidersFor($documentConversions['txt'], 'text/plain'), + + // Spreadsheet conversions + ...$this->getMimeProvidersFor($spreadsheetConversions['xlsx'], $sheets['xlsx']), + ...$this->getMimeProvidersFor($spreadsheetConversions['ods'], $sheets['ods']), + + // Presentation conversions + ...$this->getMimeProvidersFor($presentationConversions['pptx'], $presentations['pptx']), + ...$this->getMimeProvidersFor($presentationConversions['odp'], $presentations['odp']), + + // Drawing conversions + ...$this->getMimeProvidersFor($drawingConversions['png'], 'image/png'), + ...$this->getMimeProvidersFor($drawingConversions['svg'], 'image/svg+xml'), + ]; + } + + public function convertFile(File $file, string $targetMimeType): mixed { + $targetFileExtension = $this->getExtensionForMimeType($targetMimeType); + if ($targetFileExtension === null) { + throw new \Exception($this->l10n->t( + 'Unable to determine the proper file extension for %1$s', + [$targetMimeType] + )); + } + + return $this->remoteService->convertFileTo($file, $targetFileExtension); + } + + private function getMimeProvidersFor(array $inputMimeTypes, string $outputMimeType): array { + $outputMimeInfo = $this->getMimeInfoFor($outputMimeType); + if ($outputMimeInfo === null) { + $this->logger->error($this->l10n->t('Unable to fetch information on $s', [$outputMimeType])); + throw new \Exception(); + } + + $conversionMimeProviders = []; + foreach ($inputMimeTypes as $mimeType) { + $conversionMimeProviders[] = new ConversionMimeProvider( + $mimeType, + ...$outputMimeInfo + ); + } + + return $conversionMimeProviders; + } + + private function getMimeInfoFor(string $targetMimeType): ?array { + foreach ($this->getTargetMimeTypes() as $mimeType => $mimeInfo) { + if ($mimeType === $targetMimeType) { + return [ + 'to' => $mimeType, + 'extension' => $mimeInfo['extension'], + 'displayName' => $mimeInfo['displayName'], + ]; + } + } + + return null; + } + + private function getTargetMimeTypes(): array { + $documents = self::MIME_TYPES['documents']; + $sheets = self::MIME_TYPES['sheets']; + $presentations = self::MIME_TYPES['presentations']; + + return [ + 'application/pdf' => [ + 'extension' => 'pdf', + 'displayName' => $this->l10n->t('Portable Document Format (.pdf)'), + ], + 'image/png' => [ + 'extension' => 'png', + 'displayName' => $this->l10n->t('Image (.png)'), + ], + 'image/svg+xml' => [ + 'extension' => 'svg', + 'displayName' => $this->l10n->t('Image (.svg)'), + ], + 'application/rtf' => [ + 'extension' => 'rtf', + 'displayName' => $this->l10n->t('Text (.rtf)'), + ], + 'text/plain' => [ + 'extension' => 'txt', + 'displayName' => $this->l10n->t('Text (.txt)'), + ], + $documents['docx'] => [ + 'extension' => 'docx', + 'displayName' => $this->l10n->t('Word Document (.docx)'), + ], + $documents['odt'] => [ + 'extension' => 'odt', + 'displayName' => $this->l10n->t('OpenDocument Text (.odt)'), + ], + $sheets['xlsx'] => [ + 'extension' => 'xlsx', + 'displayName' => $this->l10n->t('Excel Workbook (.xlsx)'), + ], + $sheets['ods'] => [ + 'extension' => 'ods', + 'displayName' => $this->l10n->t('OpenDocument Spreadsheet (.ods)'), + ], + $presentations['pptx'] => [ + 'extension' => 'pptx', + 'displayName' => $this->l10n->t('PowerPoint Presentation (.pptx)'), + ], + $presentations['odp'] => [ + 'extension' => 'odp', + 'displayName' => $this->l10n->t('OpenDocument Presentation (.odp)'), + ], + ]; + } + + private function getExtensionForMimeType(string $mimeType): ?string { + foreach ($this->getTargetMimeTypes() as $targetMimeType => $targetMimeInfo) { + if ($targetMimeType === $mimeType) { + return $targetMimeInfo['extension']; + } + } + + return null; + } +}