Skip to content

Commit a747539

Browse files
Fix #254 - Embedding files can fail, when storage has multiple shared mounts
Signed-off-by: Christoph Bessei <28066477+christoph-bessei@users.noreply.github.com>
1 parent bafb235 commit a747539

2 files changed

Lines changed: 150 additions & 6 deletions

File tree

lib/Controller/QueueController.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -290,12 +290,17 @@ private function getFileSource(QueueFile $document, IRootFolder $rootFolder, Sto
290290
if (empty($mounts)) {
291291
throw new \Exception('Couldn\'t find any mounts for this storage');
292292
}
293-
$userId = $mounts[0]->getUser()->getUID();
294-
295-
try {
296-
$file = $rootFolder->getUserFolder($userId)->getFirstNodeById($document->getFileId());
297-
} catch (NotPermittedException $e) {
298-
throw new \Exception('Not allowed to get user folder');
293+
$file = null;
294+
foreach ($mounts as $mount) {
295+
$userId = $mount->getUser()->getUID();
296+
try {
297+
$file = $rootFolder->getUserFolder($userId)->getFirstNodeById($document->getFileId());
298+
} catch (NotPermittedException $e) {
299+
throw new \Exception('Not allowed to get user folder');
300+
}
301+
if ($file instanceof File) {
302+
break;
303+
}
299304
}
300305
if (!($file instanceof File)) {
301306
throw new \Exception('File not found or not a file');
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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 OCA\ContextChat\Tests;
11+
12+
use OCA\ContextChat\Controller\QueueController;
13+
use OCA\ContextChat\Db\QueueContentItemMapper;
14+
use OCA\ContextChat\Db\QueueFile;
15+
use OCA\ContextChat\Db\QueueMapper;
16+
use OCA\ContextChat\Service\ProviderConfigService;
17+
use OCA\ContextChat\Service\QueueService;
18+
use OCA\ContextChat\Service\StorageService;
19+
use OCP\AppFramework\Services\IAppConfig;
20+
use OCP\AppFramework\Utility\ITimeFactory;
21+
use OCP\BackgroundJob\IJobList;
22+
use OCP\Files\Config\ICachedMountInfo;
23+
use OCP\Files\Config\IUserMountCache;
24+
use OCP\Files\File;
25+
use OCP\Files\Folder;
26+
use OCP\Files\IRootFolder;
27+
use OCP\IRequest;
28+
use OCP\IUser;
29+
use PHPUnit\Framework\TestCase;
30+
use Psr\Log\LoggerInterface;
31+
32+
class QueueControllerTest extends TestCase {
33+
public function testDocumentIsResolvedUsingLaterMount(): void {
34+
$document = new QueueFile();
35+
$document->setId(7);
36+
$document->setFileId(42);
37+
$document->setStorageId(3);
38+
39+
$queueMapper = $this->createMock(QueueMapper::class);
40+
$queueMapper->expects($this->once())
41+
->method('getFromQueue')
42+
->with(1)
43+
->willReturn([$document]);
44+
$queueMapper->expects($this->once())
45+
->method('lock')
46+
->with(7)
47+
->willReturn(true);
48+
$queueMapper->expects($this->never())
49+
->method('delete');
50+
51+
$contentItemMapper = $this->createMock(QueueContentItemMapper::class);
52+
$contentItemMapper->expects($this->once())
53+
->method('getFromQueue')
54+
->with(1)
55+
->willReturn([]);
56+
57+
$wrongMount = $this->createMock(ICachedMountInfo::class);
58+
$wrongUser = $this->createMock(IUser::class);
59+
$wrongUser->method('getUID')->willReturn('wrong-user');
60+
$wrongMount->method('getUser')->willReturn($wrongUser);
61+
62+
$validMount = $this->createMock(ICachedMountInfo::class);
63+
$validUser = $this->createMock(IUser::class);
64+
$validUser->method('getUID')->willReturn('valid-user');
65+
$validMount->method('getUser')->willReturn($validUser);
66+
67+
$userMountCache = $this->createMock(IUserMountCache::class);
68+
$userMountCache->expects($this->once())
69+
->method('getMountsForStorageId')
70+
->with(3)
71+
->willReturn([$wrongMount, $validMount]);
72+
73+
$wrongFolder = $this->createMock(Folder::class);
74+
$wrongFolder->expects($this->once())
75+
->method('getFirstNodeById')
76+
->with(42)
77+
->willReturn(null);
78+
79+
$file = $this->createMock(File::class);
80+
$file->method('getId')->willReturn(42);
81+
$file->method('getInternalPath')->willReturn('files/Test-Text.md');
82+
$file->method('getMTime')->willReturn(1234567890);
83+
$file->method('getMimeType')->willReturn('text/markdown');
84+
$file->method('getSize')->willReturn(123);
85+
86+
$validFolder = $this->createMock(Folder::class);
87+
$validFolder->expects($this->once())
88+
->method('getFirstNodeById')
89+
->with(42)
90+
->willReturn($file);
91+
92+
$rootFolder = $this->createMock(IRootFolder::class);
93+
$rootFolder->expects($this->exactly(2))
94+
->method('getUserFolder')
95+
->willReturnMap([
96+
['wrong-user', $wrongFolder],
97+
['valid-user', $validFolder],
98+
]);
99+
100+
$storageService = $this->createMock(StorageService::class);
101+
$storageService->expects($this->once())
102+
->method('getUsersForFileId')
103+
->with(42)
104+
->willReturn(['valid-user']);
105+
106+
$controller = new QueueController(
107+
'context_chat',
108+
$this->createMock(IRequest::class),
109+
$this->createMock(LoggerInterface::class),
110+
$this->createMock(IAppConfig::class),
111+
$this->createMock(QueueService::class),
112+
$storageService,
113+
$this->createMock(IJobList::class),
114+
$this->createMock(ITimeFactory::class),
115+
$queueMapper,
116+
);
117+
118+
$response = $controller->getDocumentsQueueItems(
119+
$storageService,
120+
$rootFolder,
121+
$queueMapper,
122+
$contentItemMapper,
123+
$userMountCache,
124+
1,
125+
);
126+
127+
$data = $response->getData();
128+
$this->assertEquals([
129+
'userIds' => ['valid-user'],
130+
'reference' => ProviderConfigService::getSourceId(42),
131+
'title' => 'files/Test-Text.md',
132+
'content' => null,
133+
'modified' => 1234567890,
134+
'type' => 'text/markdown',
135+
'provider' => ProviderConfigService::getDefaultProviderKey(),
136+
'size' => 123,
137+
], ((array)$data['files'])[7]->jsonSerialize());
138+
}
139+
}

0 commit comments

Comments
 (0)