Skip to content

Commit e91d64f

Browse files
authored
Merge pull request #6035 from nextcloud/backport/5973/stable32
[stable32] fix: pass language to Collabora file conversions
2 parents 964a993 + 749db7e commit e91d64f

4 files changed

Lines changed: 187 additions & 5 deletions

File tree

lib/Conversion/ConversionProvider.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,18 @@ public function convertFile(File $file, string $targetMimeType): mixed {
142142
));
143143
}
144144

145-
return $this->remoteService->convertFileTo($file, $targetFileExtension);
145+
return $this->remoteService->convertFileTo(
146+
$file,
147+
$targetFileExtension,
148+
conversionOptions: ['lang' => $this->getConversionLanguage()]
149+
);
150+
}
151+
152+
private function getConversionLanguage(): string {
153+
$locale = $this->l10n->getLocaleCode();
154+
$language = $locale !== '' ? $locale : $this->l10n->getLanguageCode();
155+
156+
return str_replace('_', '-', $language);
146157
}
147158

148159
private function getMimeProvidersFor(array $inputMimeTypes, string $outputMimeType): array {

lib/Service/RemoteService.php

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,28 @@ public function fetchTargetThumbnail(File $file, string $target): ?string {
5656
}
5757

5858
/**
59+
* @param array<string, string> $conversionOptions
5960
* @return resource|string
6061
*/
61-
public function convertFileTo(File $file, string $format, int $timeout = RemoteOptionsService::REMOTE_TIMEOUT_DEFAULT) {
62+
public function convertFileTo(
63+
File $file,
64+
string $format,
65+
int $timeout = RemoteOptionsService::REMOTE_TIMEOUT_DEFAULT,
66+
array $conversionOptions = [],
67+
) {
6268
$fileName = $file->getStorage()->getLocalFile($file->getInternalPath());
6369
$stream = fopen($fileName, 'rb');
6470

6571
if ($stream === false) {
6672
throw new Exception('Failed to open stream');
6773
}
6874

69-
return $this->convertTo($file->getName(), $stream, $format, [], $timeout);
75+
return $this->convertTo($file->getName(), $stream, $format, $conversionOptions, $timeout);
7076
}
7177

7278
/**
7379
* @param resource $stream
80+
* @param array<string, string>|null $conversionOptions
7481
* @return resource|string
7582
*/
7683
public function convertTo(string $filename, $stream, string $format, ?array $conversionOptions = [], int $timeout = RemoteOptionsService::REMOTE_TIMEOUT_DEFAULT) {
@@ -84,13 +91,20 @@ public function convertTo(string $filename, $stream, string $format, ?array $con
8491
}
8592

8693
$options['multipart'] = [
87-
array_merge([
94+
[
8895
'name' => $filename,
8996
'filename' => $filename,
9097
'contents' => $stream
91-
], $conversionOptions),
98+
],
9299
];
93100

101+
foreach ($conversionOptions ?? [] as $name => $contents) {
102+
$options['multipart'][] = [
103+
'name' => (string)$name,
104+
'contents' => $contents,
105+
];
106+
}
107+
94108
try {
95109
$response = $client->post($this->appConfig->getCollaboraUrlInternal() . '/cool/convert-to/' . $format, $options);
96110
$body = $response->getBody();
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace Tests\Richdocuments\Conversion;
11+
12+
use OCA\Richdocuments\Conversion\ConversionProvider;
13+
use OCA\Richdocuments\Service\RemoteOptionsService;
14+
use OCA\Richdocuments\Service\RemoteService;
15+
use OCA\Richdocuments\Service\SecureViewService;
16+
use OCP\Files\File;
17+
use OCP\IL10N;
18+
use OCP\L10N\IFactory;
19+
use PHPUnit\Framework\MockObject\MockObject;
20+
use PHPUnit\Framework\TestCase;
21+
use Psr\Log\LoggerInterface;
22+
23+
class ConversionProviderTest extends TestCase {
24+
private RemoteService&MockObject $remoteService;
25+
private LoggerInterface&MockObject $logger;
26+
private IFactory&MockObject $l10nFactory;
27+
private IL10N&MockObject $l10n;
28+
private SecureViewService&MockObject $secureViewService;
29+
private ConversionProvider $provider;
30+
31+
protected function setUp(): void {
32+
parent::setUp();
33+
34+
$this->remoteService = $this->createMock(RemoteService::class);
35+
$this->logger = $this->createMock(LoggerInterface::class);
36+
$this->l10nFactory = $this->createMock(IFactory::class);
37+
$this->l10n = $this->createMock(IL10N::class);
38+
$this->secureViewService = $this->createMock(SecureViewService::class);
39+
40+
$this->l10n->method('t')->willReturnCallback(static fn (string $text): string => $text);
41+
$this->l10nFactory->method('get')
42+
->with('richdocuments')
43+
->willReturn($this->l10n);
44+
45+
$this->provider = new ConversionProvider(
46+
$this->remoteService,
47+
$this->logger,
48+
$this->l10nFactory,
49+
$this->secureViewService,
50+
);
51+
}
52+
53+
public function testConvertFilePassesCurrentLocaleToCollabora(): void {
54+
$file = $this->createMock(File::class);
55+
56+
$this->l10n->expects($this->once())
57+
->method('getLocaleCode')
58+
->willReturn('de_DE');
59+
$this->secureViewService->method('isEnabled')
60+
->willReturn(false);
61+
$this->remoteService->expects($this->once())
62+
->method('convertFileTo')
63+
->with($file, 'pdf', RemoteOptionsService::REMOTE_TIMEOUT_DEFAULT, ['lang' => 'de-DE'])
64+
->willReturn('pdf-content');
65+
66+
$result = $this->provider->convertFile($file, 'application/pdf');
67+
68+
$this->assertSame('pdf-content', $result);
69+
}
70+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace Tests\Richdocuments\Service;
11+
12+
use OCA\Richdocuments\AppConfig;
13+
use OCA\Richdocuments\Service\CapabilitiesService;
14+
use OCA\Richdocuments\Service\RemoteService;
15+
use OCP\Http\Client\IClient;
16+
use OCP\Http\Client\IClientService;
17+
use OCP\Http\Client\IResponse;
18+
use PHPUnit\Framework\MockObject\MockObject;
19+
use PHPUnit\Framework\TestCase;
20+
use Psr\Log\LoggerInterface;
21+
22+
class RemoteServiceTest extends TestCase {
23+
private AppConfig&MockObject $appConfig;
24+
private IClientService&MockObject $clientService;
25+
private IClient&MockObject $client;
26+
private CapabilitiesService&MockObject $capabilitiesService;
27+
private LoggerInterface&MockObject $logger;
28+
private RemoteService $service;
29+
30+
protected function setUp(): void {
31+
parent::setUp();
32+
33+
$this->appConfig = $this->createMock(AppConfig::class);
34+
$this->clientService = $this->createMock(IClientService::class);
35+
$this->client = $this->createMock(IClient::class);
36+
$this->capabilitiesService = $this->createMock(CapabilitiesService::class);
37+
$this->logger = $this->createMock(LoggerInterface::class);
38+
39+
$this->clientService->method('newClient')
40+
->willReturn($this->client);
41+
42+
$this->service = new RemoteService(
43+
$this->appConfig,
44+
$this->clientService,
45+
$this->capabilitiesService,
46+
$this->logger,
47+
);
48+
}
49+
50+
public function testConvertToSendsConversionOptionsAsMultipartFields(): void {
51+
$stream = fopen('php://memory', 'r+');
52+
$response = $this->createMock(IResponse::class);
53+
54+
$this->appConfig->method('getCollaboraUrlInternal')
55+
->willReturn('http://cool.example');
56+
$this->appConfig->method('getDisableCertificateValidation')
57+
->willReturn(false);
58+
$response->method('getBody')
59+
->willReturn('converted-content');
60+
61+
$this->client->expects($this->once())
62+
->method('post')
63+
->with(
64+
'http://cool.example/cool/convert-to/pdf',
65+
$this->callback(function (array $options) use ($stream): bool {
66+
$this->assertSame([
67+
[
68+
'name' => 'document.xlsx',
69+
'filename' => 'document.xlsx',
70+
'contents' => $stream,
71+
],
72+
[
73+
'name' => 'lang',
74+
'contents' => 'de-DE',
75+
],
76+
], $options['multipart']);
77+
78+
return true;
79+
})
80+
)
81+
->willReturn($response);
82+
83+
$result = $this->service->convertTo('document.xlsx', $stream, 'pdf', ['lang' => 'de-DE']);
84+
85+
$this->assertSame('converted-content', $result);
86+
}
87+
}

0 commit comments

Comments
 (0)