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

LibreSign / libresign / 21006909149

14 Jan 2026 07:21PM UTC coverage: 43.837%. First build
21006909149

Pull #6436

github

web-flow
Merge 1b659c916 into 9bd4c65c5
Pull Request #6436: feat: async parallel signing

294 of 825 new or added lines in 35 files covered. (35.64%)

6921 of 15788 relevant lines covered (43.84%)

4.87 hits per line

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

50.99
/lib/Db/SignRequestMapper.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\Db;
10

11
use OCA\Libresign\Enum\FileStatus;
12
use OCA\Libresign\Enum\SignRequestStatus;
13
use OCA\Libresign\Helper\Pagination;
14
use OCA\Libresign\Service\IdentifyMethod\IIdentifyMethod;
15
use OCA\Libresign\Service\IdentifyMethodService;
16
use OCP\AppFramework\Db\DoesNotExistException;
17
use OCP\AppFramework\Db\Entity;
18
use OCP\AppFramework\Db\QBMapper;
19
use OCP\DB\QueryBuilder\IQueryBuilder;
20
use OCP\IDateTimeFormatter;
21
use OCP\IDBConnection;
22
use OCP\IL10N;
23
use OCP\IURLGenerator;
24
use OCP\IUser;
25
use OCP\IUserManager;
26

27
/**
28
 * Class SignRequestMapper
29
 *
30
 * @package OCA\Libresign\DB
31
 * @template-extends QBMapper<SignRequest>
32
 */
33
class SignRequestMapper extends QBMapper {
34
        /**
35
         * @var SignRequest[]
36
         */
37
        private $signers = [];
38
        private bool $firstNotification = false;
39

40
        public function __construct(
41
                IDBConnection $db,
42
                protected IL10N $l10n,
43
                protected FileMapper $fileMapper,
44
                private IUserManager $userManager,
45
                private IDateTimeFormatter $dateTimeFormatter,
46
                private IURLGenerator $urlGenerator,
47
        ) {
48
                parent::__construct($db, 'libresign_sign_request');
47✔
49
        }
50

51
        /**
52
         * @return boolean true when is the first notification
53
         */
54
        public function incrementNotificationCounter(SignRequest $signRequest, string $method): bool {
55
                $this->db->beginTransaction();
13✔
56
                try {
57
                        $fromDatabase = $this->getById($signRequest->getId());
13✔
58
                        $metadata = $fromDatabase->getMetadata();
13✔
59
                        if (!isset($metadata['notify'])) {
13✔
60
                                $this->firstNotification = true;
13✔
61
                        }
62

63
                        $notificationEntry = [
13✔
64
                                'method' => $method,
13✔
65
                                'date' => time(),
13✔
66
                        ];
13✔
67

68
                        if (!empty($fromDatabase->getDescription())) {
13✔
69
                                $notificationEntry['description'] = $fromDatabase->getDescription();
×
70
                        }
71

72
                        $metadata['notify'][] = $notificationEntry;
13✔
73
                        $fromDatabase->setMetadata($metadata);
13✔
74
                        $this->update($fromDatabase);
13✔
75
                        $this->db->commit();
13✔
76
                } catch (\Throwable) {
×
77
                        $this->db->rollBack();
×
78
                }
79
                return $this->firstNotification;
13✔
80
        }
81

82
        /**
83
         * @inheritDoc
84
         */
85
        #[\Override]
86
        public function update(Entity $entity): SignRequest {
87
                /** @var SignRequest */
88
                $signRequest = parent::update($entity);
13✔
89
                $this->signers[$signRequest->getId()] = $signRequest;
13✔
90
                return $signRequest;
13✔
91
        }
92

93
        /**
94
         * Get sign request by UUID
95
         *
96
         * @throws DoesNotExistException
97
         */
98
        public function getByUuid(string $uuid): SignRequest {
99
                foreach ($this->signers as $signRequest) {
5✔
100
                        if ($signRequest->getUuid() === $uuid) {
5✔
101
                                return $signRequest;
4✔
102
                        }
103
                }
104
                $qb = $this->db->getQueryBuilder();
1✔
105

106
                $qb->select('*')
1✔
107
                        ->from($this->getTableName())
1✔
108
                        ->where(
1✔
109
                                $qb->expr()->eq('uuid', $qb->createNamedParameter($uuid))
1✔
110
                        );
1✔
111
                /** @var SignRequest */
112
                $signRequest = $this->findEntity($qb);
1✔
113
                if (!isset($this->signers[$signRequest->getId()])) {
×
114
                        $this->signers[$signRequest->getId()] = $signRequest;
×
115
                }
116
                return $signRequest;
×
117
        }
118

119
        public function getByEmailAndFileId(string $email, int $fileId): SignRequest {
120
                $qb = $this->db->getQueryBuilder();
×
121

122
                $qb->select('*')
×
123
                        ->from($this->getTableName())
×
124
                        ->where(
×
125
                                $qb->expr()->eq('email', $qb->createNamedParameter($email))
×
126
                        )
×
127
                        ->andWhere(
×
128
                                $qb->expr()->eq('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))
×
129
                        );
×
130
                /** @var SignRequest */
131
                return $this->findEntity($qb);
×
132
        }
133

134
        public function getByIdentifyMethodAndFileId(IIdentifyMethod $identifyMethod, int $fileId): SignRequest {
135
                $qb = $this->db->getQueryBuilder();
13✔
136
                $qb->select('sr.*')
13✔
137
                        ->from($this->getTableName(), 'sr')
13✔
138
                        ->join('sr', 'libresign_identify_method', 'im', 'sr.id = im.sign_request_id')
13✔
139
                        ->where($qb->expr()->eq('im.identifier_key', $qb->createNamedParameter($identifyMethod->getEntity()->getIdentifierKey())))
13✔
140
                        ->andWhere($qb->expr()->eq('im.identifier_value', $qb->createNamedParameter($identifyMethod->getEntity()->getIdentifierValue())))
13✔
141
                        ->andWhere($qb->expr()->eq('sr.file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
13✔
142
                /** @var SignRequest */
143
                return $this->findEntity($qb);
13✔
144
        }
145

146
        /**
147
         * Get all signers by fileId
148
         *
149
         * @return SignRequest[]
150
         */
151
        public function getByFileId(int $fileId): array {
152
                $qb = $this->db->getQueryBuilder();
15✔
153

154
                $qb->select('*')
15✔
155
                        ->from($this->getTableName())
15✔
156
                        ->where(
15✔
157
                                $qb->expr()->eq('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))
15✔
158
                        );
15✔
159
                /** @var SignRequest[] */
160
                $signers = $this->findEntities($qb);
15✔
161
                foreach ($signers as $signRequest) {
15✔
162
                        $this->signers[$signRequest->getId()] = $signRequest;
13✔
163
                }
164
                return $signers;
15✔
165
        }
166

167
        public function flushCache(?int $signRequestId = null): void {
NEW
168
                if ($signRequestId !== null) {
×
NEW
169
                        unset($this->signers[$signRequestId]);
×
170
                } else {
NEW
171
                        $this->signers = [];
×
172
                }
173
        }
174

175
        /**
176
         * @throws DoesNotExistException
177
         */
178
        public function getById(int $signRequestId): SignRequest {
179
                if (isset($this->signers[$signRequestId])) {
15✔
180
                        return $this->signers[$signRequestId];
14✔
181
                }
182
                $qb = $this->db->getQueryBuilder();
14✔
183

184
                $qb->select('*')
14✔
185
                        ->from($this->getTableName())
14✔
186
                        ->where(
14✔
187
                                $qb->expr()->eq('id', $qb->createNamedParameter($signRequestId, IQueryBuilder::PARAM_INT))
14✔
188
                        );
14✔
189

190
                /** @var SignRequest */
191
                $signRequest = $this->findEntity($qb);
14✔
192
                if (!isset($this->signers[$signRequest->getId()])) {
14✔
193
                        $this->signers[$signRequest->getId()] = $signRequest;
14✔
194
                }
195
                return $signRequest;
14✔
196
        }
197

198
        /**
199
         * Get sign requests of child files from an envelope for the same signer
200
         *
201
         * @return SignRequest[]
202
         */
203
        public function getByEnvelopeChildrenAndIdentifyMethod(int $parentFileId, int $signRequestId): array {
204
                $qb = $this->db->getQueryBuilder();
×
205

206
                $qb->select('sr.*')
×
207
                        ->from('libresign_file', 'f')
×
208
                        ->innerJoin('f', $this->getTableName(), 'sr', $qb->expr()->eq('sr.file_id', 'f.id'))
×
209
                        ->innerJoin('sr', 'libresign_identify_method', 'im', $qb->expr()->eq('im.sign_request_id', 'sr.id'))
×
210
                        ->innerJoin('im', 'libresign_identify_method', 'im2',
×
211
                                $qb->expr()->andX(
×
212
                                        $qb->expr()->eq('im2.sign_request_id', $qb->createNamedParameter($signRequestId, IQueryBuilder::PARAM_INT)),
×
213
                                        $qb->expr()->eq('im2.identifier_key', 'im.identifier_key'),
×
214
                                        $qb->expr()->eq('im2.identifier_value', 'im.identifier_value')
×
215
                                )
×
216
                        )
×
217
                        ->where(
×
218
                                $qb->expr()->eq('f.parent_file_id', $qb->createNamedParameter($parentFileId, IQueryBuilder::PARAM_INT))
×
219
                        );
×
220

221
                /** @var SignRequest[] */
222
                $signRequests = $this->findEntities($qb);
×
223
                foreach ($signRequests as $signRequest) {
×
224
                        if (!isset($this->signers[$signRequest->getId()])) {
×
225
                                $this->signers[$signRequest->getId()] = $signRequest;
×
226
                        }
227
                }
228
                return $signRequests;
×
229
        }
230

231
        /**
232
         * @return \Generator<IdentifyMethod>
233
         */
234
        public function findRemindersCandidates(): \Generator {
235
                $qb = $this->db->getQueryBuilder();
×
236
                $qb->select(
×
237
                        'sr.id AS sr_id',
×
238
                        'sr.file_id AS sr_file_id',
×
239
                        'sr.uuid AS sr_uuid',
×
240
                        'sr.display_name AS sr_display_name',
×
241
                        'sr.description AS sr_description',
×
242
                        'sr.metadata AS sr_metadata',
×
243
                        'sr.signed_hash AS sr_signed_hash',
×
244
                        'sr.created_at AS sr_created_at',
×
245
                        'sr.signed AS sr_signed',
×
246

247
                        'im.id AS im_id',
×
248
                        'im.mandatory AS im_mandatory',
×
249
                        'im.code AS im_code',
×
250
                        'im.identifier_key AS im_identifier_key',
×
251
                        'im.identifier_value AS im_identifier_value',
×
252
                        'im.attempts AS im_attempts',
×
253
                        'im.identified_at_date AS im_identified_at_date',
×
254
                        'im.last_attempt_date AS im_last_attempt_date',
×
255
                        'im.sign_request_id AS im_sign_request_id',
×
256
                        'im.metadata AS im_metadata',
×
257
                )
×
258
                        ->from('libresign_sign_request', 'sr')
×
259
                        ->join('sr', 'libresign_identify_method', 'im', 'sr.id = im.sign_request_id')
×
260
                        ->join('sr', 'libresign_file', 'f', 'sr.file_id = f.id')
×
261
                        ->where($qb->expr()->isNull('sr.signed'))
×
262
                        ->andWhere($qb->expr()->neq('im.identifier_value', $qb->createNamedParameter('deleted_users')))
×
263
                        ->andWhere($qb->expr()->in('f.status', $qb->createNamedParameter([
×
264
                                FileStatus::ABLE_TO_SIGN->value,
×
265
                                FileStatus::PARTIAL_SIGNED->value
×
266
                        ], IQueryBuilder::PARAM_INT_ARRAY)))
×
267
                        ->setParameter('st', [1,2], IQueryBuilder::PARAM_INT_ARRAY)
×
268
                        ->orderBy('sr.id', 'ASC');
×
269

270
                $result = $qb->executeQuery();
×
271
                try {
272
                        /** @var array<string, mixed> $row */
273
                        while ($row = $result->fetch()) {
×
274
                                $signRequest = new SignRequest();
×
275
                                $identifyMethod = new IdentifyMethod();
×
276
                                foreach ($row as $key => $value) {
×
277
                                        $prop = $identifyMethod->columnToProperty(substr($key, 3));
×
278
                                        if (str_starts_with($key, 'sr_')) {
×
279
                                                $signRequest->{'set' . lcfirst($prop)}($value);
×
280
                                        } else {
281
                                                $identifyMethod->{'set' . lcfirst($prop)}($value);
×
282
                                        }
283
                                }
284
                                $signRequest->resetUpdatedFields();
×
285
                                $identifyMethod->resetUpdatedFields();
×
286
                                if (!isset($this->signers[$signRequest->getId()])) {
×
287
                                        $this->signers[$signRequest->getId()] = $signRequest;
×
288
                                }
289
                                yield $identifyMethod;
×
290
                        }
291
                } finally {
292
                        $result->closeCursor();
×
293
                }
294
        }
295

296
        /**
297
         * Get all signers by multiple fileId
298
         * Includes signers from both the files themselves and their children files (for envelopes)
299
         *
300
         * @return SignRequest[]
301
         */
302
        public function getByMultipleFileId(array $fileId) {
303
                $qb = $this->db->getQueryBuilder();
4✔
304

305
                $qb->select('sr.*')
4✔
306
                        ->from($this->getTableName(), 'sr')
4✔
307
                        ->join('sr', 'libresign_file', 'f', $qb->expr()->eq('sr.file_id', 'f.id'))
4✔
308
                        ->where(
4✔
309
                                $qb->expr()->orX(
4✔
310
                                        $qb->expr()->in('f.id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT_ARRAY)),
4✔
311
                                        $qb->expr()->in('f.parent_file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT_ARRAY))
4✔
312
                                )
4✔
313
                        )
4✔
314
                        ->orderBy('sr.id', 'ASC');
4✔
315

316
                /** @var SignRequest[] */
317
                return $this->findEntities($qb);
4✔
318
        }
319

320
        /**
321
         * Get all signers by fileId
322
         *
323
         * @return SignRequest[]
324
         */
325
        public function getByNodeId(int $nodeId) {
326
                $qb = $this->db->getQueryBuilder();
×
327

328
                $qb->select('sr.*')
×
329
                        ->from($this->getTableName(), 'sr')
×
330
                        ->join('sr', 'libresign_file', 'f', 'sr.file_id = f.id')
×
331
                        ->where(
×
332
                                $qb->expr()->eq('f.node_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT))
×
333
                        );
×
334

335
                /** @var SignRequest[] */
336
                $signers = $this->findEntities($qb);
×
337
                return $signers;
×
338
        }
339

340
        /**
341
         * Get all signers by File Uuid
342
         *
343
         * @param string $nodeId
344
         * @return SignRequest[]
345
         */
346
        public function getByFileUuid(string $uuid) {
347
                $qb = $this->db->getQueryBuilder();
1✔
348

349
                $qb->select('sr.*')
1✔
350
                        ->from($this->getTableName(), 'sr')
1✔
351
                        ->join('sr', 'libresign_file', 'f', 'sr.file_id = f.id')
1✔
352
                        ->where(
1✔
353
                                $qb->expr()->eq('f.uuid', $qb->createNamedParameter($uuid))
1✔
354
                        );
1✔
355

356
                /** @var SignRequest[] */
357
                $signers = $this->findEntities($qb);
1✔
358
                foreach ($signers as $signRequest) {
1✔
359
                        if (!isset($this->signers[$signRequest->getId()])) {
1✔
360
                                $this->signers[$signRequest->getId()] = $signRequest;
×
361
                        }
362
                }
363
                return $signers;
1✔
364
        }
365

366
        public function getBySignerUuidAndUserId(string $uuid): SignRequest {
367
                $qb = $this->db->getQueryBuilder();
×
368

369
                $qb->select('sr.*')
×
370
                        ->from($this->getTableName(), 'sr')
×
371
                        ->where(
×
372
                                $qb->expr()->eq('sr.uuid', $qb->createNamedParameter($uuid))
×
373
                        );
×
374

375
                /** @var SignRequest */
376
                $signRequest = $this->findEntity($qb);
×
377
                if (!isset($this->signers[$signRequest->getId()])) {
×
378
                        $this->signers[$signRequest->getId()] = $signRequest;
×
379
                }
380
                return $signRequest;
×
381
        }
382

383
        public function getByFileIdAndUserId(int $file_id): SignRequest {
384
                $qb = $this->db->getQueryBuilder();
×
385

386
                $qb->select('sr.*')
×
387
                        ->from($this->getTableName(), 'sr')
×
388
                        ->join('sr', 'libresign_file', 'f', 'sr.file_id = f.id')
×
389
                        ->where(
×
390
                                $qb->expr()->eq('f.node_id', $qb->createNamedParameter($file_id, IQueryBuilder::PARAM_INT))
×
391
                        );
×
392

393
                /** @var SignRequest */
394
                return $this->findEntity($qb);
×
395
        }
396

397
        public function getByFileIdAndEmail(int $file_id, string $email): SignRequest {
398
                $qb = $this->db->getQueryBuilder();
×
399

400
                $qb->select('sr.*')
×
401
                        ->from($this->getTableName(), 'sr')
×
402
                        ->join('sr', 'libresign_file', 'f', 'sr.file_id = f.id')
×
403
                        ->where(
×
404
                                $qb->expr()->eq('f.node_id', $qb->createNamedParameter($file_id, IQueryBuilder::PARAM_INT))
×
405
                        )
×
406
                        ->andWhere(
×
407
                                $qb->expr()->eq('sr.email', $qb->createNamedParameter($email))
×
408
                        );
×
409

410
                /** @var SignRequest */
411
                return $this->findEntity($qb);
×
412
        }
413

414
        public function getByFileIdAndSignRequestId(int $fileId, int $signRequestId): SignRequest {
415
                if (isset($this->signers[$signRequestId])) {
2✔
416
                        return $this->signers[$signRequestId];
2✔
417
                }
418
                $qb = $this->db->getQueryBuilder();
×
419

420
                $qb->select('sr.*')
×
421
                        ->from($this->getTableName(), 'sr')
×
422
                        ->where(
×
423
                                $qb->expr()->eq('sr.file_id', $qb->createNamedParameter($fileId))
×
424
                        )
×
425
                        ->andWhere(
×
426
                                $qb->expr()->eq('sr.id', $qb->createNamedParameter($signRequestId))
×
427
                        );
×
428

429
                $signRequest = $this->findEntity($qb);
×
430
                if (!isset($this->signers[$signRequest->getId()])) {
×
431
                        $this->signers[$signRequest->getId()] = $signRequest;
×
432
                }
433
                /** @var SignRequest */
434
                return end($this->signers);
×
435
        }
436

437
        /**
438
         * @return array{data: list<File>, pagination: Pagination}
439
         */
440
        public function getFilesAssociatedFilesWithMe(
441
                IUser $user,
442
                array $filter,
443
                ?int $page = null,
444
                ?int $length = null,
445
                ?array $sort = [],
446
        ): array {
447
                $filter['email'] = $user->getEMailAddress();
1✔
448
                $filter['length'] = $length;
1✔
449
                $filter['page'] = $page;
1✔
450
                $pagination = $this->getFilesAssociatedFilesWithMeStmt($user->getUID(), $filter, $sort);
1✔
451
                $pagination->setMaxPerPage($length);
1✔
452
                $pagination->setCurrentPage($page);
1✔
453
                $currentPageResults = $pagination->getCurrentPageResults();
1✔
454

455
                $data = [];
1✔
456
                foreach ($currentPageResults as $row) {
1✔
457
                        $file = new File();
×
458
                        $data[] = $file->fromRow($row);
×
459
                }
460
                /** @var array{data: list<File>, pagination: Pagination} */
461
                return [
1✔
462
                        'data' => $data,
1✔
463
                        'pagination' => $pagination,
1✔
464
                ];
1✔
465
        }
466

467
        /**
468
         * @param array<SignRequest> $signRequests
469
         * @return FileElement[][]
470
         */
471
        public function getVisibleElementsFromSigners(array $signRequests): array {
472
                $signRequestIds = array_map(fn (SignRequest $signRequest): int => $signRequest->getId(), $signRequests);
6✔
473
                if (!$signRequestIds) {
6✔
474
                        return [];
2✔
475
                }
476
                $qb = $this->db->getQueryBuilder();
4✔
477

478
                $qb->select('fe.*')
4✔
479
                        ->from('libresign_file_element', 'fe')
4✔
480
                        ->where(
4✔
481
                                $qb->expr()->in('fe.sign_request_id', $qb->createParameter('signRequestIds'))
4✔
482
                        );
4✔
483

484
                $return = [];
4✔
485
                foreach (array_chunk($signRequestIds, 1000) as $signRequestIdsChunk) {
4✔
486
                        $qb->setParameter('signRequestIds', $signRequestIdsChunk, IQueryBuilder::PARAM_INT_ARRAY);
4✔
487
                        $cursor = $qb->executeQuery();
4✔
488
                        while ($row = $cursor->fetch()) {
4✔
489
                                $return[$row['sign_request_id']][] = (new FileElement())->fromRow($row);
×
490
                        }
491
                }
492
                return $return;
4✔
493
        }
494

495
        /**
496
         * @param array<SignRequest> $signRequests
497
         * @return array<array-key, array<array-key, \OCP\AppFramework\Db\Entity&\OCA\Libresign\Db\IdentifyMethod>>
498
         */
499
        public function getIdentifyMethodsFromSigners(array $signRequests): array {
500
                $signRequestIds = array_map(fn (SignRequest $signRequest): int => $signRequest->getId(), $signRequests);
4✔
501
                if (!$signRequestIds) {
4✔
502
                        return [];
2✔
503
                }
504
                $qb = $this->db->getQueryBuilder();
2✔
505
                $qb->select('im.*')
2✔
506
                        ->from('libresign_identify_method', 'im')
2✔
507
                        ->where(
2✔
508
                                $qb->expr()->in('im.sign_request_id', $qb->createParameter('signRequestIds'))
2✔
509
                        )
2✔
510
                        ->orderBy('im.mandatory', 'DESC')
2✔
511
                        ->addOrderBy('im.identified_at_date', 'ASC');
2✔
512

513
                $return = [];
2✔
514
                foreach (array_chunk($signRequestIds, 1000) as $signRequestIdsChunk) {
2✔
515
                        $qb->setParameter('signRequestIds', $signRequestIdsChunk, IQueryBuilder::PARAM_INT_ARRAY);
2✔
516
                        $cursor = $qb->executeQuery();
2✔
517
                        while ($row = $cursor->fetch()) {
2✔
518
                                $identifyMethod = new IdentifyMethod();
2✔
519
                                $return[$row['sign_request_id']][$row['identifier_key']] = $identifyMethod->fromRow($row);
2✔
520
                        }
521
                }
522
                return $return;
2✔
523
        }
524

525
        public function getMyLibresignFile(string $userId, ?array $filter = []): File {
526
                $qb = $this->getFilesAssociatedFilesWithMeQueryBuilder(
×
527
                        userId: $userId,
×
528
                        filter: $filter,
×
529
                );
×
530
                $cursor = $qb->executeQuery();
×
531
                $row = $cursor->fetch();
×
532
                if (!$row) {
×
533
                        throw new DoesNotExistException('LibreSign file not found');
×
534
                }
535

536
                $file = new File();
×
537
                return $file->fromRow($row);
×
538
        }
539

540
        private function getFilesAssociatedFilesWithMeQueryBuilder(string $userId, array $filter = [], bool $count = false): IQueryBuilder {
541
                $qb = $this->db->getQueryBuilder();
1✔
542
                $qb->from('libresign_file', 'f')
1✔
543
                        ->leftJoin('f', 'libresign_sign_request', 'sr', 'sr.file_id = f.id')
1✔
544
                        ->leftJoin('f', 'libresign_identify_method', 'im', $qb->expr()->eq('sr.id', 'im.sign_request_id'))
1✔
545
                        ->leftJoin('f', 'libresign_id_docs', 'id', 'id.file_id = f.id');
1✔
546
                if ($count) {
1✔
547
                        $qb->select($qb->func()->count())
1✔
548
                                ->setFirstResult(0)
1✔
549
                                ->setMaxResults(null);
1✔
550
                } else {
551
                        $qb->select(
1✔
552
                                'f.id',
1✔
553
                                'f.node_id',
1✔
554
                                'f.signed_node_id',
1✔
555
                                'f.user_id',
1✔
556
                                'f.uuid',
1✔
557
                                'f.name',
1✔
558
                                'f.status',
1✔
559
                                'f.metadata',
1✔
560
                                'f.created_at',
1✔
561
                                'f.signature_flow',
1✔
562
                                'f.docmdp_level',
1✔
563
                                'f.node_type',
1✔
564
                                'f.parent_file_id'
1✔
565
                        )
1✔
566
                                ->groupBy(
1✔
567
                                        'f.id',
1✔
568
                                        'f.node_id',
1✔
569
                                        'f.signed_node_id',
1✔
570
                                        'f.user_id',
1✔
571
                                        'f.uuid',
1✔
572
                                        'f.name',
1✔
573
                                        'f.status',
1✔
574
                                        'f.created_at',
1✔
575
                                        'f.signature_flow',
1✔
576
                                        'f.docmdp_level',
1✔
577
                                        'f.node_type',
1✔
578
                                        'f.parent_file_id'
1✔
579
                                );
1✔
580
                        // metadata is a json column, the right way is to use f.metadata::text
581
                        // when the database is PostgreSQL. The problem is that the command
582
                        // addGroupBy add quotes over all text send as argument. With
583
                        // PostgreSQL json columns don't have problem if not added to group by.
584
                        if ($qb->getConnection()->getDatabaseProvider() !== IDBConnection::PLATFORM_POSTGRES) {
1✔
585
                                $qb->addGroupBy('f.metadata');
1✔
586
                        }
587
                        if (isset($filter['length']) && isset($filter['page'])) {
1✔
588
                                $qb->setFirstResult($filter['length'] * ($filter['page'] - 1));
1✔
589
                                $qb->setMaxResults($filter['length']);
1✔
590
                        }
591
                }
592

593
                $or = [
1✔
594
                        $qb->expr()->eq('f.user_id', $qb->createNamedParameter($userId)),
1✔
595
                        $qb->expr()->andX(
1✔
596
                                $qb->expr()->eq('im.identifier_key', $qb->createNamedParameter(IdentifyMethodService::IDENTIFY_ACCOUNT)),
1✔
597
                                $qb->expr()->eq('im.identifier_value', $qb->createNamedParameter($userId)),
1✔
598
                                $qb->expr()->neq('f.status', $qb->createNamedParameter(FileStatus::DRAFT->value)),
1✔
599
                                $qb->expr()->neq('sr.status', $qb->createNamedParameter(SignRequestStatus::DRAFT->value)),
1✔
600
                        )
1✔
601
                ];
1✔
602
                $qb->where($qb->expr()->orX(...$or))
1✔
603
                        ->andWhere($qb->expr()->isNull('id.id'));
1✔
604

605
                if ($filter) {
1✔
606
                        if (isset($filter['email']) && filter_var($filter['email'], FILTER_VALIDATE_EMAIL)) {
1✔
607
                                $or[] = $qb->expr()->andX(
×
608
                                        $qb->expr()->eq('im.identifier_key', $qb->createNamedParameter(IdentifyMethodService::IDENTIFY_EMAIL)),
×
609
                                        $qb->expr()->eq('im.identifier_value', $qb->createNamedParameter($filter['email']))
×
610
                                );
×
611
                        }
612
                        if (!empty($filter['signer_uuid']) && !empty($filter['parentFileId'])) {
1✔
613
                                $qb->leftJoin('f', 'libresign_file', 'parent', $qb->expr()->eq('f.parent_file_id', 'parent.id'));
×
614
                                $qb->innerJoin('parent', 'libresign_sign_request', 'psr', $qb->expr()->eq('psr.file_id', 'parent.id'))
×
615
                                        ->andWhere($qb->expr()->eq('psr.uuid', $qb->createNamedParameter($filter['signer_uuid'])));
×
616
                        } elseif (!empty($filter['signer_uuid'])) {
1✔
617
                                $qb->andWhere(
×
618
                                        $qb->expr()->eq('sr.uuid', $qb->createNamedParameter($filter['signer_uuid']))
×
619
                                );
×
620
                        }
621
                        if (!empty($filter['nodeIds'])) {
1✔
622
                                $qb->andWhere(
×
623
                                        $qb->expr()->orX(
×
624
                                                $qb->expr()->in('f.node_id', $qb->createNamedParameter($filter['nodeIds'], IQueryBuilder::PARAM_INT_ARRAY)),
×
625
                                                $qb->expr()->in('f.signed_node_id', $qb->createNamedParameter($filter['nodeIds'], IQueryBuilder::PARAM_INT_ARRAY))
×
626
                                        )
×
627
                                );
×
628
                        }
629
                        if (!empty($filter['fileIds'])) {
1✔
630
                                $qb->andWhere(
×
631
                                        $qb->expr()->in('f.id', $qb->createNamedParameter($filter['fileIds'], IQueryBuilder::PARAM_INT_ARRAY))
×
632
                                );
×
633
                        }
634
                        if (!empty($filter['status'])) {
1✔
635
                                $qb->andWhere(
×
636
                                        $qb->expr()->in('f.status', $qb->createNamedParameter($filter['status'], IQueryBuilder::PARAM_INT_ARRAY))
×
637
                                );
×
638
                        }
639
                        if (!empty($filter['start'])) {
1✔
640
                                $start = (new \DateTime('@' . $filter['start'], new \DateTimeZone('UTC')))->format('Y-m-d H:i:s');
×
641
                                $qb->andWhere(
×
642
                                        $qb->expr()->gte('f.created_at', $qb->createNamedParameter($start, IQueryBuilder::PARAM_STR))
×
643
                                );
×
644
                        }
645
                        if (!empty($filter['end'])) {
1✔
646
                                $end = (new \DateTime('@' . $filter['end'], new \DateTimeZone('UTC')))->format('Y-m-d H:i:s');
×
647
                                $qb->andWhere(
×
648
                                        $qb->expr()->lte('f.created_at', $qb->createNamedParameter($end, IQueryBuilder::PARAM_STR))
×
649
                                );
×
650
                        }
651
                        if (!empty($filter['parentFileId'])) {
1✔
652
                                $qb->andWhere(
×
653
                                        $qb->expr()->eq('f.parent_file_id', $qb->createNamedParameter($filter['parentFileId'], IQueryBuilder::PARAM_INT))
×
654
                                );
×
655
                        } else {
656
                                $qb->andWhere($qb->expr()->isNull('f.parent_file_id'));
1✔
657
                        }
658
                } else {
659
                        $qb->andWhere($qb->expr()->isNull('f.parent_file_id'));
×
660
                }
661
                return $qb;
1✔
662
        }
663

664
        private function getFilesAssociatedFilesWithMeStmt(
665
                string $userId,
666
                ?array $filter = [],
667
                ?array $sort = [],
668
        ): Pagination {
669
                $qb = $this->getFilesAssociatedFilesWithMeQueryBuilder($userId, $filter);
1✔
670
                if (!empty($sort['sortBy'])) {
1✔
671
                        switch ($sort['sortBy']) {
×
672
                                case 'name':
×
673
                                case 'status':
×
674
                                        $qb->orderBy(
×
675
                                                $qb->func()->lower('f.' . $sort['sortBy']),
×
676
                                                $sort['sortDirection'] == 'asc' ? 'asc' : 'desc'
×
677
                                        );
×
678
                                        break;
×
679
                                case 'created_at':
×
680
                                        $qb->orderBy(
×
681
                                                'f.' . $sort['sortBy'],
×
682
                                                $sort['sortDirection'] == 'asc' ? 'asc' : 'desc'
×
683
                                        );
×
684
                        }
685
                }
686

687
                $countQb = $this->getFilesAssociatedFilesWithMeQueryBuilder(
1✔
688
                        userId: $userId,
1✔
689
                        filter: $filter,
1✔
690
                        count: true,
1✔
691
                );
1✔
692

693
                $pagination = new Pagination($qb, $this->urlGenerator, $countQb);
1✔
694
                return $pagination;
1✔
695
        }
696

697
        public function getTextOfSignerStatus(int $status): string {
698
                return SignRequestStatus::from($status)->getLabel($this->l10n);
4✔
699
        }
700
}
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