From 4ec71478e081bcab328a69dcae53a19e80eeec17 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 3ae5ece8ca60de2b4032bb1f019685bf5df6038c 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 fc0c6295d5c988ad1b450a880735a782e60ebc82 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); + } }