Skip to content

Commit 8e10b39

Browse files
committed
feat(envelope): add FileElementService dependency and visibleElements support
- Add FileElementService as constructor dependency - Support visibleElements in envelope child files - Format visible elements using FileElementService - Add comprehensive unit tests for envelope scenarios Tests cover: - Child files without certificate chain - Child files with visibleElements - Child files without visibleElements when not requested - Multiple signers in child files This enables proper visible element handling in envelope child files, preparing for full envelope support. Signed-off-by: Vitor Mattos <[email protected]>
1 parent c4469db commit 8e10b39

2 files changed

Lines changed: 207 additions & 21 deletions

File tree

lib/Service/File/EnvelopeAssembler.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use OCA\Libresign\Db\File;
1414
use OCA\Libresign\Db\FileMapper;
1515
use OCA\Libresign\Db\SignRequestMapper;
16+
use OCA\Libresign\Service\FileElementService;
1617
use OCA\Libresign\Service\IdentifyMethodService;
1718
use OCP\Files\IRootFolder;
1819
use Psr\Log\LoggerInterface;
@@ -27,6 +28,7 @@ public function __construct(
2728
private ?CertificateChainService $certificateChainService,
2829
private \OCA\Libresign\Handler\SignEngine\Pkcs12Handler $pkcs12Handler,
2930
private LoggerInterface $logger,
31+
private FileElementService $fileElementService,
3032
) {
3133
}
3234

@@ -40,6 +42,7 @@ public function buildEnvelopeChildData(File $childFile, \OCA\Libresign\Service\F
4042
$fileData->nodeId = $childFile->getNodeId();
4143
$fileData->metadata = $childFile->getMetadata();
4244
$fileData->signers = [];
45+
$fileData->visibleElements = [];
4346

4447
$signRequests = $this->signRequestMapper->getByFileId($childFile->getId());
4548
foreach ($signRequests as $signRequest) {
@@ -76,6 +79,19 @@ public function buildEnvelopeChildData(File $childFile, \OCA\Libresign\Service\F
7679
$fileData->signers[] = $signer;
7780
}
7881

82+
if ($options->isShowVisibleElements()) {
83+
$childMetadata = $childFile->getMetadata();
84+
foreach ($this->signRequestMapper->getVisibleElementsFromSigners($signRequests) as $row) {
85+
if (empty($row)) {
86+
continue;
87+
}
88+
$fileData->visibleElements = array_merge(
89+
$this->fileElementService->formatVisibleElements($row, $childMetadata),
90+
$fileData->visibleElements
91+
);
92+
}
93+
}
94+
7995
if ($options->isValidateFile() && $childFile->getSignedNodeId()) {
8096
try {
8197
$fileNode = $this->root->getUserFolder($childFile->getUserId())->getFirstNodeById($childFile->getSignedNodeId());

tests/php/Unit/Service/File/EnvelopeAssemblerTest.php

Lines changed: 191 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,70 @@
99
namespace OCA\Libresign\Tests\Unit\Service\File;
1010

1111
use OCA\Libresign\Db\File as DbFile;
12+
use OCA\Libresign\Db\FileMapper;
1213
use OCA\Libresign\Db\SignRequest as DbSignRequest;
14+
use OCA\Libresign\Db\SignRequestMapper;
15+
use OCA\Libresign\Handler\SignEngine\Pkcs12Handler;
1316
use OCA\Libresign\Service\File\EnvelopeAssembler;
1417
use OCA\Libresign\Service\File\FileResponseOptions;
18+
use OCA\Libresign\Service\File\SignersLoader;
19+
use OCA\Libresign\Service\FileElementService;
1520
use OCA\Libresign\Service\IdentifyMethodService;
1621
use OCP\Files\IRootFolder;
22+
use PHPUnit\Framework\MockObject\MockObject;
1723
use Psr\Log\NullLogger;
1824

1925
final class EnvelopeAssemblerTest extends \OCA\Libresign\Tests\Unit\TestCase {
26+
private SignRequestMapper&MockObject $signRequestMapper;
27+
private IdentifyMethodService&MockObject $identifyMethodService;
28+
private FileMapper&MockObject $fileMapper;
29+
private IRootFolder&MockObject $root;
30+
private SignersLoader&MockObject $signersLoader;
31+
private Pkcs12Handler&MockObject $pkcs12Handler;
32+
private FileElementService&MockObject $fileElementService;
33+
34+
public function setUp(): void {
35+
parent::setUp();
36+
$this->signRequestMapper = $this->createMock(SignRequestMapper::class);
37+
$this->identifyMethodService = $this->createMock(IdentifyMethodService::class);
38+
$this->fileMapper = $this->createMock(FileMapper::class);
39+
$this->root = $this->createMock(IRootFolder::class);
40+
$this->signersLoader = $this->createMock(SignersLoader::class);
41+
$this->pkcs12Handler = $this->createMock(Pkcs12Handler::class);
42+
$this->fileElementService = $this->createMock(FileElementService::class);
43+
}
44+
45+
private function getService(): EnvelopeAssembler {
46+
return new EnvelopeAssembler(
47+
$this->signRequestMapper,
48+
$this->identifyMethodService,
49+
$this->fileMapper,
50+
$this->root,
51+
$this->signersLoader,
52+
null,
53+
$this->pkcs12Handler,
54+
new NullLogger(),
55+
$this->fileElementService
56+
);
57+
}
58+
2059
public function testBuildsChildDataWithoutCertificateChain(): void {
2160
$signRequest = new DbSignRequest();
2261
$signRequest->setId(42);
2362
$signRequest->setSigned(null);
2463
$signRequest->setDisplayName('Alice');
2564
$signRequest->setStatus(1);
2665

27-
$signRequestMapper = $this->createMock(\OCA\Libresign\Db\SignRequestMapper::class);
28-
$signRequestMapper->method('getByFileId')->willReturn([$signRequest]);
29-
30-
$identify = $this->createMock(IdentifyMethodService::class);
31-
$identify->method('setIsRequest')->willReturnSelf();
32-
$identify->method('getIdentifyMethodsFromSignRequestId')->willReturn([]);
66+
$this->signRequestMapper->method('getByFileId')->willReturn([$signRequest]);
3367

34-
$fileMapper = $this->createMock(\OCA\Libresign\Db\FileMapper::class);
35-
$fileMapper->method('getTextOfStatus')->willReturn('status-text');
68+
$this->identifyMethodService->method('setIsRequest')->willReturnSelf();
69+
$this->identifyMethodService->method('getIdentifyMethodsFromSignRequestId')->willReturn([]);
3670

37-
$root = $this->createMock(IRootFolder::class);
71+
$this->fileMapper->method('getTextOfStatus')->willReturn('status-text');
3872

39-
$signersLoader = $this->createMock(\OCA\Libresign\Service\File\SignersLoader::class);
40-
$signersLoader->expects($this->never())->method('loadSignersFromCertData');
73+
$this->signersLoader->expects($this->never())->method('loadSignersFromCertData');
4174

42-
$assembler = new EnvelopeAssembler(
43-
$signRequestMapper,
44-
$identify,
45-
$fileMapper,
46-
$root,
47-
$signersLoader,
48-
null,
49-
$this->createMock(\OCA\Libresign\Handler\SignEngine\Pkcs12Handler::class),
50-
new NullLogger()
51-
);
75+
$assembler = $this->getService();
5276

5377
$childFile = new DbFile();
5478
$childFile->setId(7);
@@ -70,4 +94,150 @@ public function testBuildsChildDataWithoutCertificateChain(): void {
7094
$this->assertCount(1, $result->signers);
7195
$this->assertEquals(42, $result->signers[0]->signRequestId);
7296
}
97+
98+
public function testBuildsChildDataWithVisibleElements(): void {
99+
$signRequest = new DbSignRequest();
100+
$signRequest->setId(100);
101+
$signRequest->setDisplayName('Signer A');
102+
$signRequest->setStatus(1);
103+
104+
$this->signRequestMapper->method('getByFileId')->willReturn([$signRequest]);
105+
106+
$element = new \OCA\Libresign\Db\FileElement();
107+
$element->setId(1);
108+
$element->setSignRequestId(100);
109+
$element->setPage(1);
110+
$element->setLlx(100);
111+
$element->setLly(100);
112+
$element->setUrx(200);
113+
$element->setUry(200);
114+
$element->setMetadata([]);
115+
116+
$this->signRequestMapper->method('getVisibleElementsFromSigners')->willReturn([
117+
100 => [$element],
118+
]);
119+
120+
$this->identifyMethodService->method('setIsRequest')->willReturnSelf();
121+
$this->identifyMethodService->method('getIdentifyMethodsFromSignRequestId')->willReturn([]);
122+
123+
$this->fileMapper->method('getTextOfStatus')->willReturn('pending');
124+
125+
$this->fileElementService->method('formatVisibleElements')->willReturn([
126+
['signRequestId' => 100, 'type' => 'signature', 'coordinates' => ['page' => 1]],
127+
]);
128+
129+
$assembler = $this->getService();
130+
131+
$childFile = new DbFile();
132+
$childFile->setId(10);
133+
$childFile->setUuid('uuid-10');
134+
$childFile->setName('doc.pdf');
135+
$childFile->setStatus(1);
136+
$childFile->setNodeId(200);
137+
$childFile->setMetadata(['p' => 3, 'd' => [['h' => 800], ['h' => 800], ['h' => 800]]]);
138+
$childFile->setUserId('user1');
139+
140+
$options = new FileResponseOptions();
141+
$options->showVisibleElements();
142+
143+
$result = $assembler->buildEnvelopeChildData($childFile, $options);
144+
145+
$this->assertIsArray($result->visibleElements);
146+
$this->assertNotEmpty($result->visibleElements);
147+
$this->assertCount(1, $result->visibleElements);
148+
}
149+
150+
public function testBuildsChildDataWithoutVisibleElementsWhenNotRequested(): void {
151+
$signRequest = new DbSignRequest();
152+
$signRequest->setId(50);
153+
$signRequest->setDisplayName('Signer B');
154+
$signRequest->setStatus(1);
155+
156+
$this->signRequestMapper->method('getByFileId')->willReturn([$signRequest]);
157+
$this->signRequestMapper->expects($this->never())->method('getVisibleElementsFromSigners');
158+
159+
$this->identifyMethodService->method('setIsRequest')->willReturnSelf();
160+
$this->identifyMethodService->method('getIdentifyMethodsFromSignRequestId')->willReturn([]);
161+
162+
$this->fileMapper->method('getTextOfStatus')->willReturn('pending');
163+
164+
$assembler = $this->getService();
165+
166+
$childFile = new DbFile();
167+
$childFile->setId(20);
168+
$childFile->setUuid('uuid-20');
169+
$childFile->setName('file.pdf');
170+
$childFile->setStatus(1);
171+
$childFile->setNodeId(300);
172+
$childFile->setMetadata(['p' => 1]);
173+
$childFile->setUserId('user1');
174+
175+
$options = new FileResponseOptions();
176+
// NOT calling showVisibleElements()
177+
178+
$result = $assembler->buildEnvelopeChildData($childFile, $options);
179+
180+
$this->assertIsArray($result->visibleElements);
181+
$this->assertEmpty($result->visibleElements);
182+
}
183+
184+
public function testBuildsChildDataWithMultipleSigners(): void {
185+
$signer1 = new DbSignRequest();
186+
$signer1->setId(1);
187+
$signer1->setDisplayName('Alice');
188+
$signer1->setStatus(1);
189+
$signer1->setSigningOrder(1);
190+
191+
$signer2 = new DbSignRequest();
192+
$signer2->setId(2);
193+
$signer2->setDisplayName('Bob');
194+
$signer2->setStatus(2);
195+
$signer2->setSigningOrder(2);
196+
197+
$this->signRequestMapper->method('getByFileId')->willReturn([$signer1, $signer2]);
198+
199+
$this->identifyMethodService->method('setIsRequest')->willReturnSelf();
200+
$this->identifyMethodService->method('getIdentifyMethodsFromSignRequestId')->willReturn([]);
201+
202+
$this->fileMapper->method('getTextOfStatus')->willReturn('partial');
203+
204+
$assembler = $this->getService();
205+
206+
$childFile = new DbFile();
207+
$childFile->setId(30);
208+
$childFile->setUuid('uuid-30');
209+
$childFile->setName('contract.pdf');
210+
$childFile->setStatus(1);
211+
$childFile->setNodeId(400);
212+
$childFile->setMetadata(['p' => 2]);
213+
$childFile->setUserId('user1');
214+
215+
$options = new FileResponseOptions();
216+
$result = $assembler->buildEnvelopeChildData($childFile, $options);
217+
218+
$this->assertCount(2, $result->signers);
219+
$this->assertEquals(1, $result->signers[0]->signRequestId);
220+
$this->assertEquals(2, $result->signers[1]->signRequestId);
221+
}
222+
223+
private function createMockFileElement(
224+
int $id,
225+
int $signRequestId,
226+
int $page,
227+
int $llx,
228+
int $lly,
229+
int $urx,
230+
int $ury,
231+
): \OCA\Libresign\Db\FileElement {
232+
$element = $this->createMock(\OCA\Libresign\Db\FileElement::class);
233+
$element->method('getId')->willReturn($id);
234+
$element->method('getSignRequestId')->willReturn($signRequestId);
235+
$element->method('getPage')->willReturn($page);
236+
$element->method('getLlx')->willReturn($llx);
237+
$element->method('getLly')->willReturn($lly);
238+
$element->method('getUrx')->willReturn($urx);
239+
$element->method('getUry')->willReturn($ury);
240+
$element->method('getMetadata')->willReturn([]);
241+
return $element;
242+
}
73243
}

0 commit comments

Comments
 (0)