mirror of
https://github.com/LibreSign/libresign.git
synced 2025-12-18 05:20:45 +01:00
Merge pull request #6163 from LibreSign/refactor/move-status-validation-to-sequential-service
refactor: move status validation to sequential service
This commit is contained in:
commit
b2044c630a
2 changed files with 112 additions and 3 deletions
|
|
@ -208,6 +208,7 @@ class RequestSignatureService {
|
||||||
foreach ($data['users'] as $user) {
|
foreach ($data['users'] as $user) {
|
||||||
$userProvidedOrder = isset($user['signingOrder']) ? (int)$user['signingOrder'] : null;
|
$userProvidedOrder = isset($user['signingOrder']) ? (int)$user['signingOrder'] : null;
|
||||||
$signingOrder = $this->sequentialSigningService->determineSigningOrder($userProvidedOrder);
|
$signingOrder = $this->sequentialSigningService->determineSigningOrder($userProvidedOrder);
|
||||||
|
$signerStatus = $user['status'] ?? null;
|
||||||
|
|
||||||
if (isset($user['identifyMethods'])) {
|
if (isset($user['identifyMethods'])) {
|
||||||
foreach ($user['identifyMethods'] as $identifyMethod) {
|
foreach ($user['identifyMethods'] as $identifyMethod) {
|
||||||
|
|
@ -221,6 +222,7 @@ class RequestSignatureService {
|
||||||
fileId: $fileId,
|
fileId: $fileId,
|
||||||
signingOrder: $signingOrder,
|
signingOrder: $signingOrder,
|
||||||
fileStatus: $fileStatus,
|
fileStatus: $fileStatus,
|
||||||
|
signerStatus: $signerStatus,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -232,6 +234,7 @@ class RequestSignatureService {
|
||||||
fileId: $fileId,
|
fileId: $fileId,
|
||||||
signingOrder: $signingOrder,
|
signingOrder: $signingOrder,
|
||||||
fileStatus: $fileStatus,
|
fileStatus: $fileStatus,
|
||||||
|
signerStatus: $signerStatus,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -254,6 +257,7 @@ class RequestSignatureService {
|
||||||
int $fileId,
|
int $fileId,
|
||||||
int $signingOrder = 0,
|
int $signingOrder = 0,
|
||||||
?int $fileStatus = null,
|
?int $fileStatus = null,
|
||||||
|
?int $signerStatus = null,
|
||||||
): SignRequestEntity {
|
): SignRequestEntity {
|
||||||
$identifyMethodsIncances = $this->identifyMethod->getByUserData($identifyMethods);
|
$identifyMethodsIncances = $this->identifyMethod->getByUserData($identifyMethods);
|
||||||
if (empty($identifyMethodsIncances)) {
|
if (empty($identifyMethodsIncances)) {
|
||||||
|
|
@ -272,8 +276,8 @@ class RequestSignatureService {
|
||||||
$currentStatus = $signRequest->getStatusEnum();
|
$currentStatus = $signRequest->getStatusEnum();
|
||||||
|
|
||||||
if ($isNewSignRequest || $currentStatus === \OCA\Libresign\Enum\SignRequestStatus::DRAFT) {
|
if ($isNewSignRequest || $currentStatus === \OCA\Libresign\Enum\SignRequestStatus::DRAFT) {
|
||||||
$initialStatus = $this->determineInitialStatus($signingOrder, $fileStatus);
|
$desiredStatus = $this->determineInitialStatus($signingOrder, $fileStatus, $signerStatus, $currentStatus, $fileId);
|
||||||
$signRequest->setStatusEnum($initialStatus);
|
$this->updateStatusIfAllowed($signRequest, $currentStatus, $desiredStatus, $isNewSignRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->saveSignRequest($signRequest);
|
$this->saveSignRequest($signRequest);
|
||||||
|
|
@ -288,13 +292,56 @@ class RequestSignatureService {
|
||||||
return $signRequest;
|
return $signRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function determineInitialStatus(int $signingOrder, ?int $fileStatus = null): \OCA\Libresign\Enum\SignRequestStatus {
|
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 ($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;
|
||||||
|
}
|
||||||
|
|
||||||
// If fileStatus is explicitly DRAFT (0), keep signer as DRAFT
|
// 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
|
// This allows adding new signers in DRAFT mode even when file is not in DRAFT status
|
||||||
if ($fileStatus === FileEntity::STATUS_DRAFT) {
|
if ($fileStatus === FileEntity::STATUS_DRAFT) {
|
||||||
return \OCA\Libresign\Enum\SignRequestStatus::DRAFT;
|
return \OCA\Libresign\Enum\SignRequestStatus::DRAFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
return \OCA\Libresign\Enum\SignRequestStatus::ABLE_TO_SIGN;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->sequentialSigningService->isOrderedNumericFlow()) {
|
if (!$this->sequentialSigningService->isOrderedNumericFlow()) {
|
||||||
return \OCA\Libresign\Enum\SignRequestStatus::ABLE_TO_SIGN;
|
return \OCA\Libresign\Enum\SignRequestStatus::ABLE_TO_SIGN;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -170,4 +170,66 @@ class SequentialSigningService {
|
||||||
|
|
||||||
return SignatureFlow::from($value);
|
return SignatureFlow::from($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there are signers with lower signing order that haven't signed yet
|
||||||
|
*/
|
||||||
|
public function hasPendingLowerOrderSigners(int $fileId, int $currentOrder): bool {
|
||||||
|
$signRequests = $this->signRequestMapper->getByFileId($fileId);
|
||||||
|
|
||||||
|
foreach ($signRequests as $signRequest) {
|
||||||
|
$order = $signRequest->getSigningOrder();
|
||||||
|
$status = $signRequest->getStatusEnum();
|
||||||
|
|
||||||
|
// If a signer with lower order hasn't signed yet, return true
|
||||||
|
if ($order < $currentOrder && $status !== SignRequestStatus::SIGNED) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if changing from currentStatus to desiredStatus is an upgrade (or same level)
|
||||||
|
* Status hierarchy: DRAFT (0) < ABLE_TO_SIGN (1) < SIGNED (2)
|
||||||
|
*/
|
||||||
|
public function isStatusUpgrade(
|
||||||
|
SignRequestStatus $currentStatus,
|
||||||
|
SignRequestStatus $desiredStatus,
|
||||||
|
): bool {
|
||||||
|
return $desiredStatus->value >= $currentStatus->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate if a signer can transition to ABLE_TO_SIGN status based on signing order
|
||||||
|
* In ordered numeric flow, prevents skipping ahead if lower-order signers haven't signed
|
||||||
|
*
|
||||||
|
* @param SignRequestStatus $desiredStatus The status being requested
|
||||||
|
* @param int $signingOrder The signer's order
|
||||||
|
* @param int $fileId The file ID
|
||||||
|
* @return SignRequestStatus The validated status (may return DRAFT if validation fails)
|
||||||
|
*/
|
||||||
|
public function validateStatusByOrder(
|
||||||
|
SignRequestStatus $desiredStatus,
|
||||||
|
int $signingOrder,
|
||||||
|
int $fileId,
|
||||||
|
): SignRequestStatus {
|
||||||
|
// Only validate for ordered numeric flow
|
||||||
|
if (!$this->isOrderedNumericFlow()) {
|
||||||
|
return $desiredStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only validate when trying to set ABLE_TO_SIGN and not the first signer
|
||||||
|
if ($desiredStatus !== SignRequestStatus::ABLE_TO_SIGN || $signingOrder <= 1) {
|
||||||
|
return $desiredStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any lower order signers haven't signed yet
|
||||||
|
if ($this->hasPendingLowerOrderSigners($fileId, $signingOrder)) {
|
||||||
|
return SignRequestStatus::DRAFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $desiredStatus;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue