From 45a39af440eb69fd57606420da7c7e6f0f9b09eb Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Sun, 14 Dec 2025 13:52:53 -0300 Subject: [PATCH 1/9] feat: add FileStatusService for file status operations Created dedicated service to handle file status management. Includes updateFileStatusIfUpgrade to upgrade file status and canNotifySigners to validate if file status allows notifications. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- lib/Service/FileStatusService.php | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 lib/Service/FileStatusService.php diff --git a/lib/Service/FileStatusService.php b/lib/Service/FileStatusService.php new file mode 100644 index 0000000000..b211bfe56a --- /dev/null +++ b/lib/Service/FileStatusService.php @@ -0,0 +1,32 @@ +getStatus(); + if ($newStatus > $currentStatus) { + $file->setStatus($newStatus); + $this->fileMapper->update($file); + } + return $file; + } + + public function canNotifySigners(?int $fileStatus): bool { + return $fileStatus === FileEntity::STATUS_ABLE_TO_SIGN; + } +} From 7b397e90840056f6151036cd005c92ab37056e1f Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Sun, 14 Dec 2025 13:53:02 -0300 Subject: [PATCH 2/9] feat: add SignRequestStatusService for sign request status logic Created dedicated service to manage sign request status determination and validation. Implements shouldNotifySignRequest, canNotifySignRequest, updateStatusIfAllowed, determineInitialStatus, and private helper methods for status calculation based on file status, signer status, signing order, and flow type (parallel/sequential). Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- lib/Service/SignRequestStatusService.php | 93 ++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 lib/Service/SignRequestStatusService.php diff --git a/lib/Service/SignRequestStatusService.php b/lib/Service/SignRequestStatusService.php new file mode 100644 index 0000000000..8c1dd81c70 --- /dev/null +++ b/lib/Service/SignRequestStatusService.php @@ -0,0 +1,93 @@ +fileStatusService->canNotifySigners($fileStatus) + && $this->canNotifySignRequest($signRequestStatus); + } + + public function canNotifySignRequest(SignRequestStatus $status): bool { + return $status === SignRequestStatus::ABLE_TO_SIGN; + } + + public function updateStatusIfAllowed( + SignRequestEntity $signRequest, + SignRequestStatus $currentStatus, + SignRequestStatus $desiredStatus, + bool $isNewSignRequest, + ): void { + if ($isNewSignRequest || $this->sequentialSigningService->isStatusUpgrade($currentStatus, $desiredStatus)) { + $signRequest->setStatusEnum($desiredStatus); + } + } + + public function determineInitialStatus( + int $signingOrder, + int $fileId, + ?int $fileStatus = null, + ?int $signerStatus = null, + ?SignRequestStatus $currentStatus = null, + ): SignRequestStatus { + if ($fileStatus === FileEntity::STATUS_DRAFT) { + return SignRequestStatus::DRAFT; + } + + if ($fileStatus === FileEntity::STATUS_ABLE_TO_SIGN) { + return $this->determineStatusForAbleToSignFile($signingOrder); + } + + if ($signerStatus !== null) { + return $this->handleExplicitSignerStatus($signerStatus, $signingOrder, $fileId, $currentStatus); + } + + return $this->getDefaultStatusByFlow($signingOrder); + } + + private function determineStatusForAbleToSignFile(int $signingOrder): SignRequestStatus { + if ($this->sequentialSigningService->isOrderedNumericFlow()) { + return $signingOrder === 1 ? SignRequestStatus::ABLE_TO_SIGN : SignRequestStatus::DRAFT; + } + return SignRequestStatus::ABLE_TO_SIGN; + } + + private function handleExplicitSignerStatus( + int $signerStatus, + int $signingOrder, + int $fileId, + ?SignRequestStatus $currentStatus, + ): SignRequestStatus { + $desiredStatus = SignRequestStatus::from($signerStatus); + + if ($currentStatus !== null && !$this->sequentialSigningService->isStatusUpgrade($currentStatus, $desiredStatus)) { + return $currentStatus; + } + + return $this->sequentialSigningService->validateStatusByOrder($desiredStatus, $signingOrder, $fileId); + } + + private function getDefaultStatusByFlow(int $signingOrder): SignRequestStatus { + if (!$this->sequentialSigningService->isOrderedNumericFlow()) { + return SignRequestStatus::ABLE_TO_SIGN; + } + + return $signingOrder === 1 ? SignRequestStatus::ABLE_TO_SIGN : SignRequestStatus::DRAFT; + } +} From c5d016cde89bb931fb140e0243f770d61a21d354 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Sun, 14 Dec 2025 13:53:09 -0300 Subject: [PATCH 3/9] refactor: extract status logic from RequestSignatureService Injected FileStatusService and SignRequestStatusService to delegate all status-related operations. Removed status determination methods and notification validation logic, delegating to specialized services. Updated method calls to use appropriate service methods. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- lib/Service/RequestSignatureService.php | 97 +++---------------------- 1 file changed, 12 insertions(+), 85 deletions(-) diff --git a/lib/Service/RequestSignatureService.php b/lib/Service/RequestSignatureService.php index 21497a265d..a57ec9b313 100644 --- a/lib/Service/RequestSignatureService.php +++ b/lib/Service/RequestSignatureService.php @@ -54,6 +54,8 @@ public function __construct( protected SequentialSigningService $sequentialSigningService, protected IAppConfig $appConfig, protected IEventDispatcher $eventDispatcher, + protected FileStatusService $fileStatusService, + protected SignRequestStatusService $signRequestStatusService, ) { } @@ -76,7 +78,7 @@ public function save(array $data): FileEntity { public function saveFile(array $data): FileEntity { if (!empty($data['uuid'])) { $file = $this->fileMapper->getByUuid($data['uuid']); - return $this->updateStatus($file, $data['status'] ?? 0); + return $this->fileStatusService->updateFileStatusIfUpgrade($file, $data['status'] ?? 0); } $fileId = null; if (isset($data['file']['fileNode']) && $data['file']['fileNode'] instanceof Node) { @@ -87,7 +89,7 @@ public function saveFile(array $data): FileEntity { if (!is_null($fileId)) { try { $file = $this->fileMapper->getByFileId($fileId); - return $this->updateStatus($file, $data['status'] ?? 0); + return $this->fileStatusService->updateFileStatusIfUpgrade($file, $data['status'] ?? 0); } catch (\Throwable) { } } @@ -136,15 +138,6 @@ private function setSignatureFlowFromGlobalConfig(FileEntity $file): void { $file->setSignatureFlowEnum($globalFlow); } - private function updateStatus(FileEntity $file, int $status): FileEntity { - if ($status > $file->getStatus()) { - $file->setStatus($status); - /** @var FileEntity */ - return $this->fileMapper->update($file); - } - return $file; - } - private function getFileMetadata(\OCP\Files\Node $node): array { $metadata = []; if ($extension = strtolower($node->getExtension())) { @@ -244,7 +237,7 @@ private function associateToSigners(array $data, int $fileId): array { ], displayName: $user['displayName'] ?? '', description: $user['description'] ?? '', - notify: empty($user['notify']) && $this->isStatusAbleToNotify($fileStatus), + notify: empty($user['notify']), fileId: $fileId, signingOrder: $signingOrder, fileStatus: $fileStatus, @@ -256,7 +249,7 @@ private function associateToSigners(array $data, int $fileId): array { identifyMethods: $user['identify'], displayName: $user['displayName'] ?? '', description: $user['description'] ?? '', - notify: empty($user['notify']) && $this->isStatusAbleToNotify($fileStatus), + notify: empty($user['notify']), fileId: $fileId, signingOrder: $signingOrder, fileStatus: $fileStatus, @@ -268,13 +261,6 @@ private function associateToSigners(array $data, int $fileId): array { return $return; } - private function isStatusAbleToNotify(?int $status): bool { - return in_array($status, [ - FileEntity::STATUS_ABLE_TO_SIGN, - FileEntity::STATUS_PARTIAL_SIGNED, - ]); - } - private function associateToSigner( array $identifyMethods, string $displayName, @@ -302,13 +288,16 @@ private function associateToSigner( $currentStatus = $signRequest->getStatusEnum(); if ($isNewSignRequest || $currentStatus === \OCA\Libresign\Enum\SignRequestStatus::DRAFT) { - $desiredStatus = $this->determineInitialStatus($signingOrder, $fileStatus, $signerStatus, $currentStatus, $fileId); - $this->updateStatusIfAllowed($signRequest, $currentStatus, $desiredStatus, $isNewSignRequest); + $desiredStatus = $this->signRequestStatusService->determineInitialStatus($signingOrder, $fileId, $fileStatus, $signerStatus, $currentStatus); + $this->signRequestStatusService->updateStatusIfAllowed($signRequest, $currentStatus, $desiredStatus, $isNewSignRequest); } $this->saveSignRequest($signRequest); - $shouldNotify = $notify && $signRequest->getStatusEnum() === \OCA\Libresign\Enum\SignRequestStatus::ABLE_TO_SIGN; + $shouldNotify = $notify && $this->signRequestStatusService->shouldNotifySignRequest( + $signRequest->getStatusEnum(), + $fileStatus + ); foreach ($identifyMethodsIncances as $identifyMethod) { $identifyMethod->getEntity()->setSignRequestId($signRequest->getId()); @@ -318,68 +307,6 @@ private function associateToSigner( return $signRequest; } - private function updateStatusIfAllowed( - SignRequestEntity $signRequest, - \OCA\Libresign\Enum\SignRequestStatus $currentStatus, - \OCA\Libresign\Enum\SignRequestStatus $desiredStatus, - bool $isNewSignRequest, - ): void { - if ($isNewSignRequest || $this->sequentialSigningService->isStatusUpgrade($currentStatus, $desiredStatus)) { - $signRequest->setStatusEnum($desiredStatus); - } - } - - private function determineInitialStatus( - int $signingOrder, - ?int $fileStatus = null, - ?int $signerStatus = null, - ?\OCA\Libresign\Enum\SignRequestStatus $currentStatus = null, - ?int $fileId = null, - ): \OCA\Libresign\Enum\SignRequestStatus { - // If fileStatus is explicitly DRAFT (0), keep signer as DRAFT - // This allows adding new signers in DRAFT mode even when file is not in DRAFT status - if ($fileStatus === FileEntity::STATUS_DRAFT) { - return \OCA\Libresign\Enum\SignRequestStatus::DRAFT; - } - - // If file status is ABLE_TO_SIGN, apply flow-based logic - if ($fileStatus === FileEntity::STATUS_ABLE_TO_SIGN) { - if ($this->sequentialSigningService->isOrderedNumericFlow()) { - // In ordered flow, only first signer (order 1) should be ABLE_TO_SIGN - // Others remain DRAFT until their turn - return $signingOrder === 1 - ? \OCA\Libresign\Enum\SignRequestStatus::ABLE_TO_SIGN - : \OCA\Libresign\Enum\SignRequestStatus::DRAFT; - } - // In parallel flow, all can sign - ignore individual signer status if file is ABLE_TO_SIGN - return \OCA\Libresign\Enum\SignRequestStatus::ABLE_TO_SIGN; - } - - // Handle explicit signer status when file status is not DRAFT or ABLE_TO_SIGN - if ($signerStatus !== null) { - $desiredStatus = \OCA\Libresign\Enum\SignRequestStatus::from($signerStatus); - if ($currentStatus !== null && !$this->sequentialSigningService->isStatusUpgrade($currentStatus, $desiredStatus)) { - return $currentStatus; - } - - // Validate status transition based on signing order - if ($fileId !== null) { - return $this->sequentialSigningService->validateStatusByOrder($desiredStatus, $signingOrder, $fileId); - } - - return $desiredStatus; - } - - // Default fallback based on flow type - if (!$this->sequentialSigningService->isOrderedNumericFlow()) { - return \OCA\Libresign\Enum\SignRequestStatus::ABLE_TO_SIGN; - } - - return $signingOrder === 1 - ? \OCA\Libresign\Enum\SignRequestStatus::ABLE_TO_SIGN - : \OCA\Libresign\Enum\SignRequestStatus::DRAFT; - } - /** * @param IIdentifyMethod[] $identifyMethodsIncances * @param string $displayName From 10a6af04f4bc5a86399ea30f7dd7302972c42464 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Sun, 14 Dec 2025 13:53:16 -0300 Subject: [PATCH 4/9] test: add comprehensive tests for FileStatusService Created test suite with 23 tests covering all file status upgrade scenarios and notification validation. Uses PHP 8 DataProvider attributes for parameterized testing. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .../Unit/Service/FileStatusServiceTest.php | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 tests/php/Unit/Service/FileStatusServiceTest.php diff --git a/tests/php/Unit/Service/FileStatusServiceTest.php b/tests/php/Unit/Service/FileStatusServiceTest.php new file mode 100644 index 0000000000..c8090c092b --- /dev/null +++ b/tests/php/Unit/Service/FileStatusServiceTest.php @@ -0,0 +1,91 @@ +fileMapper = $this->createMock(FileMapper::class); + $this->service = new FileStatusService($this->fileMapper); + } + + #[DataProvider('fileStatusUpgradeScenarios')] + public function testUpdateFileStatusIfUpgrade(int $currentStatus, int $newStatus, bool $shouldUpdate): void { + $file = new FileEntity(); + $file->setStatus($currentStatus); + + if ($shouldUpdate) { + $this->fileMapper->expects($this->once()) + ->method('update') + ->with($file) + ->willReturn($file); + } else { + $this->fileMapper->expects($this->never())->method('update'); + } + + $result = $this->service->updateFileStatusIfUpgrade($file, $newStatus); + + $expectedStatus = $shouldUpdate ? $newStatus : $currentStatus; + $this->assertEquals($expectedStatus, $result->getStatus()); + } + + public static function fileStatusUpgradeScenarios(): array { + $draft = FileEntity::STATUS_DRAFT; + $able = FileEntity::STATUS_ABLE_TO_SIGN; + $partial = FileEntity::STATUS_PARTIAL_SIGNED; + $signed = FileEntity::STATUS_SIGNED; + $deleted = FileEntity::STATUS_DELETED; + + return [ + [$draft, $able, true], + [$draft, $partial, true], + [$draft, $signed, true], + [$draft, $deleted, true], + [$able, $partial, true], + [$able, $signed, true], + [$able, $deleted, true], + [$partial, $signed, true], + [$partial, $deleted, true], + [$signed, $deleted, true], + [$able, $draft, false], + [$partial, $draft, false], + [$partial, $able, false], + [$signed, $draft, false], + [$signed, $able, false], + [$signed, $partial, false], + [$deleted, $draft, false], + ]; + } + + #[DataProvider('fileStatusNotificationScenarios')] + public function testCanNotifySigners(?int $fileStatus, bool $expected): void { + $result = $this->service->canNotifySigners($fileStatus); + $this->assertEquals($expected, $result); + } + + public static function fileStatusNotificationScenarios(): array { + return [ + [FileEntity::STATUS_DRAFT, false], + [FileEntity::STATUS_ABLE_TO_SIGN, true], + [FileEntity::STATUS_PARTIAL_SIGNED, false], + [FileEntity::STATUS_SIGNED, false], + [FileEntity::STATUS_DELETED, false], + [null, false], + ]; + } +} From dae155c5d26b5a949bfc437f1ba53ab8c4ce8709 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Sun, 14 Dec 2025 13:53:24 -0300 Subject: [PATCH 5/9] test: add comprehensive tests for SignRequestStatusService Created test suite with 53 tests validating business rules for sign request status determination. Covers notification scenarios, status updates, and initial status calculation based on file status, signer status, signing order, and flow type. Uses PHP 8 DataProvider attributes for parameterized testing. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .../Service/SignRequestStatusServiceTest.php | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 tests/php/Unit/Service/SignRequestStatusServiceTest.php diff --git a/tests/php/Unit/Service/SignRequestStatusServiceTest.php b/tests/php/Unit/Service/SignRequestStatusServiceTest.php new file mode 100644 index 0000000000..d4c39a3a62 --- /dev/null +++ b/tests/php/Unit/Service/SignRequestStatusServiceTest.php @@ -0,0 +1,201 @@ +sequentialSigningService = $this->createMock(SequentialSigningService::class); + $this->fileStatusService = $this->createMock(FileStatusService::class); + $this->service = new SignRequestStatusService( + $this->sequentialSigningService, + $this->fileStatusService + ); + } + + #[DataProvider('signRequestStatusNotificationScenarios')] + public function testCanNotifySignRequest(SignRequestStatus $status, bool $canNotify): void { + $this->assertSame($canNotify, $this->service->canNotifySignRequest($status)); + } + + public static function signRequestStatusNotificationScenarios(): array { + return [ + [SignRequestStatus::DRAFT, false], + [SignRequestStatus::ABLE_TO_SIGN, true], + [SignRequestStatus::SIGNED, false], + ]; + } + + #[DataProvider('shouldNotifyScenarios')] + public function testShouldNotifySignRequest( + SignRequestStatus $signRequestStatus, + ?int $fileStatus, + bool $fileCanNotify, + bool $signRequestCanNotify, + bool $expected, + ): void { + $this->fileStatusService + ->expects($this->once()) + ->method('canNotifySigners') + ->with($fileStatus) + ->willReturn($fileCanNotify); + + $result = $this->service->shouldNotifySignRequest($signRequestStatus, $fileStatus); + $this->assertSame($expected, $result); + } + + public static function shouldNotifyScenarios(): array { + return [ + [SignRequestStatus::ABLE_TO_SIGN, FileEntity::STATUS_ABLE_TO_SIGN, true, true, true], + [SignRequestStatus::ABLE_TO_SIGN, FileEntity::STATUS_DRAFT, false, true, false], + [SignRequestStatus::DRAFT, FileEntity::STATUS_ABLE_TO_SIGN, true, false, false], + [SignRequestStatus::SIGNED, FileEntity::STATUS_ABLE_TO_SIGN, true, false, false], + [SignRequestStatus::DRAFT, FileEntity::STATUS_DRAFT, false, false, false], + [SignRequestStatus::ABLE_TO_SIGN, null, false, true, false], + ]; + } + + #[DataProvider('signRequestStatusUpdateScenarios')] + public function testUpdateStatusIfAllowed( + SignRequestStatus $current, + SignRequestStatus $desired, + bool $isNew, + bool $isUpgrade, + bool $shouldUpdate, + ): void { + $signRequest = $this->createMock(SignRequestEntity::class); + + if (!$isNew) { + $this->sequentialSigningService + ->expects($this->once()) + ->method('isStatusUpgrade') + ->with($current, $desired) + ->willReturn($isUpgrade); + } + + $signRequest + ->expects($shouldUpdate ? $this->once() : $this->never()) + ->method('setStatusEnum') + ->with($desired); + + $this->service->updateStatusIfAllowed($signRequest, $current, $desired, $isNew); + } + + public static function signRequestStatusUpdateScenarios(): array { + $draft = SignRequestStatus::DRAFT; + $able = SignRequestStatus::ABLE_TO_SIGN; + $signed = SignRequestStatus::SIGNED; + + return [ + [$draft, $able, true, true, true], + [$draft, $signed, true, true, true], + [$able, $signed, true, true, true], + [$draft, $able, false, true, true], + [$draft, $signed, false, true, true], + [$able, $signed, false, true, true], + [$able, $draft, false, false, false], + [$signed, $draft, false, false, false], + [$signed, $able, false, false, false], + [$draft, $draft, false, false, false], + [$able, $able, false, false, false], + ]; + } + + #[DataProvider('initialStatusScenarios')] + public function testDetermineInitialStatus( + int $order, + int $fileId, + ?int $fileStatus, + ?int $signerStatus, + ?SignRequestStatus $currentStatus, + bool $isOrdered, + SignRequestStatus $expected, + ): void { + $this->sequentialSigningService->method('isOrderedNumericFlow')->willReturn($isOrdered); + + if ($signerStatus !== null && $currentStatus !== null) { + $desired = SignRequestStatus::from($signerStatus); + $this->sequentialSigningService + ->method('isStatusUpgrade') + ->with($currentStatus, $desired) + ->willReturn($expected !== $currentStatus); + } + + if ($signerStatus !== null) { + $desired = SignRequestStatus::from($signerStatus); + $this->sequentialSigningService + ->method('validateStatusByOrder') + ->with($desired, $order, $fileId) + ->willReturn($expected); + } + + $result = $this->service->determineInitialStatus($order, $fileId, $fileStatus, $signerStatus, $currentStatus); + $this->assertSame($expected, $result); + } + + public static function initialStatusScenarios(): array { + $draft = FileEntity::STATUS_DRAFT; + $able = FileEntity::STATUS_ABLE_TO_SIGN; + $draftStatus = SignRequestStatus::DRAFT; + $ableStatus = SignRequestStatus::ABLE_TO_SIGN; + $signedStatus = SignRequestStatus::SIGNED; + + return [ + [1, 123, $draft, null, null, false, $draftStatus], + [1, 123, $draft, null, null, true, $draftStatus], + [2, 123, $draft, null, null, false, $draftStatus], + [2, 123, $draft, null, null, true, $draftStatus], + [1, 123, $draft, $ableStatus->value, null, false, $draftStatus], + [1, 123, $draft, $ableStatus->value, null, true, $draftStatus], + + [1, 123, $able, null, null, false, $ableStatus], + [2, 123, $able, null, null, false, $ableStatus], + [3, 123, $able, null, null, false, $ableStatus], + [1, 123, $able, null, null, true, $ableStatus], + [2, 123, $able, null, null, true, $draftStatus], + [3, 123, $able, null, null, true, $draftStatus], + [10, 123, $able, null, null, true, $draftStatus], + [1, 123, $able, $draftStatus->value, null, false, $ableStatus], + [2, 123, $able, $draftStatus->value, null, false, $ableStatus], + [1, 123, $able, $draftStatus->value, null, true, $ableStatus], + [2, 123, $able, $draftStatus->value, null, true, $draftStatus], + + [1, 123, null, $ableStatus->value, null, false, $ableStatus], + [1, 123, null, $ableStatus->value, null, true, $ableStatus], + [1, 123, null, $draftStatus->value, null, false, $draftStatus], + [1, 123, null, $signedStatus->value, null, false, $signedStatus], + [2, 123, null, $ableStatus->value, null, true, $ableStatus], + [2, 123, null, $ableStatus->value, null, false, $ableStatus], + + [1, 123, null, $ableStatus->value, $draftStatus, false, $ableStatus], + [1, 123, null, $draftStatus->value, $ableStatus, false, $ableStatus], + [1, 123, null, $ableStatus->value, $ableStatus, false, $ableStatus], + + [1, 123, null, null, null, false, $ableStatus], + [2, 123, null, null, null, false, $ableStatus], + [10, 123, null, null, null, false, $ableStatus], + [1, 123, null, null, null, true, $ableStatus], + [2, 123, null, null, null, true, $draftStatus], + [3, 123, null, null, null, true, $draftStatus], + [10, 123, null, null, null, true, $draftStatus], + ]; + } +} From 3d56b37d1250d151ba999d9d9b7f1e094a5501e9 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Sun, 14 Dec 2025 13:53:33 -0300 Subject: [PATCH 6/9] test: update RequestSignatureService tests for new architecture Updated tests to inject FileStatusService and SignRequestStatusService mocks. Added specific tests validating parallel and ordered flow behavior with correct parameter ordering for determineInitialStatus. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .../Service/RequestSignatureServiceTest.php | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/tests/php/Unit/Service/RequestSignatureServiceTest.php b/tests/php/Unit/Service/RequestSignatureServiceTest.php index 2631680b1f..da78cc2579 100644 --- a/tests/php/Unit/Service/RequestSignatureServiceTest.php +++ b/tests/php/Unit/Service/RequestSignatureServiceTest.php @@ -14,11 +14,13 @@ use OCA\Libresign\Handler\DocMdpHandler; use OCA\Libresign\Helper\ValidateHelper; use OCA\Libresign\Service\FileElementService; +use OCA\Libresign\Service\FileStatusService; use OCA\Libresign\Service\FolderService; use OCA\Libresign\Service\IdentifyMethodService; use OCA\Libresign\Service\PdfParserService; use OCA\Libresign\Service\RequestSignatureService; use OCA\Libresign\Service\SequentialSigningService; +use OCA\Libresign\Service\SignRequestStatusService; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\IMimeTypeDetector; use OCP\Http\Client\IClient; @@ -52,6 +54,8 @@ final class RequestSignatureServiceTest extends \OCA\Libresign\Tests\Unit\TestCa private SequentialSigningService&MockObject $sequentialSigningService; private IAppConfig&MockObject $appConfig; private IEventDispatcher&MockObject $eventDispatcher; + private FileStatusService&MockObject $fileStatusService; + private SignRequestStatusService&MockObject $signRequestStatusService; public function setUp(): void { parent::setUp(); @@ -79,6 +83,8 @@ public function setUp(): void { $this->sequentialSigningService = $this->createMock(SequentialSigningService::class); $this->appConfig = $this->createMock(IAppConfig::class); $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->fileStatusService = $this->createMock(FileStatusService::class); + $this->signRequestStatusService = $this->createMock(SignRequestStatusService::class); } private function getService(?SequentialSigningService $sequentialSigningService = null): RequestSignatureService { @@ -101,6 +107,8 @@ private function getService(?SequentialSigningService $sequentialSigningService $sequentialSigningService ?? $this->sequentialSigningService, $this->appConfig, $this->eventDispatcher, + $this->fileStatusService, + $this->signRequestStatusService, ); } @@ -261,22 +269,21 @@ public function testParallelFlowIgnoresSignerDraftStatusWhenFileIsAbleToSign(): ->method('isOrderedNumericFlow') ->willReturn(false); // Parallel flow + $fileStatusService = $this->createMock(FileStatusService::class); + $statusService = new SignRequestStatusService($sequentialSigningService, $fileStatusService); + // File status is ABLE_TO_SIGN (1) $fileStatus = \OCA\Libresign\Db\File::STATUS_ABLE_TO_SIGN; // Signer status is DRAFT (0) - as sent by frontend $signerStatus = \OCA\Libresign\Enum\SignRequestStatus::DRAFT->value; - $result = self::invokePrivate( - $this->getService($sequentialSigningService), - 'determineInitialStatus', - [ - 1, // signingOrder - $fileStatus, - $signerStatus, - null, // currentStatus - null, // fileId - ] + $result = $statusService->determineInitialStatus( + 1, // signingOrder + 123, // fileId + $fileStatus, + $signerStatus, + null, // currentStatus ); // In parallel flow with ABLE_TO_SIGN file status, signer should be ABLE_TO_SIGN @@ -296,14 +303,15 @@ public function testOrderedFlowRespectsSigningOrderWhenFileIsAbleToSign(): void ->method('isOrderedNumericFlow') ->willReturn(true); // Ordered flow + $fileStatusService = $this->createMock(FileStatusService::class); + $statusService = new SignRequestStatusService($sequentialSigningService, $fileStatusService); + $fileStatus = \OCA\Libresign\Db\File::STATUS_ABLE_TO_SIGN; $signerStatus = \OCA\Libresign\Enum\SignRequestStatus::DRAFT->value; // First signer (order 1) should be ABLE_TO_SIGN - $result1 = self::invokePrivate( - $this->getService($sequentialSigningService), - 'determineInitialStatus', - [1, $fileStatus, $signerStatus, null, null] + $result1 = $statusService->determineInitialStatus( + 1, 123, $fileStatus, $signerStatus, null ); $this->assertEquals( \OCA\Libresign\Enum\SignRequestStatus::ABLE_TO_SIGN, @@ -312,10 +320,8 @@ public function testOrderedFlowRespectsSigningOrderWhenFileIsAbleToSign(): void ); // Second signer (order 2) should remain DRAFT - $result2 = self::invokePrivate( - $this->getService($sequentialSigningService), - 'determineInitialStatus', - [2, $fileStatus, $signerStatus, null, null] + $result2 = $statusService->determineInitialStatus( + 2, 123, $fileStatus, $signerStatus, null ); $this->assertEquals( \OCA\Libresign\Enum\SignRequestStatus::DRAFT, From 5926d3ba7546e7809c185fdfcf96adcfe171c636 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Sun, 14 Dec 2025 13:53:52 -0300 Subject: [PATCH 7/9] fix: cs Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- tests/php/Unit/Service/SignRequestStatusServiceTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/php/Unit/Service/SignRequestStatusServiceTest.php b/tests/php/Unit/Service/SignRequestStatusServiceTest.php index d4c39a3a62..6ed07746fb 100644 --- a/tests/php/Unit/Service/SignRequestStatusServiceTest.php +++ b/tests/php/Unit/Service/SignRequestStatusServiceTest.php @@ -7,7 +7,6 @@ */ use OCA\Libresign\Db\File as FileEntity; -use OCA\Libresign\Db\FileMapper; use OCA\Libresign\Db\SignRequest as SignRequestEntity; use OCA\Libresign\Enum\SignRequestStatus; use OCA\Libresign\Service\FileStatusService; From 22a17a3d7af5f391f89f3ff4663df6d7a6bf7abf Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Sun, 14 Dec 2025 13:59:46 -0300 Subject: [PATCH 8/9] refactor: remove unused IAppConfig dependency from SequentialSigningService IAppConfig was injected but never used in any method. Removed dependency to clean up constructor. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- lib/Service/SequentialSigningService.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/Service/SequentialSigningService.php b/lib/Service/SequentialSigningService.php index 43109d189b..d02ccb590f 100644 --- a/lib/Service/SequentialSigningService.php +++ b/lib/Service/SequentialSigningService.php @@ -12,14 +12,12 @@ use OCA\Libresign\Db\SignRequestMapper; use OCA\Libresign\Enum\SignatureFlow; use OCA\Libresign\Enum\SignRequestStatus; -use OCP\IAppConfig; class SequentialSigningService { private int $currentOrder = 1; private ?FileEntity $file = null; public function __construct( - private IAppConfig $appConfig, private SignRequestMapper $signRequestMapper, private IdentifyMethodService $identifyMethodService, ) { From 81e5a16e81e176c2f95deb511e7c26881f7bc46a Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Sun, 14 Dec 2025 13:59:59 -0300 Subject: [PATCH 9/9] test: update SequentialSigningServiceTest after IAppConfig removal Removed IAppConfig mock from test setup to match updated service constructor signature. Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- tests/php/Unit/Service/SequentialSigningServiceTest.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/php/Unit/Service/SequentialSigningServiceTest.php b/tests/php/Unit/Service/SequentialSigningServiceTest.php index 5025f51589..f7a0d8a330 100644 --- a/tests/php/Unit/Service/SequentialSigningServiceTest.php +++ b/tests/php/Unit/Service/SequentialSigningServiceTest.php @@ -14,24 +14,20 @@ use OCA\Libresign\Service\IdentifyMethodService; use OCA\Libresign\Service\SequentialSigningService; use OCA\Libresign\Tests\Unit\TestCase; -use OCP\IAppConfig; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; final class SequentialSigningServiceTest extends TestCase { - private IAppConfig&MockObject $appConfig; private SignRequestMapper&MockObject $signRequestMapper; private IdentifyMethodService&MockObject $identifyMethodService; private SequentialSigningService $service; public function setUp(): void { parent::setUp(); - $this->appConfig = $this->createMock(IAppConfig::class); $this->signRequestMapper = $this->createMock(SignRequestMapper::class); $this->identifyMethodService = $this->createMock(IdentifyMethodService::class); $this->service = new SequentialSigningService( - $this->appConfig, $this->signRequestMapper, $this->identifyMethodService );