Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.83% covered (success)
97.83%
45 / 46
88.89% covered (warning)
88.89%
8 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
StatusService
97.83% covered (success)
97.83%
45 / 46
88.89% covered (warning)
88.89%
8 / 9
25
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 shouldNotifySignRequest
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 canNotifySignRequest
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 cacheFileStatus
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 updateStatusIfAllowed
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
4
 determineInitialStatus
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
6
 determineStatusForAbleToSignFile
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 handleExplicitSignerStatus
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 getDefaultStatusByFlow
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2025 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service\SignRequest;
10
11use OCA\Libresign\Db\File as FileEntity;
12use OCA\Libresign\Db\SignRequest as SignRequestEntity;
13use OCA\Libresign\Enum\FileStatus;
14use OCA\Libresign\Enum\ParticipantRole;
15use OCA\Libresign\Enum\SignRequestStatus;
16use OCA\Libresign\Service\FileStatusService;
17use OCA\Libresign\Service\SequentialSigningService;
18
19class StatusService {
20    public function __construct(
21        private SequentialSigningService $sequentialSigningService,
22        private FileStatusService $fileStatusService,
23        private StatusCacheService $statusCacheService,
24        private StatusUpdatePolicy $statusUpdatePolicy,
25    ) {
26    }
27
28    public function shouldNotifySignRequest(SignRequestStatus $signRequestStatus, ?int $fileStatus): bool {
29        return $this->fileStatusService->canNotifySigners($fileStatus)
30            && $this->canNotifySignRequest($signRequestStatus);
31    }
32
33    public function canNotifySignRequest(SignRequestStatus $status): bool {
34        return $status === SignRequestStatus::ABLE_TO_SIGN
35            || $status === SignRequestStatus::OBSERVING;
36    }
37
38    public function cacheFileStatus(FileEntity $file): void {
39        $this->statusCacheService->setStatus($file->getUuid(), $file->getStatus());
40    }
41
42    public function updateStatusIfAllowed(
43        SignRequestEntity $signRequest,
44        SignRequestStatus $currentStatus,
45        SignRequestStatus $desiredStatus,
46        bool $isNewSignRequest,
47    ): void {
48        $isStatusUpgrade = !$isNewSignRequest
49            ? $this->sequentialSigningService->isStatusUpgrade($currentStatus, $desiredStatus)
50            : false;
51        $isOrderedNumericFlow = $this->sequentialSigningService->isOrderedNumericFlow();
52        $hasPendingLowerOrderSigners = $isOrderedNumericFlow
53            ? $this->sequentialSigningService->hasPendingLowerOrderSigners(
54                $signRequest->getFileId(),
55                $signRequest->getSigningOrder()
56            )
57            : false;
58
59        if ($this->statusUpdatePolicy->shouldUpdateStatus(
60            $currentStatus,
61            $desiredStatus,
62            $isNewSignRequest,
63            $isStatusUpgrade,
64            $isOrderedNumericFlow,
65            $hasPendingLowerOrderSigners,
66        )) {
67            $signRequest->setStatusEnum($desiredStatus);
68        }
69    }
70
71    public function determineInitialStatus(
72        int $signingOrder,
73        int $fileId,
74        ?int $fileStatus = null,
75        ?int $signerStatus = null,
76        ?SignRequestStatus $currentStatus = null,
77        ParticipantRole $participantRole = ParticipantRole::SIGNER,
78    ): SignRequestStatus {
79        if ($participantRole === ParticipantRole::OBSERVER) {
80            if ($fileStatus === FileStatus::DRAFT->value) {
81                return SignRequestStatus::DRAFT;
82            }
83
84            return SignRequestStatus::OBSERVING;
85        }
86
87        if ($fileStatus === FileStatus::DRAFT->value) {
88            return SignRequestStatus::DRAFT;
89        }
90
91        if ($fileStatus === FileStatus::ABLE_TO_SIGN->value) {
92            return $this->determineStatusForAbleToSignFile($signingOrder);
93        }
94
95        if ($signerStatus !== null) {
96            return $this->handleExplicitSignerStatus($signerStatus, $signingOrder, $fileId, $currentStatus);
97        }
98
99        return $this->getDefaultStatusByFlow($signingOrder);
100    }
101
102    private function determineStatusForAbleToSignFile(int $signingOrder): SignRequestStatus {
103        if ($this->sequentialSigningService->isOrderedNumericFlow()) {
104            return $signingOrder === 1 ? SignRequestStatus::ABLE_TO_SIGN : SignRequestStatus::DRAFT;
105        }
106        return SignRequestStatus::ABLE_TO_SIGN;
107    }
108
109    private function handleExplicitSignerStatus(
110        int $signerStatus,
111        int $signingOrder,
112        int $fileId,
113        ?SignRequestStatus $currentStatus,
114    ): SignRequestStatus {
115        $desiredStatus = SignRequestStatus::from($signerStatus);
116
117        if ($currentStatus !== null && !$this->sequentialSigningService->isStatusUpgrade($currentStatus, $desiredStatus)) {
118            return $currentStatus;
119        }
120
121        return $this->sequentialSigningService->validateStatusByOrder($desiredStatus, $signingOrder, $fileId);
122    }
123
124    private function getDefaultStatusByFlow(int $signingOrder): SignRequestStatus {
125        if (!$this->sequentialSigningService->isOrderedNumericFlow()) {
126            return SignRequestStatus::ABLE_TO_SIGN;
127        }
128
129        return $signingOrder === 1 ? SignRequestStatus::ABLE_TO_SIGN : SignRequestStatus::DRAFT;
130    }
131}