From e5cd8d2b590b9b7e3fb70c73738f68f28d3709b4 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 7964fb32fc3f1d57a7753d15c947ed67176f2439 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 916820dbc2a67cb4647b3179e4e3e0bcbb03e14d 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 e3b90e84349ae3daf93a3a8755a2ab09d50f2f53 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 63d0ea1e709f950ef26d5b55ae60706acc21d745 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 2e00e51677c8209eebbfd4b9616ab46ae4d6d410 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 6e51f64cd333fda51ae3a8172e4fd2b003839bcc 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 0570c1d942d5736cc42f9d57ffab464702bda4c5 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 dae8ac5accbb2818231551d6d31cf97fc3fdd526 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 );