• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

LibreSign / libresign / 21500367177

30 Jan 2026 12:54AM UTC coverage: 46.602%. First build
21500367177

Pull #6641

github

web-flow
Merge cb4c40590 into f39fc2360
Pull Request #6641: refactor: centralize file status management

75 of 104 new or added lines in 13 files covered. (72.12%)

7906 of 16965 relevant lines covered (46.6%)

5.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

48.34
/lib/Service/FileService.php
1
<?php
2

3
declare(strict_types=1);
4
/**
5
 * SPDX-FileCopyrightText: 2020-2024 LibreCode coop and contributors
6
 * SPDX-License-Identifier: AGPL-3.0-or-later
7
 */
8

9
namespace OCA\Libresign\Service;
10

11
use DateTimeInterface;
12
use InvalidArgumentException;
13
use OCA\Libresign\Db\File;
14
use OCA\Libresign\Db\FileElementMapper;
15
use OCA\Libresign\Db\FileMapper;
16
use OCA\Libresign\Db\IdDocsMapper;
17
use OCA\Libresign\Db\SignRequest;
18
use OCA\Libresign\Db\SignRequestMapper;
19
use OCA\Libresign\Enum\FileStatus;
20
use OCA\Libresign\Exception\LibresignException;
21
use OCA\Libresign\Handler\DocMdpHandler;
22
use OCA\Libresign\Handler\SignEngine\Pkcs12Handler;
23
use OCA\Libresign\Helper\FileUploadHelper;
24
use OCA\Libresign\ResponseDefinitions;
25
use OCA\Libresign\Service\Envelope\EnvelopeService;
26
use OCA\Libresign\Service\File\CertificateChainService;
27
use OCA\Libresign\Service\File\EnvelopeAssembler;
28
use OCA\Libresign\Service\File\EnvelopeProgressService;
29
use OCA\Libresign\Service\File\FileContentProvider;
30
use OCA\Libresign\Service\File\FileResponseOptions;
31
use OCA\Libresign\Service\File\MessagesLoader;
32
use OCA\Libresign\Service\File\MetadataLoader;
33
use OCA\Libresign\Service\File\MimeService;
34
use OCA\Libresign\Service\File\Pdf\PdfValidator;
35
use OCA\Libresign\Service\File\SettingsLoader;
36
use OCA\Libresign\Service\File\SignersLoader;
37
use OCA\Libresign\Service\File\UploadProcessor;
38
use OCP\AppFramework\Db\DoesNotExistException;
39
use OCP\Files\IMimeTypeDetector;
40
use OCP\Files\IRootFolder;
41
use OCP\Files\Node;
42
use OCP\Files\NotFoundException;
43
use OCP\IL10N;
44
use OCP\IURLGenerator;
45
use OCP\IUser;
46
use OCP\IUserManager;
47
use Psr\Log\LoggerInterface;
48
use stdClass;
49

50
/**
51
 * @psalm-import-type LibresignEnvelopeChildFile from ResponseDefinitions
52
 * @psalm-import-type LibresignValidateFile from ResponseDefinitions
53
 * @psalm-import-type LibresignVisibleElement from ResponseDefinitions
54
 */
55
class FileService {
56

57
        private string $fileContent = '';
58
        private ?File $file = null;
59
        private ?SignRequest $signRequest = null;
60
        private array $certData = [];
61
        private stdClass $fileData;
62
        private FileResponseOptions $options;
63
        public const IDENTIFICATION_DOCUMENTS_DISABLED = 0;
64
        public const IDENTIFICATION_DOCUMENTS_NEED_SEND = 1;
65
        public const IDENTIFICATION_DOCUMENTS_NEED_APPROVAL = 2;
66
        public const IDENTIFICATION_DOCUMENTS_APPROVED = 3;
67
        public function __construct(
68
                protected FileMapper $fileMapper,
69
                protected SignRequestMapper $signRequestMapper,
70
                protected FileElementMapper $fileElementMapper,
71
                protected FileElementService $fileElementService,
72
                protected FolderService $folderService,
73
                private IdDocsMapper $idDocsMapper,
74
                private IdentifyMethodService $identifyMethodService,
75
                private IUserManager $userManager,
76
                private IURLGenerator $urlGenerator,
77
                protected IMimeTypeDetector $mimeTypeDetector,
78
                protected Pkcs12Handler $pkcs12Handler,
79
                protected DocMdpHandler $docMdpHandler,
80
                protected PdfValidator $pdfValidator,
81
                private IRootFolder $root,
82
                protected LoggerInterface $logger,
83
                protected IL10N $l10n,
84
                private EnvelopeService $envelopeService,
85
                private SignersLoader $signersLoader,
86
                protected FileUploadHelper $uploadHelper,
87
                private EnvelopeAssembler $envelopeAssembler,
88
                private EnvelopeProgressService $envelopeProgressService,
89
                private CertificateChainService $certificateChainService,
90
                private MimeService $mimeService,
91
                private FileContentProvider $contentProvider,
92
                private UploadProcessor $uploadProcessor,
93
                private MetadataLoader $metadataLoader,
94
                private SettingsLoader $settingsLoader,
95
                private MessagesLoader $messagesLoader,
96
                private FileStatusService $fileStatusService,
97
        ) {
98
                $this->fileData = new stdClass();
42✔
99
                $this->options = new FileResponseOptions();
42✔
100
        }
101

102
        public function update(File $file): File {
NEW
103
                return $this->fileStatusService->update($file);
×
104
        }
105

106
        public function getNodeFromData(array $data): Node {
107
                if (!$this->folderService->getUserId()) {
18✔
108
                        $this->folderService->setUserId($data['userManager']->getUID());
12✔
109
                }
110

111
                if (isset($data['uploadedFile'])) {
18✔
112
                        return $this->uploadProcessor->getNodeFromUploadedFile($data);
×
113
                }
114

115
                if (isset($data['file']['fileNode']) && $data['file']['fileNode'] instanceof Node) {
18✔
116
                        return $data['file']['fileNode'];
×
117
                }
118
                if (isset($data['file']['fileId'])) {
18✔
119
                        return $this->folderService->getFileByNodeId($data['file']['fileId']);
2✔
120
                }
121
                if (isset($data['file']['path'])) {
16✔
122
                        return $this->folderService->getFileByPath($data['file']['path']);
×
123
                }
124
                if (isset($data['file']['nodeId'])) {
16✔
125
                        return $this->folderService->getFileByNodeId($data['file']['nodeId']);
1✔
126
                }
127

128
                $content = $this->getFileRaw($data);
15✔
129
                $extension = $this->getExtension($content);
15✔
130

131
                $fileName = $data['name'];
15✔
132
                $this->validateFileContent($content, $fileName, $extension);
15✔
133

134
                $folderToFile = $this->folderService->getFolderForFile($data, $data['userManager']);
15✔
135
                $filename = $this->resolveFileName($data, $extension);
15✔
136
                return $folderToFile->newFile($filename, $content);
15✔
137
        }
138

139
        public function validateFileContent(string $content, string $fileName, string $extension): void {
140
                if ($extension === 'pdf') {
16✔
141
                        $this->pdfValidator->validate($content, $fileName);
15✔
142
                }
143
        }
144

145
        private function getExtension(string $content): string {
146
                return $this->mimeService->getExtension($content);
15✔
147
        }
148

149
        private function getFileRaw(array $data): string {
150
                return $this->contentProvider->getContentFromData($data);
15✔
151
        }
152

153
        private function resolveFileName(array $data, string $extension): string {
154
                $name = '';
15✔
155
                if (isset($data['name'])) {
15✔
156
                        $name = trim((string)$data['name']);
15✔
157
                }
158

159
                if ($name === '') {
15✔
160
                        $basename = '';
×
161
                        if (!empty($data['file']['url'])) {
×
162
                                $path = (string)parse_url((string)$data['file']['url'], PHP_URL_PATH);
×
163
                                if ($path !== '') {
×
164
                                        $basename = basename($path);
×
165
                                }
166
                        }
167
                        if ($basename !== '') {
×
168
                                $filenameNoExt = pathinfo($basename, PATHINFO_FILENAME);
×
169
                                $name = $filenameNoExt !== '' ? $filenameNoExt : $basename;
×
170
                        } else {
171
                                $name = 'document';
×
172
                        }
173
                }
174

175
                $name = preg_replace('/\s+/', '_', $name);
15✔
176
                $name = $name !== '' ? $name : 'document';
15✔
177
                return $name . '.' . $extension;
15✔
178
        }
179

180
        /**
181
         * @return static
182
         */
183
        public function showSigners(bool $show = true): self {
184
                $this->options->showSigners($show);
2✔
185
                return $this;
2✔
186
        }
187

188
        /**
189
         * @return static
190
         */
191
        public function showSettings(bool $show = true): self {
192
                $this->options->showSettings($show);
2✔
193
                if ($show) {
2✔
194
                        $this->fileData->settings = [
2✔
195
                                'canSign' => false,
2✔
196
                                'canRequestSign' => false,
2✔
197
                                'signerFileUuid' => null,
2✔
198
                                'phoneNumber' => '',
2✔
199
                        ];
2✔
200
                } else {
201
                        unset($this->fileData->settings);
×
202
                }
203
                return $this;
2✔
204
        }
205

206
        /**
207
         * @return static
208
         */
209
        public function showVisibleElements(bool $show = true): self {
210
                $this->options->showVisibleElements($show);
3✔
211
                return $this;
3✔
212
        }
213

214
        /**
215
         * @return static
216
         */
217
        public function showMessages(bool $show = true): self {
218
                $this->options->showMessages($show);
2✔
219
                return $this;
2✔
220
        }
221

222
        /**
223
         * @return static
224
         */
225
        public function setMe(?IUser $user): self {
226
                $this->options->setMe($user);
2✔
227
                return $this;
2✔
228
        }
229

230
        public function setSignerIdentified(bool $identified = true): self {
231
                $this->options->setSignerIdentified($identified);
×
232
                return $this;
×
233
        }
234

235
        public function setIdentifyMethodId(?int $id): self {
236
                $this->options->setIdentifyMethodId($id);
2✔
237
                return $this;
2✔
238
        }
239

240
        public function setHost(string $host): self {
241
                $this->options->setHost($host);
2✔
242
                return $this;
2✔
243
        }
244

245
        /**
246
         * @return static
247
         */
248
        public function setFile(File $file): self {
249
                $this->file = $file;
5✔
250
                $this->fileData->status = $this->file->getStatus();
5✔
251
                return $this;
5✔
252
        }
253

254
        public function setSignRequest(SignRequest $signRequest): self {
255
                $this->signRequest = $signRequest;
×
256
                return $this;
×
257
        }
258

259
        public function showValidateFile(bool $validateFile = true): self {
260
                $this->options->validateFile($validateFile);
2✔
261
                return $this;
2✔
262
        }
263

264
        private function setFileOrFail(callable $resolver): self {
265
                try {
266
                        $file = $resolver();
6✔
267
                } catch (\Throwable) {
3✔
268
                        throw new LibresignException($this->l10n->t('Invalid data to validate file'), 404);
3✔
269
                }
270

271
                if (!$file instanceof File) {
3✔
272
                        throw new LibresignException($this->l10n->t('Invalid file identifier'), 404);
×
273
                }
274

275
                return $this->setFile($file);
3✔
276
        }
277

278
        public function setFileById(int $fileId): self {
279
                return $this->setFileOrFail(fn () => $this->fileMapper->getById($fileId));
3✔
280
        }
281

282
        public function setFileByUuid(string $uuid): self {
283
                return $this->setFileOrFail(fn () => $this->fileMapper->getByUuid($uuid));
3✔
284
        }
285

286
        public function setFileBySignerUuid(string $uuid): self {
287
                return $this->setFileOrFail(fn () => $this->fileMapper->getBySignerUuid($uuid));
1✔
288
        }
289

290
        public function setFileByNodeId(int $nodeId): self {
291
                return $this->setFileOrFail(fn () => $this->fileMapper->getByNodeId($nodeId));
×
292
        }
293

294
        public function validateUploadedFile(array $file): void {
295
                $this->uploadHelper->validateUploadedFile($file);
×
296
        }
297

298
        public function setFileFromRequest(?array $file): self {
299
                if ($file === null) {
×
300
                        throw new InvalidArgumentException($this->l10n->t('No file provided'));
×
301
                }
302
                $this->uploadHelper->validateUploadedFile($file);
×
303

304
                $this->fileContent = file_get_contents($file['tmp_name']);
×
305
                $mimeType = $this->mimeService->getMimeType($this->fileContent);
×
306
                if ($mimeType !== 'application/pdf') {
×
307
                        $this->fileContent = '';
×
308
                        unlink($file['tmp_name']);
×
309
                        throw new InvalidArgumentException($this->l10n->t('Invalid file provided'));
×
310
                }
311
                $this->fileData->size = $file['size'];
×
312

313
                $memoryFile = fopen($file['tmp_name'], 'rb');
×
314
                try {
315
                        $this->certData = $this->pkcs12Handler->getCertificateChain($memoryFile);
×
316
                        $this->fileData->status = FileStatus::SIGNED->value;
×
317
                } catch (LibresignException) {
×
318
                        $this->fileData->status = FileStatus::DRAFT->value;
×
319
                }
320
                fclose($memoryFile);
×
321
                unlink($file['tmp_name']);
×
322
                $this->fileData->hash = hash('sha256', $this->fileContent);
×
323
                try {
324
                        $libresignFile = $this->fileMapper->getBySignedHash($this->fileData->hash);
×
325
                        $this->setFile($libresignFile);
×
326
                } catch (DoesNotExistException) {
×
327
                        $this->fileData->status = FileStatus::NOT_LIBRESIGN_FILE->value;
×
328
                }
329
                $this->fileData->name = $file['name'];
×
330
                return $this;
×
331
        }
332

333
        private function getFile(): \OCP\Files\File {
334
                $nodeId = $this->file->getSignedNodeId();
×
335
                if (!$nodeId) {
×
336
                        $nodeId = $this->file->getNodeId();
×
337
                }
338
                $fileToValidate = $this->root->getUserFolder($this->file->getUserId())->getFirstNodeById($nodeId);
×
339
                if (!$fileToValidate instanceof \OCP\Files\File) {
×
340
                        throw new LibresignException($this->l10n->t('File not found'), 404);
×
341
                }
342
                return $fileToValidate;
×
343
        }
344

345
        public function getStatus(): int {
346
                return $this->file->getStatus();
1✔
347
        }
348

349
        public function isLibresignFile(int $nodeId): bool {
350
                return $this->fileMapper->nodeIdExists($nodeId);
×
351
        }
352

353
        public function getSignedNodeId(): ?int {
354
                $status = $this->file->getStatus();
×
355

356
                if (!in_array($status, [FileStatus::PARTIAL_SIGNED->value, FileStatus::SIGNED->value])) {
×
357
                        return null;
×
358
                }
359
                return $this->file->getSignedNodeId();
×
360
        }
361

362
        private function loadSigners(): void {
363
                if (!$this->options->isShowSigners()) {
4✔
364
                        return;
2✔
365
                }
366

367
                if (!$this->file instanceof File) {
2✔
368
                        return;
×
369
                }
370

371
                if ($this->file->getSignedNodeId()) {
2✔
372
                        $fileNode = $this->getFile();
×
373
                        $certData = $this->certificateChainService->getCertificateChain($fileNode, $this->file, $this->options);
×
374
                        if ($certData) {
×
375
                                $this->signersLoader->loadSignersFromCertData($this->fileData, $certData, $this->options->getHost());
×
376
                        }
377
                }
378
                $this->signersLoader->loadLibreSignSigners($this->file, $this->fileData, $this->options, $this->certData);
2✔
379
                $this->loadSignRequestData();
2✔
380
        }
381

382
        private function loadSignRequestData(): void {
383
                if (empty($this->fileData->signers) || !is_array($this->fileData->signers)) {
2✔
384
                        return;
×
385
                }
386

387
                foreach ($this->fileData->signers as $signer) {
2✔
388
                        if (!empty($signer->me) && isset($signer->sign_uuid)) {
2✔
389
                                $this->fileData->url = $this->urlGenerator->linkToRoute('libresign.page.getPdfFile', ['uuid' => $signer->sign_uuid]);
1✔
390
                                $this->fileData->signUuid = $signer->sign_uuid;
1✔
391
                                return;
1✔
392
                        }
393
                }
394
        }
395

396
        private function loadFileMetadata(): void {
397
                $this->metadataLoader->loadMetadata($this->file, $this->fileData);
4✔
398
        }
399

400
        private function loadSettings(): void {
401
                $this->settingsLoader->loadSettings($this->fileData, $this->options);
4✔
402
        }
403

404
        public function getIdentificationDocumentsStatus(string $userId = ''): int {
405
                return $this->settingsLoader->getIdentificationDocumentsStatus($userId);
3✔
406
        }
407

408
        private function loadLibreSignData(): void {
409
                if (!$this->file) {
4✔
410
                        return;
×
411
                }
412
                $this->fileData->id = $this->file->getId();
4✔
413
                $this->fileData->uuid = $this->file->getUuid();
4✔
414
                $this->fileData->name = $this->file->getName();
4✔
415
                $this->fileData->status = $this->file->getStatus();
4✔
416
                $this->fileData->created_at = $this->file->getCreatedAt()->format(DateTimeInterface::ATOM);
4✔
417
                $this->fileData->statusText = $this->fileMapper->getTextOfStatus($this->file->getStatus());
4✔
418
                $this->fileData->nodeId = $this->file->getNodeId();
4✔
419
                $this->fileData->signatureFlow = $this->file->getSignatureFlow();
4✔
420
                $this->fileData->docmdpLevel = $this->file->getDocmdpLevel();
4✔
421
                $this->fileData->nodeType = $this->file->getNodeType();
4✔
422

423
                if ($this->fileData->nodeType !== 'envelope' && !$this->file->getParentFileId()) {
4✔
424
                        $fileId = $this->file->getId();
4✔
425

426
                        $childrenFiles = $this->fileMapper->getChildrenFiles($fileId);
4✔
427

428
                        if (!empty($childrenFiles)) {
4✔
429
                                $this->file->setNodeType('envelope');
×
430
                                $this->fileMapper->update($this->file);
×
431

432
                                $this->fileData->nodeType = 'envelope';
×
433
                                $this->fileData->filesCount = count($childrenFiles);
×
434
                                $this->fileData->files = [];
×
435
                        }
436
                }
437

438
                if ($this->fileData->nodeType === 'envelope') {
4✔
439
                        $metadata = $this->file->getMetadata();
×
440
                        $this->fileData->filesCount = $metadata['filesCount'] ?? 0;
×
441
                        $this->fileData->files = [];
×
442
                        $this->loadEnvelopeFiles();
×
443
                        if ($this->file->getStatus() === FileStatus::SIGNED->value) {
×
444
                                $latestSignedDate = $this->getLatestSignedDateFromEnvelope();
×
445
                                if ($latestSignedDate) {
×
446
                                        $this->fileData->signedDate = $latestSignedDate->format(DateTimeInterface::ATOM);
×
447
                                }
448
                        }
449
                }
450

451
                $this->fileData->requested_by = [
4✔
452
                        'userId' => $this->file->getUserId(),
4✔
453
                        'displayName' => $this->userManager->get($this->file->getUserId())->getDisplayName(),
4✔
454
                ];
4✔
455
                $this->fileData->file = $this->urlGenerator->linkToRoute('libresign.page.getPdf', ['uuid' => $this->file->getUuid()]);
4✔
456

457
                $this->loadEnvelopeData();
4✔
458

459
                if (!isset($this->fileData->files) || !is_array($this->fileData->files)) {
4✔
460
                        $this->fileData->files = [];
4✔
461
                }
462
        }
463

464
        private function loadVisibleElements(): void {
465
                if (!$this->options->isShowVisibleElements()) {
4✔
466
                        return;
1✔
467
                }
468
                $signers = $this->signRequestMapper->getByMultipleFileId([$this->file->getId()]);
3✔
469
                $this->fileData->visibleElements = [];
3✔
470
                $fileMetadata = $this->file->getMetadata();
3✔
471
                foreach ($this->signRequestMapper->getVisibleElementsFromSigners($signers) as $visibleElements) {
3✔
472
                        if (empty($visibleElements)) {
×
473
                                continue;
×
474
                        }
475
                        $this->fileData->visibleElements = array_merge(
×
476
                                $this->fileElementService->formatVisibleElements($visibleElements, $fileMetadata),
×
477
                                $this->fileData->visibleElements
×
478
                        );
×
479
                }
480
        }
481

482
        private function getLatestSignedDateFromEnvelope(): ?\DateTime {
483
                if (!$this->file || $this->file->getNodeType() !== 'envelope') {
×
484
                        return null;
×
485
                }
486

487
                $childrenFiles = $this->fileMapper->getChildrenFiles($this->file->getId());
×
488
                $latestDate = null;
×
489

490
                $childFileIds = array_map(fn ($childFile) => $childFile->getId(), $childrenFiles);
×
491
                if (empty($childFileIds)) {
×
492
                        return null;
×
493
                }
494

495
                $signRequests = $this->signRequestMapper->getByMultipleFileId($childFileIds);
×
496
                foreach ($signRequests as $signRequest) {
×
497
                        $signed = $signRequest->getSigned();
×
498
                        if ($signed && (!$latestDate || $signed > $latestDate)) {
×
499
                                $latestDate = $signed;
×
500
                        }
501
                }
502

503
                return $latestDate;
×
504
        }
505

506
        private function loadEnvelopeFiles(): void {
507
                if (!$this->file || $this->file->getNodeType() !== 'envelope') {
×
508
                        return;
×
509
                }
510

511
                $childrenFiles = $this->fileMapper->getChildrenFiles($this->file->getId());
×
512
                foreach ($childrenFiles as $childFile) {
×
513
                        $this->fileData->files[] = $this->buildEnvelopeChildData($childFile);
×
514
                }
515
        }
516

517
        private function buildEnvelopeChildData(File $childFile): stdClass {
518
                return $this->envelopeAssembler->buildEnvelopeChildData($childFile, $this->options);
×
519
        }
520

521
        private function loadEnvelopeData(): void {
522
                if (!$this->file->hasParent()) {
4✔
523
                        return;
4✔
524
                }
525

526
                $envelope = $this->envelopeService->getEnvelopeByFileId($this->file->getId());
×
527
                if (!$envelope) {
×
528
                        return;
×
529
                }
530

531
                $envelopeMetadata = $envelope->getMetadata();
×
532
                $this->fileData->envelope = [
×
533
                        'id' => $envelope->getId(),
×
534
                        'uuid' => $envelope->getUuid(),
×
535
                        'name' => $envelope->getName(),
×
536
                        'status' => $envelope->getStatus(),
×
537
                        'statusText' => $this->fileMapper->getTextOfStatus($envelope->getStatus()),
×
538
                        'filesCount' => $envelopeMetadata['filesCount'] ?? 0,
×
539
                        'files' => [],
×
540
                ];
×
541
        }
542

543
        private function loadMessages(): void {
544
                $this->messagesLoader->loadMessages($this->file, $this->fileData, $this->options, $this->certData);
4✔
545
        }
546

547
        /**
548
         * @return LibresignValidateFile
549
         * @psalm-return LibresignValidateFile
550
         */
551
        public function toArray(): array {
552
                $this->loadLibreSignData();
4✔
553
                $this->loadFileMetadata();
4✔
554
                $this->loadSettings();
4✔
555
                $this->loadSigners();
4✔
556
                $this->loadVisibleElements();
4✔
557
                $this->loadMessages();
4✔
558
                $this->computeEnvelopeSignersProgress();
4✔
559

560
                $return = json_decode(json_encode($this->fileData), true);
4✔
561
                ksort($return);
4✔
562
                return $return;
4✔
563
        }
564

565
        private function computeEnvelopeSignersProgress(): void {
566
                if (!$this->file || $this->file->getParentFileId() || empty($this->fileData->signers)) {
4✔
567
                        return;
2✔
568
                }
569

570
                $childrenFiles = $this->fileMapper->getChildrenFiles($this->file->getId());
2✔
571
                if (empty($childrenFiles)) {
2✔
572
                        return;
2✔
573
                }
574

575
                $childFileIds = array_map(fn ($childFile) => $childFile->getId(), $childrenFiles);
×
576
                $allSignRequests = $this->signRequestMapper->getByMultipleFileId($childFileIds);
×
577

578
                $signRequestsByFileId = array_fill_keys($childFileIds, []);
×
579
                foreach ($allSignRequests as $signRequest) {
×
580
                        $signRequestsByFileId[$signRequest->getFileId()][] = $signRequest;
×
581
                }
582

583
                $identifyMethodsBySignRequest = [];
×
584
                if (!empty($allSignRequests)) {
×
585
                        $allSignRequestIds = array_map(fn ($sr) => $sr->getId(), $allSignRequests);
×
586
                        $identifyMethodsBySignRequest = $this->identifyMethodService
×
587
                                ->setIsRequest(false)
×
588
                                ->getIdentifyMethodsFromSignRequestIds($allSignRequestIds);
×
589
                }
590

591
                $this->envelopeProgressService->computeProgress(
×
592
                        $this->fileData,
×
593
                        $this->file,
×
594
                        $childrenFiles,
×
595
                        $signRequestsByFileId,
×
596
                        $identifyMethodsBySignRequest
×
597
                );
×
598
        }
599

600
        public function delete(int $fileId, bool $deleteFile = true): void {
601
                $file = $this->fileMapper->getById($fileId);
3✔
602

603
                $this->decrementEnvelopeFilesCountIfNeeded($file);
3✔
604

605
                if ($file->getNodeType() === 'envelope') {
3✔
606
                        $childrenFiles = $this->fileMapper->getChildrenFiles($file->getId());
×
607
                        foreach ($childrenFiles as $childFile) {
×
608
                                $this->delete($childFile->getId(), $deleteFile);
×
609
                        }
610
                }
611

612
                $this->fileElementService->deleteVisibleElements($file->getId());
3✔
613
                $list = $this->signRequestMapper->getByFileId($file->getId());
3✔
614
                foreach ($list as $signRequest) {
3✔
615
                        $this->identifyMethodService->deleteBySignRequestId($signRequest->getId());
×
616
                        $this->signRequestMapper->delete($signRequest);
×
617
                }
618
                $this->idDocsMapper->deleteByFileId($file->getId());
3✔
619
                $this->fileMapper->delete($file);
3✔
620
                if ($deleteFile) {
3✔
621
                        if ($file->getSignedNodeId()) {
2✔
622
                                $signedNextcloudFile = $this->folderService->getFileByNodeId($file->getSignedNodeId());
×
623
                                $parentFolder = $signedNextcloudFile->getParent();
×
624
                                $signedNextcloudFile->delete();
×
625
                                $this->deleteEmptyFolder($parentFolder);
×
626
                        }
627
                        try {
628
                                $nextcloudFile = $this->folderService->getFileByNodeId($file->getNodeId());
2✔
629
                                $parentFolder = $nextcloudFile->getParent();
2✔
630
                                $nextcloudFile->delete();
2✔
631
                                $this->deleteEmptyFolder($parentFolder);
2✔
632
                        } catch (NotFoundException) {
×
633
                        }
634
                }
635
        }
636

637
        private function deleteEmptyFolder(\OCP\Files\Folder $folder): void {
638
                try {
639
                        $contents = $folder->getDirectoryListing();
2✔
640
                        if (count($contents) === 0) {
2✔
641
                                $folder->delete();
2✔
642
                        }
643
                } catch (\Exception $e) {
×
644
                        $this->logger->debug('Could not delete empty folder: ' . $e->getMessage(), [
×
645
                                'exception' => $e,
×
646
                        ]);
×
647
                }
648
        }
649

650
        public function processUploadedFilesWithRollback(array $filesArray, IUser $user, array $settings): array {
651
                return $this->uploadProcessor->processUploadedFilesWithRollback($filesArray, $user, $settings);
×
652
        }
653

654
        public function updateEnvelopeFilesCount(File $envelope, int $delta = 0): void {
655
                $metadata = $envelope->getMetadata();
×
656
                $currentCount = $metadata['filesCount'] ?? 0;
×
657
                $metadata['filesCount'] = max(0, $currentCount + $delta);
×
658
                $envelope->setMetadata($metadata);
×
659
                $this->fileMapper->update($envelope);
×
660
        }
661

662
        private function decrementEnvelopeFilesCountIfNeeded(File $file): void {
663
                if ($file->getParentFileId() === null) {
3✔
664
                        return;
3✔
665
                }
666

667
                $parentEnvelope = $this->fileMapper->getById($file->getParentFileId());
×
668
                if ($parentEnvelope->getNodeType() === 'envelope') {
×
669
                        $this->updateEnvelopeFilesCount($parentEnvelope, -1);
×
670
                }
671
        }
672
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc