Skip to content

Commit 08e4636

Browse files
authored
Merge pull request #4408 from nextcloud/backport/4375/stable31
[stable31] feat: file conversion provider
2 parents 3e24a35 + 2e26d4e commit 08e4636

File tree

4 files changed

+246
-0
lines changed

4 files changed

+246
-0
lines changed

composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
'OCA\\Richdocuments\\Controller\\TemplateFieldController' => $baseDir . '/../lib/Controller/TemplateFieldController.php',
3131
'OCA\\Richdocuments\\Controller\\TemplatesController' => $baseDir . '/../lib/Controller/TemplatesController.php',
3232
'OCA\\Richdocuments\\Controller\\WopiController' => $baseDir . '/../lib/Controller/WopiController.php',
33+
'OCA\\Richdocuments\\Conversion\\ConversionProvider' => $baseDir . '/../lib/Conversion/ConversionProvider.php',
3334
'OCA\\Richdocuments\\Db\\Asset' => $baseDir . '/../lib/Db/Asset.php',
3435
'OCA\\Richdocuments\\Db\\AssetMapper' => $baseDir . '/../lib/Db/AssetMapper.php',
3536
'OCA\\Richdocuments\\Db\\Direct' => $baseDir . '/../lib/Db/Direct.php',

composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class ComposerStaticInitRichdocuments
6363
'OCA\\Richdocuments\\Controller\\TemplateFieldController' => __DIR__ . '/..' . '/../lib/Controller/TemplateFieldController.php',
6464
'OCA\\Richdocuments\\Controller\\TemplatesController' => __DIR__ . '/..' . '/../lib/Controller/TemplatesController.php',
6565
'OCA\\Richdocuments\\Controller\\WopiController' => __DIR__ . '/..' . '/../lib/Controller/WopiController.php',
66+
'OCA\\Richdocuments\\Conversion\\ConversionProvider' => __DIR__ . '/..' . '/../lib/Conversion/ConversionProvider.php',
6667
'OCA\\Richdocuments\\Db\\Asset' => __DIR__ . '/..' . '/../lib/Db/Asset.php',
6768
'OCA\\Richdocuments\\Db\\AssetMapper' => __DIR__ . '/..' . '/../lib/Db/AssetMapper.php',
6869
'OCA\\Richdocuments\\Db\\Direct' => __DIR__ . '/..' . '/../lib/Db/Direct.php',

lib/AppInfo/Application.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use OCA\Files_Sharing\Event\ShareLinkAccessedEvent;
1212
use OCA\Richdocuments\Capabilities;
13+
use OCA\Richdocuments\Conversion\ConversionProvider;
1314
use OCA\Richdocuments\Db\WopiMapper;
1415
use OCA\Richdocuments\Listener\AddContentSecurityPolicyListener;
1516
use OCA\Richdocuments\Listener\AddFeaturePolicyListener;
@@ -81,6 +82,7 @@ public function register(IRegistrationContext $context): void {
8182
$context->registerPreviewProvider(OOXML::class, OOXML::MIMETYPE_REGEX);
8283
$context->registerPreviewProvider(OpenDocument::class, OpenDocument::MIMETYPE_REGEX);
8384
$context->registerPreviewProvider(Pdf::class, Pdf::MIMETYPE_REGEX);
85+
$context->registerFileConversionProvider(ConversionProvider::class);
8486
$context->registerNotifierService(Notifier::class);
8587
}
8688

lib/Conversion/ConversionProvider.php

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Richdocuments\Conversion;
11+
12+
use OCA\Richdocuments\Service\RemoteService;
13+
use OCP\Files\Conversion\ConversionMimeProvider;
14+
use OCP\Files\Conversion\IConversionProvider;
15+
use OCP\Files\File;
16+
use OCP\IL10N;
17+
use OCP\L10N\IFactory;
18+
use Psr\Log\LoggerInterface;
19+
20+
class ConversionProvider implements IConversionProvider {
21+
private IL10N $l10n;
22+
23+
private const MIME_TYPES = [
24+
'documents' => [
25+
'doc' => 'application/msword',
26+
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
27+
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
28+
'ott' => 'application/vnd.oasis.opendocument.text-template',
29+
'odt' => 'application/vnd.oasis.opendocument.text',
30+
],
31+
'sheets' => [
32+
'xls' => 'application/vnd.ms-excel',
33+
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
34+
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
35+
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
36+
'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
37+
],
38+
'presentations' => [
39+
'ppt' => 'application/vnd.ms-powerpoint',
40+
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
41+
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
42+
'odp' => 'application/vnd.oasis.opendocument.presentation',
43+
'otp' => 'application/vnd.oasis.opendocument.presentation-template',
44+
],
45+
'drawings' => [
46+
'vsdx' => 'application/vnd.visio',
47+
'odg' => 'application/vnd.oasis.opendocument.graphics',
48+
'otg' => 'application/vnd.oasis.opendocument.graphics-template',
49+
],
50+
];
51+
52+
public function __construct(
53+
private RemoteService $remoteService,
54+
private LoggerInterface $logger,
55+
IFactory $l10nFactory,
56+
) {
57+
$this->l10n = $l10nFactory->get('richdocuments');
58+
}
59+
60+
public function getSupportedMimeTypes(): array {
61+
$documents = self::MIME_TYPES['documents'];
62+
$sheets = self::MIME_TYPES['sheets'];
63+
$presentations = self::MIME_TYPES['presentations'];
64+
$drawings = self::MIME_TYPES['drawings'];
65+
66+
$pdfConversions = array_merge(
67+
[],
68+
self::MIME_TYPES['documents'],
69+
self::MIME_TYPES['sheets'],
70+
self::MIME_TYPES['presentations'],
71+
self::MIME_TYPES['drawings'],
72+
);
73+
74+
$documentConversions = [
75+
// OpenDocument Text to Word Document
76+
'docx' => [$documents['odt']],
77+
78+
// Word Document to OpenDocument Text
79+
'odt' => [$documents['doc'], $documents['docx']],
80+
81+
// Documents to Rich Text Format
82+
'rtf' => [$documents['odt'], $documents['doc'], $documents['docx']],
83+
84+
// Documents to text
85+
'txt' => [$documents['odt'], $documents['doc'], $documents['docx']],
86+
];
87+
88+
$spreadsheetConversions = [
89+
// OpenDocument Spreadsheet to Excel Workbook
90+
'xlsx' => [$sheets['ods']],
91+
92+
// Excel Workbook to OpenDocument Spreadsheet
93+
'ods' => [$sheets['xls'], $sheets['xlsx']],
94+
];
95+
96+
$presentationConversions = [
97+
// OpenDocument Presentation to PowerPoint Presentation
98+
'pptx' => [$presentations['odp']],
99+
100+
// PowerPoint Presentation to OpenDocument Presentation
101+
'odp' => [$presentations['ppt'], $presentations['pptx']],
102+
];
103+
104+
$drawingConversions = [
105+
// OpenDocument Drawing to Portable Network Graphics
106+
'png' => [$drawings['odg']],
107+
108+
// OpenDocument Drawing to Scalable Vector Graphics
109+
'svg' => [$drawings['odg']],
110+
];
111+
112+
return [
113+
// PDF conversions
114+
...$this->getMimeProvidersFor($pdfConversions, 'application/pdf'),
115+
116+
// Document conversions
117+
...$this->getMimeProvidersFor($documentConversions['docx'], $documents['docx']),
118+
...$this->getMimeProvidersFor($documentConversions['odt'], $documents['odt']),
119+
...$this->getMimeProvidersFor($documentConversions['rtf'], 'application/rtf'),
120+
...$this->getMimeProvidersFor($documentConversions['txt'], 'text/plain'),
121+
122+
// Spreadsheet conversions
123+
...$this->getMimeProvidersFor($spreadsheetConversions['xlsx'], $sheets['xlsx']),
124+
...$this->getMimeProvidersFor($spreadsheetConversions['ods'], $sheets['ods']),
125+
126+
// Presentation conversions
127+
...$this->getMimeProvidersFor($presentationConversions['pptx'], $presentations['pptx']),
128+
...$this->getMimeProvidersFor($presentationConversions['odp'], $presentations['odp']),
129+
130+
// Drawing conversions
131+
...$this->getMimeProvidersFor($drawingConversions['png'], 'image/png'),
132+
...$this->getMimeProvidersFor($drawingConversions['svg'], 'image/svg+xml'),
133+
];
134+
}
135+
136+
public function convertFile(File $file, string $targetMimeType): mixed {
137+
$targetFileExtension = $this->getExtensionForMimeType($targetMimeType);
138+
if ($targetFileExtension === null) {
139+
throw new \Exception($this->l10n->t(
140+
'Unable to determine the proper file extension for %1$s',
141+
[$targetMimeType]
142+
));
143+
}
144+
145+
return $this->remoteService->convertFileTo($file, $targetFileExtension);
146+
}
147+
148+
private function getMimeProvidersFor(array $inputMimeTypes, string $outputMimeType): array {
149+
$outputMimeInfo = $this->getMimeInfoFor($outputMimeType);
150+
if ($outputMimeInfo === null) {
151+
$this->logger->error($this->l10n->t('Unable to fetch information on $s', [$outputMimeType]));
152+
throw new \Exception();
153+
}
154+
155+
$conversionMimeProviders = [];
156+
foreach ($inputMimeTypes as $mimeType) {
157+
$conversionMimeProviders[] = new ConversionMimeProvider(
158+
$mimeType,
159+
...$outputMimeInfo
160+
);
161+
}
162+
163+
return $conversionMimeProviders;
164+
}
165+
166+
private function getMimeInfoFor(string $targetMimeType): ?array {
167+
foreach ($this->getTargetMimeTypes() as $mimeType => $mimeInfo) {
168+
if ($mimeType === $targetMimeType) {
169+
return [
170+
'to' => $mimeType,
171+
'extension' => $mimeInfo['extension'],
172+
'displayName' => $mimeInfo['displayName'],
173+
];
174+
}
175+
}
176+
177+
return null;
178+
}
179+
180+
private function getTargetMimeTypes(): array {
181+
$documents = self::MIME_TYPES['documents'];
182+
$sheets = self::MIME_TYPES['sheets'];
183+
$presentations = self::MIME_TYPES['presentations'];
184+
185+
return [
186+
'application/pdf' => [
187+
'extension' => 'pdf',
188+
'displayName' => $this->l10n->t('Portable Document Format (.pdf)'),
189+
],
190+
'image/png' => [
191+
'extension' => 'png',
192+
'displayName' => $this->l10n->t('Image (.png)'),
193+
],
194+
'image/svg+xml' => [
195+
'extension' => 'svg',
196+
'displayName' => $this->l10n->t('Image (.svg)'),
197+
],
198+
'application/rtf' => [
199+
'extension' => 'rtf',
200+
'displayName' => $this->l10n->t('Text (.rtf)'),
201+
],
202+
'text/plain' => [
203+
'extension' => 'txt',
204+
'displayName' => $this->l10n->t('Text (.txt)'),
205+
],
206+
$documents['docx'] => [
207+
'extension' => 'docx',
208+
'displayName' => $this->l10n->t('Word Document (.docx)'),
209+
],
210+
$documents['odt'] => [
211+
'extension' => 'odt',
212+
'displayName' => $this->l10n->t('OpenDocument Text (.odt)'),
213+
],
214+
$sheets['xlsx'] => [
215+
'extension' => 'xlsx',
216+
'displayName' => $this->l10n->t('Excel Workbook (.xlsx)'),
217+
],
218+
$sheets['ods'] => [
219+
'extension' => 'ods',
220+
'displayName' => $this->l10n->t('OpenDocument Spreadsheet (.ods)'),
221+
],
222+
$presentations['pptx'] => [
223+
'extension' => 'pptx',
224+
'displayName' => $this->l10n->t('PowerPoint Presentation (.pptx)'),
225+
],
226+
$presentations['odp'] => [
227+
'extension' => 'odp',
228+
'displayName' => $this->l10n->t('OpenDocument Presentation (.odp)'),
229+
],
230+
];
231+
}
232+
233+
private function getExtensionForMimeType(string $mimeType): ?string {
234+
foreach ($this->getTargetMimeTypes() as $targetMimeType => $targetMimeInfo) {
235+
if ($targetMimeType === $mimeType) {
236+
return $targetMimeInfo['extension'];
237+
}
238+
}
239+
240+
return null;
241+
}
242+
}

0 commit comments

Comments
 (0)