Skip to content

Commit b09a16a

Browse files
authored
Merge pull request #6169 from LibreSign/feat/file-level-signature-flow
feat: file level signature flow
2 parents c05b15a + e97580b commit b09a16a

22 files changed

+357
-34
lines changed

lib/Controller/RequestSignatureController.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public function __construct(
5656
* @param string $name The name of file to sign
5757
* @param string|null $callback URL that will receive a POST after the document is signed
5858
* @param integer|null $status Numeric code of status * 0 - no signers * 1 - signed * 2 - pending
59+
* @param string|null $signatureFlow Signature flow mode: 'parallel' or 'ordered_numeric'. If not provided, uses global configuration
5960
* @return DataResponse<Http::STATUS_OK, array{data: LibresignValidateFile, message: string}, array{}>|DataResponse<Http::STATUS_UNPROCESSABLE_ENTITY, array{message?: string, action?: integer, errors?: list<array{message: string, title?: string}>}, array{}>
6061
*
6162
* 200: OK
@@ -65,15 +66,23 @@ public function __construct(
6566
#[NoCSRFRequired]
6667
#[RequireManager]
6768
#[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/request-signature', requirements: ['apiVersion' => '(v1)'])]
68-
public function request(array $file, array $users, string $name, ?string $callback = null, ?int $status = 1): DataResponse {
69+
public function request(
70+
array $file,
71+
array $users,
72+
string $name,
73+
?string $callback = null,
74+
?int $status = 1,
75+
?string $signatureFlow = null,
76+
): DataResponse {
6977
$user = $this->userSession->getUser();
7078
$data = [
7179
'file' => $file,
7280
'name' => $name,
7381
'users' => $users,
7482
'status' => $status,
7583
'callback' => $callback,
76-
'userManager' => $user
84+
'userManager' => $user,
85+
'signatureFlow' => $signatureFlow,
7786
];
7887
try {
7988
$this->requestSignatureService->validateNewRequestToFile($data);

lib/Db/File.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
namespace OCA\Libresign\Db;
1010

11+
use OCA\Libresign\Enum\SignatureFlow;
1112
use OCP\AppFramework\Db\Entity;
1213
use OCP\DB\Types;
1314

@@ -38,6 +39,8 @@
3839
* @method ?array getMetadata()
3940
* @method void setModificationStatus(int $modificationStatus)
4041
* @method int getModificationStatus()
42+
* @method void setSignatureFlow(int $signatureFlow)
43+
* @method int getSignatureFlow()
4144
*/
4245
class File extends Entity {
4346
protected int $nodeId = 0;
@@ -52,6 +55,7 @@ class File extends Entity {
5255
protected ?string $callback = null;
5356
protected ?array $metadata = null;
5457
protected int $modificationStatus = 0;
58+
protected int $signatureFlow = SignatureFlow::NUMERIC_PARALLEL;
5559
public const STATUS_NOT_LIBRESIGN_FILE = -1;
5660
public const STATUS_DRAFT = 0;
5761
public const STATUS_ABLE_TO_SIGN = 1;
@@ -78,6 +82,7 @@ public function __construct() {
7882
$this->addType('status', Types::INTEGER);
7983
$this->addType('metadata', Types::JSON);
8084
$this->addType('modificationStatus', Types::SMALLINT);
85+
$this->addType('signatureFlow', Types::SMALLINT);
8186
}
8287

8388
public function isDeletedAccount(): bool {
@@ -89,4 +94,12 @@ public function getUserId(): string {
8994
$metadata = $this->getMetadata();
9095
return $metadata['deleted_account']['account'] ?? $this->userId ?? '';
9196
}
97+
98+
public function getSignatureFlowEnum(): \OCA\Libresign\Enum\SignatureFlow {
99+
return \OCA\Libresign\Enum\SignatureFlow::fromNumeric($this->signatureFlow);
100+
}
101+
102+
public function setSignatureFlowEnum(\OCA\Libresign\Enum\SignatureFlow $flow): void {
103+
$this->setSignatureFlow($flow->toNumeric());
104+
}
92105
}

lib/Db/SignRequestMapper.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace OCA\Libresign\Db;
1010

1111
use DateTimeInterface;
12+
use OCA\Libresign\Enum\SignatureFlow;
1213
use OCA\Libresign\Enum\SignRequestStatus;
1314
use OCA\Libresign\Helper\Pagination;
1415
use OCA\Libresign\Service\IdentifyMethod\IIdentifyMethod;
@@ -500,6 +501,7 @@ private function getFilesAssociatedFilesWithMeQueryBuilder(string $userId, array
500501
'f.status',
501502
'f.metadata',
502503
'f.created_at',
504+
'f.signature_flow',
503505
)
504506
->groupBy(
505507
'f.id',
@@ -510,6 +512,7 @@ private function getFilesAssociatedFilesWithMeQueryBuilder(string $userId, array
510512
'f.name',
511513
'f.status',
512514
'f.created_at',
515+
'f.signature_flow',
513516
);
514517
// metadata is a json column, the right way is to use f.metadata::text
515518
// when the database is PostgreSQL. The problem is that the command
@@ -620,11 +623,13 @@ private function formatListRow(array $row): array {
620623
$row['nodeId'] = (int)$row['node_id'];
621624

622625
$row['name'] = $this->removeExtensionFromName($row['name'], $row['metadata']);
626+
$row['signatureFlow'] = SignatureFlow::fromNumeric((int)($row['signature_flow']))->value;
623627

624628
unset(
625629
$row['user_id'],
626630
$row['node_id'],
627631
$row['signed_node_id'],
632+
$row['signature_flow'],
628633
);
629634
return $row;
630635
}

lib/Enum/SignatureFlow.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,22 @@
1515
enum SignatureFlow: string {
1616
case PARALLEL = 'parallel';
1717
case ORDERED_NUMERIC = 'ordered_numeric';
18+
19+
public const NUMERIC_PARALLEL = 1;
20+
public const NUMERIC_ORDERED_NUMERIC = 2;
21+
22+
public function toNumeric(): int {
23+
return match($this) {
24+
self::PARALLEL => self::NUMERIC_PARALLEL,
25+
self::ORDERED_NUMERIC => self::NUMERIC_ORDERED_NUMERIC,
26+
};
27+
}
28+
29+
public static function fromNumeric(int $value): self {
30+
return match($value) {
31+
self::NUMERIC_PARALLEL => self::PARALLEL,
32+
self::NUMERIC_ORDERED_NUMERIC => self::ORDERED_NUMERIC,
33+
default => throw new \ValueError("Invalid numeric value for SignatureFlow: $value"),
34+
};
35+
}
1836
}

lib/Migration/Version15000Date20251209000000.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace OCA\Libresign\Migration;
1010

1111
use Closure;
12+
use OCA\Libresign\Enum\SignatureFlow;
1213
use OCP\DB\ISchemaWrapper;
1314
use OCP\DB\QueryBuilder\IQueryBuilder;
1415
use OCP\DB\Types;
@@ -56,6 +57,17 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
5657
}
5758
}
5859

60+
if ($schema->hasTable('libresign_file')) {
61+
$tableFile = $schema->getTable('libresign_file');
62+
if (!$tableFile->hasColumn('signature_flow')) {
63+
$tableFile->addColumn('signature_flow', Types::SMALLINT, [
64+
'notnull' => true,
65+
'default' => SignatureFlow::NUMERIC_PARALLEL,
66+
'comment' => 'Signature flow mode: 1=parallel, 2=ordered_numeric',
67+
]);
68+
}
69+
}
70+
5971
return $schema;
6072
}
6173

lib/ResponseDefinitions.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@
186186
* status: 0|1|2|3|4,
187187
* statusText: string,
188188
* nodeId: non-negative-int,
189+
* signatureFlow: int,
189190
* totalPages: non-negative-int,
190191
* size: non-negative-int,
191192
* pdfVersion: string,

lib/Service/FileService.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ private function loadLibreSignData(): void {
711711
$this->fileData->created_at = $this->file->getCreatedAt()->format(DateTimeInterface::ATOM);
712712
$this->fileData->statusText = $this->fileMapper->getTextOfStatus($this->file->getStatus());
713713
$this->fileData->nodeId = $this->file->getNodeId();
714+
$this->fileData->signatureFlow = $this->file->getSignatureFlow();
714715

715716
$this->fileData->requested_by = [
716717
'userId' => $this->file->getUserId(),

lib/Service/RequestSignatureService.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,22 @@
88

99
namespace OCA\Libresign\Service;
1010

11+
use OCA\Libresign\AppInfo\Application;
1112
use OCA\Libresign\Db\File as FileEntity;
1213
use OCA\Libresign\Db\FileElementMapper;
1314
use OCA\Libresign\Db\FileMapper;
1415
use OCA\Libresign\Db\IdentifyMethodMapper;
1516
use OCA\Libresign\Db\SignRequest as SignRequestEntity;
1617
use OCA\Libresign\Db\SignRequestMapper;
18+
use OCA\Libresign\Enum\SignatureFlow;
1719
use OCA\Libresign\Handler\DocMdpHandler;
1820
use OCA\Libresign\Helper\ValidateHelper;
1921
use OCA\Libresign\Service\IdentifyMethod\IIdentifyMethod;
2022
use OCP\AppFramework\Db\DoesNotExistException;
2123
use OCP\Files\IMimeTypeDetector;
2224
use OCP\Files\Node;
2325
use OCP\Http\Client\IClientService;
26+
use OCP\IAppConfig;
2427
use OCP\IL10N;
2528
use OCP\IUser;
2629
use OCP\IUserManager;
@@ -47,6 +50,7 @@ public function __construct(
4750
protected DocMdpHandler $docMdpHandler,
4851
protected LoggerInterface $logger,
4952
protected SequentialSigningService $sequentialSigningService,
53+
protected IAppConfig $appConfig,
5054
) {
5155
}
5256

@@ -56,6 +60,7 @@ public function save(array $data): FileEntity {
5660
if (!isset($data['status'])) {
5761
$data['status'] = $file->getStatus();
5862
}
63+
$this->sequentialSigningService->setFile($file);
5964
$this->associateToSigners($data, $file->getId());
6065
return $file;
6166
}
@@ -106,10 +111,28 @@ public function saveFile(array $data): FileEntity {
106111
} else {
107112
$file->setStatus(FileEntity::STATUS_ABLE_TO_SIGN);
108113
}
114+
115+
if (isset($data['signatureFlow']) && is_string($data['signatureFlow'])) {
116+
try {
117+
$signatureFlow = \OCA\Libresign\Enum\SignatureFlow::from($data['signatureFlow']);
118+
$file->setSignatureFlowEnum($signatureFlow);
119+
} catch (\ValueError) {
120+
$this->setSignatureFlowFromGlobalConfig($file);
121+
}
122+
} else {
123+
$this->setSignatureFlowFromGlobalConfig($file);
124+
}
125+
109126
$this->fileMapper->insert($file);
110127
return $file;
111128
}
112129

130+
private function setSignatureFlowFromGlobalConfig(FileEntity $file): void {
131+
$globalFlowValue = $this->appConfig->getValueString(Application::APP_ID, 'signature_flow', SignatureFlow::PARALLEL->value);
132+
$globalFlow = SignatureFlow::from($globalFlowValue);
133+
$file->setSignatureFlowEnum($globalFlow);
134+
}
135+
113136
private function updateStatus(FileEntity $file, int $status): FileEntity {
114137
if ($status > $file->getStatus()) {
115138
$file->setStatus($status);

lib/Service/SequentialSigningService.php

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88

99
namespace OCA\Libresign\Service;
1010

11-
use OCA\Libresign\AppInfo\Application;
11+
use OCA\Libresign\Db\File as FileEntity;
1212
use OCA\Libresign\Db\SignRequestMapper;
1313
use OCA\Libresign\Enum\SignatureFlow;
1414
use OCA\Libresign\Enum\SignRequestStatus;
1515
use OCP\IAppConfig;
1616

1717
class SequentialSigningService {
1818
private int $currentOrder = 1;
19+
private ?FileEntity $file = null;
1920

2021
public function __construct(
2122
private IAppConfig $appConfig,
@@ -24,9 +25,11 @@ public function __construct(
2425
) {
2526
}
2627

27-
/**
28-
* Check if ordered numeric flow is enabled
29-
*/
28+
public function setFile(FileEntity $file): self {
29+
$this->file = $file;
30+
return $this;
31+
}
32+
3033
public function isOrderedNumericFlow(): bool {
3134
return $this->getSignatureFlow() === SignatureFlow::ORDERED_NUMERIC;
3235
}
@@ -51,8 +54,8 @@ public function determineSigningOrder(?int $userProvidedOrder): int {
5154
}
5255

5356
if ($userProvidedOrder !== null) {
54-
if ($userProvidedOrder > $this->currentOrder) {
55-
$this->currentOrder = $userProvidedOrder;
57+
if ($userProvidedOrder >= $this->currentOrder) {
58+
$this->currentOrder = $userProvidedOrder + 1;
5659
}
5760
return $userProvidedOrder;
5861
}
@@ -162,13 +165,10 @@ private function activateSignersForOrder(array $signRequests, int $order): void
162165
}
163166

164167
private function getSignatureFlow(): SignatureFlow {
165-
$value = $this->appConfig->getValueString(
166-
Application::APP_ID,
167-
'signature_flow',
168-
SignatureFlow::PARALLEL->value
169-
);
170-
171-
return SignatureFlow::from($value);
168+
if ($this->file === null) {
169+
throw new \LogicException('File must be set before calling getSignatureFlow(). Call setFile() first.');
170+
}
171+
return $this->file->getSignatureFlowEnum();
172172
}
173173

174174
/**

lib/Service/SignFileService.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -380,10 +380,12 @@ protected function updateSignRequest(string $hash): void {
380380

381381
$this->signRequestMapper->update($this->signRequest);
382382

383-
$this->sequentialSigningService->releaseNextOrder(
384-
$this->signRequest->getFileId(),
385-
$this->signRequest->getSigningOrder()
386-
);
383+
$this->sequentialSigningService
384+
->setFile($this->libreSignFile)
385+
->releaseNextOrder(
386+
$this->signRequest->getFileId(),
387+
$this->signRequest->getSigningOrder()
388+
);
387389
}
388390

389391
protected function updateLibreSignFile(string $hash): void {

0 commit comments

Comments
 (0)