From 46605a24f279b5e47ff32f80918e5997340c563b Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 28 Apr 2025 10:37:30 +0200 Subject: [PATCH 1/3] enh(api): indicate missing file owner in create response Files without an owner such as federated shares cannot receive attachments as the attachment would need to be stored in the owners user folder. Signed-off-by: Max --- lib/Service/ApiService.php | 3 ++ tests/unit/Service/ApiServiceTest.php | 78 +++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 tests/unit/Service/ApiServiceTest.php diff --git a/lib/Service/ApiService.php b/lib/Service/ApiService.php index 2ae85a22a13..972990243b6 100644 --- a/lib/Service/ApiService.php +++ b/lib/Service/ApiService.php @@ -141,6 +141,8 @@ public function create(?int $fileId = null, ?string $filePath = null, ?string $b $lockInfo = null; } + $hasOwner = $file->getOwner() !== null; + if (!$readOnly) { $isLocked = $this->documentService->lock($file->getId()); if (!$isLocked) { @@ -155,6 +157,7 @@ public function create(?int $fileId = null, ?string $filePath = null, ?string $b 'content' => $content, 'documentState' => $documentState, 'lock' => $lockInfo, + 'hasOwner' => $hasOwner, ]); } diff --git a/tests/unit/Service/ApiServiceTest.php b/tests/unit/Service/ApiServiceTest.php new file mode 100644 index 00000000000..83a4b848c84 --- /dev/null +++ b/tests/unit/Service/ApiServiceTest.php @@ -0,0 +1,78 @@ +request = $this->createMock(IRequest::class); + $this->configService = $this->createMock(ConfigService::class); + $this->sessionService = $this->createMock(SessionService::class); + $this->documentService = $this->createMock(DocumentService::class); + $this->encodingService = $this->createMock(EncodingService::class); + $this->loggerInterface = $this->createMock(LoggerInterface::class); + $this->l10n = $this->createMock(IL10N::class); + $this->userId = 'admin'; + + $document = new Document(); + $document->setId(123); + $this->documentService->method('getDocument')->willReturn($document); + $this->documentService->method('isReadOnly')->willReturn(false); + + $this->apiService = new ApiService( + $this->request, + $this->configService, + $this->sessionService, + $this->documentService, + $this->encodingService, + $this->loggerInterface, + $this->l10n, + $this->userId, + null, + ); + } + + public function testCreateNewSession() { + $file = $this->mockFile(1234, 'admin'); + $this->documentService->method('getFileById')->willReturn($file); + $actual = $this->apiService->create(1234); + self::assertTrue($actual->getData()['hasOwner']); + } + + public function testCreateNewSessionWithoutOwner() { + $file = $this->mockFile(1234, null); + $this->documentService->method('getFileById')->willReturn($file); + $actual = $this->apiService->create(1234); + self::assertFalse($actual->getData()['hasOwner']); + } + + private function mockFile(int $id, ?string $owner) { + $file = $this->createMock(\OCP\Files\File::class); + $storage = $this->createMock(\OCP\Files\Storage\IStorage::class); + $file->method('getStorage')->willReturn($storage); + $file->method('getId')->willReturn($id); + $file->method('getOwner')->willReturn($owner); + return $file; + } + +} From 20f7a9a358267c005b31482df43266aa345eaf2d Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 29 Apr 2025 13:11:30 +0200 Subject: [PATCH 2/3] enh(api): expose hasOwner in the SyncService Signed-off-by: Max --- src/services/SessionApi.js | 16 +++++++++++++++- src/services/SyncService.js | 4 ++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/services/SessionApi.js b/src/services/SessionApi.js index 2e020e37106..23b6ce78e8b 100644 --- a/src/services/SessionApi.js +++ b/src/services/SessionApi.js @@ -49,10 +49,19 @@ export class Connection { #session #lock #readOnly + #hasOwner #options constructor(response, options) { - const { document, session, lock, readOnly, content, documentState } = response.data + const { + document, + session, + lock, + readOnly, + content, + documentState, + hasOwner, + } = response.data this.#document = document this.#session = session this.#lock = lock @@ -60,6 +69,7 @@ export class Connection { this.#content = content this.#documentState = documentState this.#options = options + this.#hasOwner = hasOwner this.isPublic = !!options.shareToken this.closed = false } @@ -89,6 +99,10 @@ export class Connection { return this.closed } + get hasOwner() { + return this.#hasOwner + } + get #defaultParams() { return { documentId: this.#document.id, diff --git a/src/services/SyncService.js b/src/services/SyncService.js index 8b59eb53013..5d63d14daf3 100644 --- a/src/services/SyncService.js +++ b/src/services/SyncService.js @@ -88,6 +88,10 @@ class SyncService { return this.#connection.state.document.readOnly } + get hasOwner() { + return this.#connection?.hasOwner + } + get guestName() { return this.#connection.session.guestName } From 664edb88c01011a86688e7a134ae7247d1d0910c Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 30 Apr 2025 08:39:45 +0200 Subject: [PATCH 3/3] fix(attachments): disable upload without owner Signed-off-by: Max --- .../Menu/ActionAttachmentUpload.vue | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/components/Menu/ActionAttachmentUpload.vue b/src/components/Menu/ActionAttachmentUpload.vue index 87d7c62c6fc..4debc3b5bd8 100644 --- a/src/components/Menu/ActionAttachmentUpload.vue +++ b/src/components/Menu/ActionAttachmentUpload.vue @@ -6,7 +6,8 @@