From 2c2629764f348f87bb5f3e37482f318efc297368 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Mon, 5 Jan 2026 18:09:22 -0300 Subject: [PATCH 1/3] feat: Add support for nodeId validation in ValidateHelper Support validating files by Nextcloud nodeId in addition to LibreSign fileId. This enables creating signature requests for files that haven't been registered in LibreSign yet. The validateFile method now accepts 'nodeId' parameter and validates it similarly to 'fileId', ensuring the file exists and has the correct MIME type. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- lib/Helper/ValidateHelper.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/Helper/ValidateHelper.php b/lib/Helper/ValidateHelper.php index ac4b1d55e8..876fd4bd88 100644 --- a/lib/Helper/ValidateHelper.php +++ b/lib/Helper/ValidateHelper.php @@ -125,6 +125,17 @@ public function validateFile(array $data, int $type = self::TYPE_TO_SIGN, ?IUser } $this->validateIfNodeIdExists((int)$data['file']['fileId'], $data['userManager']->getUID(), $type); $this->validateMimeTypeAcceptedByNodeId((int)$data['file']['fileId'], $data['userManager']->getUID(), $type); + } elseif (!empty($data['file']['nodeId'])) { + if (!is_numeric($data['file']['nodeId'])) { + throw new LibresignException($this->l10n->t('File type: %s. Invalid fileID.', [$this->getTypeOfFile($type)])); + } + if (!is_a($user, IUser::class)) { + if (!is_a($data['userManager'], IUser::class)) { + throw new LibresignException($this->l10n->t('User not found.')); + } + } + $this->validateIfNodeIdExists((int)$data['file']['nodeId'], $data['userManager']->getUID(), $type); + $this->validateMimeTypeAcceptedByNodeId((int)$data['file']['nodeId'], $data['userManager']->getUID(), $type); } elseif (!empty($data['file']['base64'])) { $this->validateBase64($data['file']['base64'], $type); } elseif (!empty($data['file']['path'])) { From 1865bdb8b825a3dc1a75516cf76ca3c314369e38 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Mon, 5 Jan 2026 18:09:57 -0300 Subject: [PATCH 2/3] feat: Add nodeId support in FileService.getNodeFromData Enable FileService to retrieve nodes using Nextcloud nodeId in addition to LibreSign fileId. This allows the service to handle both registered LibreSign files and new Nextcloud files in the same workflow. The method now checks for 'nodeId' after 'fileId' and 'path', maintaining backward compatibility while adding new functionality. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- lib/Service/FileService.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Service/FileService.php b/lib/Service/FileService.php index be8211173a..2a5fca7151 100644 --- a/lib/Service/FileService.php +++ b/lib/Service/FileService.php @@ -115,6 +115,9 @@ public function getNodeFromData(array $data): Node { if (isset($data['file']['path'])) { return $this->folderService->getFileByPath($data['file']['path']); } + if (isset($data['file']['nodeId'])) { + return $this->folderService->getFileByNodeId($data['file']['nodeId']); + } $content = $this->getFileRaw($data); $extension = $this->getExtension($content); From 3504b683d539628ae2b556f3f9328921adba5d04 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Mon, 5 Jan 2026 18:10:25 -0300 Subject: [PATCH 3/3] test: Add unit tests for nodeId validation support Add comprehensive test coverage for: - ValidateHelper nodeId validation (success, invalid nodeId, missing user) - FileService nodeId-based node retrieval - Precedence of fileId over nodeId when both are provided These tests ensure the new nodeId functionality works correctly while maintaining backward compatibility with existing fileId behavior. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- lib/Helper/ValidateHelper.php | 2 +- tests/php/Unit/Helper/ValidateHelperTest.php | 41 +++++++++++ tests/php/Unit/Service/FileServiceTest.php | 72 ++++++++++++++++++++ 3 files changed, 114 insertions(+), 1 deletion(-) diff --git a/lib/Helper/ValidateHelper.php b/lib/Helper/ValidateHelper.php index 876fd4bd88..39bd95b9ba 100644 --- a/lib/Helper/ValidateHelper.php +++ b/lib/Helper/ValidateHelper.php @@ -130,7 +130,7 @@ public function validateFile(array $data, int $type = self::TYPE_TO_SIGN, ?IUser throw new LibresignException($this->l10n->t('File type: %s. Invalid fileID.', [$this->getTypeOfFile($type)])); } if (!is_a($user, IUser::class)) { - if (!is_a($data['userManager'], IUser::class)) { + if (!isset($data['userManager']) || !is_a($data['userManager'], IUser::class)) { throw new LibresignException($this->l10n->t('User not found.')); } } diff --git a/tests/php/Unit/Helper/ValidateHelperTest.php b/tests/php/Unit/Helper/ValidateHelperTest.php index 7b29c6bff8..28f2aface7 100644 --- a/tests/php/Unit/Helper/ValidateHelperTest.php +++ b/tests/php/Unit/Helper/ValidateHelperTest.php @@ -135,6 +135,47 @@ public function testValidateNewFileUsingFileIdWithSuccess():void { $this->assertNull($actual); } + public function testValidateNewFileUsingNodeIdWithSuccess():void { + $file = $this->createMock(\OCP\Files\File::class); + $file + ->method('getMimeType') + ->willReturn('application/pdf'); + $this->root + ->method('getUserFolder') + ->willReturn($this->root); + $this->root + ->method('getFirstNodeById') + ->willReturn($file); + + $user = $this->createMock(\OCP\IUser::class); + $user->method('getUID')->willReturn('john.doe'); + $actual = $this->getValidateHelper()->validateNewFile([ + 'file' => ['nodeId' => 35523], + 'name' => 'test', + 'userManager' => $user, + ]); + $this->assertNull($actual); + } + + public function testValidateFileWithInvalidNodeId():void { + $this->expectExceptionMessage('Invalid fileID'); + $user = $this->createMock(\OCP\IUser::class); + $user->method('getUID')->willReturn('john.doe'); + $this->getValidateHelper()->validateFile([ + 'file' => ['nodeId' => 'invalid'], + 'name' => 'test', + 'userManager' => $user, + ]); + } + + public function testValidateFileWithNodeIdWithoutUser():void { + $this->expectExceptionMessage('User not found'); + $this->getValidateHelper()->validateFile([ + 'file' => ['nodeId' => 35523], + 'name' => 'test', + ]); + } + public function testValidateNotRequestedSignWhenAlreadyAskedToSignThisDocument():void { $this->signRequestMapper->method('getByNodeId')->willReturn('exists'); $this->expectExceptionMessage('Already asked to sign this document'); diff --git a/tests/php/Unit/Service/FileServiceTest.php b/tests/php/Unit/Service/FileServiceTest.php index 62fdf48b69..c8324f0109 100644 --- a/tests/php/Unit/Service/FileServiceTest.php +++ b/tests/php/Unit/Service/FileServiceTest.php @@ -88,4 +88,76 @@ public function testSetFileByIdSetsFile(): void { $this->assertInstanceOf(FileService::class, $returned); $this->assertSame(1, $service->getStatus()); } + + public function testGetNodeFromDataWithNodeId(): void { + $node = $this->createMock(\OCP\Files\File::class); + $folderService = $this->createMock(\OCA\Libresign\Service\FolderService::class); + $folderService->method('getUserId')->willReturn('testuser'); + $folderService->method('getFileByNodeId')->with(35523)->willReturn($node); + + $userManager = $this->createMock(\OCP\IUser::class); + $userManager->method('getUID')->willReturn('testuser'); + + $service = $this->createFileService([ + \OCA\Libresign\Service\FolderService::class => $folderService, + ]); + + $data = [ + 'file' => ['nodeId' => 35523], + 'userManager' => $userManager, + ]; + + $result = $service->getNodeFromData($data); + $this->assertSame($node, $result); + } + + public function testGetNodeFromDataWithFileId(): void { + $node = $this->createMock(\OCP\Files\File::class); + $folderService = $this->createMock(\OCA\Libresign\Service\FolderService::class); + $folderService->method('getUserId')->willReturn('testuser'); + $folderService->method('getFileByNodeId')->with(12345)->willReturn($node); + + $userManager = $this->createMock(\OCP\IUser::class); + $userManager->method('getUID')->willReturn('testuser'); + + $service = $this->createFileService([ + \OCA\Libresign\Service\FolderService::class => $folderService, + ]); + + $data = [ + 'file' => ['fileId' => 12345], + 'userManager' => $userManager, + ]; + + $result = $service->getNodeFromData($data); + $this->assertSame($node, $result); + } + + public function testGetNodeFromDataPrefersFileIdOverNodeId(): void { + $nodeFromFileId = $this->createMock(\OCP\Files\File::class); + $folderService = $this->createMock(\OCA\Libresign\Service\FolderService::class); + $folderService->method('getUserId')->willReturn('testuser'); + $folderService->expects($this->once()) + ->method('getFileByNodeId') + ->with(12345) + ->willReturn($nodeFromFileId); + + $userManager = $this->createMock(\OCP\IUser::class); + $userManager->method('getUID')->willReturn('testuser'); + + $service = $this->createFileService([ + \OCA\Libresign\Service\FolderService::class => $folderService, + ]); + + $data = [ + 'file' => [ + 'fileId' => 12345, + 'nodeId' => 35523, // This should be ignored + ], + 'userManager' => $userManager, + ]; + + $result = $service->getNodeFromData($data); + $this->assertSame($nodeFromFileId, $result); + } }