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

LibreSign / libresign / 21182715382

20 Jan 2026 06:23PM UTC coverage: 44.208%. First build
21182715382

Pull #6243

github

web-flow
Merge e224ea5b9 into ec977726d
Pull Request #6243: feat: unified search

4 of 86 new or added lines in 2 files covered. (4.65%)

7037 of 15918 relevant lines covered (44.21%)

4.92 hits per line

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

48.6
/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\IDBConnection;
21
use OCP\IL10N;
22
use OCP\IURLGenerator;
23
use OCP\IUser;
24

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

38
        public function __construct(
39
                IDBConnection $db,
40
                protected IL10N $l10n,
41
                protected FileMapper $fileMapper,
42
                private IURLGenerator $urlGenerator,
43
        ) {
44
                parent::__construct($db, 'libresign_sign_request');
47✔
45
        }
46

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

59
                        $notificationEntry = [
13✔
60
                                'method' => $method,
13✔
61
                                'date' => time(),
13✔
62
                        ];
13✔
63

64
                        if (!empty($fromDatabase->getDescription())) {
13✔
65
                                $notificationEntry['description'] = $fromDatabase->getDescription();
×
66
                        }
67

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

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

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

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

115
        public function getByEmailAndFileId(string $email, int $fileId): SignRequest {
116
                $qb = $this->db->getQueryBuilder();
×
117

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

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

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

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

163
        public function flushCache(?int $signRequestId = null): void {
164
                if ($signRequestId !== null) {
×
165
                        unset($this->signers[$signRequestId]);
×
166
                } else {
167
                        $this->signers = [];
×
168
                }
169
        }
170

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

180
                $qb->select('*')
14✔
181
                        ->from($this->getTableName())
14✔
182
                        ->where(
14✔
183
                                $qb->expr()->eq('id', $qb->createNamedParameter($signRequestId, IQueryBuilder::PARAM_INT))
14✔
184
                        );
14✔
185

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

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

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

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

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

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

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

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

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

312
                /** @var SignRequest[] */
313
                return $this->findEntities($qb);
4✔
314
        }
315

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

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

331
                /** @var SignRequest[] */
332
                $signers = $this->findEntities($qb);
×
333
                return $signers;
×
334
        }
335

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

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

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

362
        public function getBySignerUuidAndUserId(string $uuid): SignRequest {
363
                $qb = $this->db->getQueryBuilder();
×
364

365
                $qb->select('sr.*')
×
366
                        ->from($this->getTableName(), 'sr')
×
367
                        ->where(
×
368
                                $qb->expr()->eq('sr.uuid', $qb->createNamedParameter($uuid))
×
369
                        );
×
370

371
                /** @var SignRequest */
372
                $signRequest = $this->findEntity($qb);
×
373
                if (!isset($this->signers[$signRequest->getId()])) {
×
374
                        $this->signers[$signRequest->getId()] = $signRequest;
×
375
                }
376
                return $signRequest;
×
377
        }
378

379
        public function getByFileIdAndUserId(int $file_id): SignRequest {
380
                $qb = $this->db->getQueryBuilder();
×
381

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

389
                /** @var SignRequest */
390
                return $this->findEntity($qb);
×
391
        }
392

393
        public function getByFileIdAndEmail(int $file_id, string $email): SignRequest {
394
                $qb = $this->db->getQueryBuilder();
×
395

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

406
                /** @var SignRequest */
407
                return $this->findEntity($qb);
×
408
        }
409

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

416
                $qb->select('sr.*')
×
417
                        ->from($this->getTableName(), 'sr')
×
418
                        ->where(
×
419
                                $qb->expr()->eq('sr.file_id', $qb->createNamedParameter($fileId))
×
420
                        )
×
421
                        ->andWhere(
×
422
                                $qb->expr()->eq('sr.id', $qb->createNamedParameter($signRequestId))
×
423
                        );
×
424

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

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

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

463
        public function getFilesToSearchProvider(IUser $user, string $fileName, int $limit, int $offset): array {
NEW
464
                $filter = [
×
NEW
465
                        'page' => ($offset / $limit) + 1,
×
NEW
466
                        'length' => $limit,
×
NEW
467
                        'fileName' => $fileName,
×
NEW
468
                ];
×
469

NEW
470
                $sort = [
×
NEW
471
                        'sortBy' => 'created_at',
×
NEW
472
                        'sortDirection' => 'desc',
×
NEW
473
                ];
×
474

NEW
475
                $qb = $this->getFilesAssociatedFilesWithMeQueryBuilder($user->getUID(), $filter, false, $sort);
×
476

NEW
477
                $result = $qb->executeQuery();
×
NEW
478
                $files = [];
×
479

NEW
480
                while ($row = $result->fetch()) {
×
481
                        try {
NEW
482
                                $file = File::fromRow($row);
×
483

NEW
484
                                $files[] = $file;
×
NEW
485
                        } catch (\Exception $e) {
×
NEW
486
                                continue;
×
487
                        }
488
                }
489

NEW
490
                $result->closeCursor();
×
491

NEW
492
                return $files;
×
493
        }
494

495
        /**
496
         * @param array<SignRequest> $signRequests
497
         * @return FileElement[][]
498
         */
499
        public function getVisibleElementsFromSigners(array $signRequests): array {
500
                $signRequestIds = array_map(fn (SignRequest $signRequest): int => $signRequest->getId(), $signRequests);
6✔
501
                if (!$signRequestIds) {
6✔
502
                        return [];
2✔
503
                }
504
                $qb = $this->db->getQueryBuilder();
4✔
505

506
                $qb->select('fe.*')
4✔
507
                        ->from('libresign_file_element', 'fe')
4✔
508
                        ->where(
4✔
509
                                $qb->expr()->in('fe.sign_request_id', $qb->createParameter('signRequestIds'))
4✔
510
                        );
4✔
511

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

523
        /**
524
         * @param array<SignRequest> $signRequests
525
         * @return array<array-key, array<array-key, \OCP\AppFramework\Db\Entity&\OCA\Libresign\Db\IdentifyMethod>>
526
         */
527
        public function getIdentifyMethodsFromSigners(array $signRequests): array {
528
                $signRequestIds = array_map(fn (SignRequest $signRequest): int => $signRequest->getId(), $signRequests);
4✔
529
                if (!$signRequestIds) {
4✔
530
                        return [];
2✔
531
                }
532
                $qb = $this->db->getQueryBuilder();
2✔
533
                $qb->select('im.*')
2✔
534
                        ->from('libresign_identify_method', 'im')
2✔
535
                        ->where(
2✔
536
                                $qb->expr()->in('im.sign_request_id', $qb->createParameter('signRequestIds'))
2✔
537
                        )
2✔
538
                        ->orderBy('im.mandatory', 'DESC')
2✔
539
                        ->addOrderBy('im.identified_at_date', 'ASC');
2✔
540

541
                $return = [];
2✔
542
                foreach (array_chunk($signRequestIds, 1000) as $signRequestIdsChunk) {
2✔
543
                        $qb->setParameter('signRequestIds', $signRequestIdsChunk, IQueryBuilder::PARAM_INT_ARRAY);
2✔
544
                        $cursor = $qb->executeQuery();
2✔
545
                        while ($row = $cursor->fetch()) {
2✔
546
                                $identifyMethod = new IdentifyMethod();
2✔
547
                                $return[$row['sign_request_id']][$row['identifier_key']] = $identifyMethod->fromRow($row);
2✔
548
                        }
549
                }
550
                return $return;
2✔
551
        }
552

553
        public function getMyLibresignFile(string $userId, ?array $filter = []): File {
554
                $qb = $this->getFilesAssociatedFilesWithMeQueryBuilder(
×
555
                        userId: $userId,
×
556
                        filter: $filter,
×
557
                );
×
558
                $cursor = $qb->executeQuery();
×
559
                $row = $cursor->fetch();
×
560
                if (!$row) {
×
561
                        throw new DoesNotExistException('LibreSign file not found');
×
562
                }
563

564
                $file = new File();
×
565
                return $file->fromRow($row);
×
566
        }
567

568
        private function getFilesAssociatedFilesWithMeQueryBuilder(
569
                        string $userId,
570
                        array $filter = [],
571
                        bool $count = false,
572
                        array $sort = []
573
                ): IQueryBuilder {
574
                $qb = $this->db->getQueryBuilder();
1✔
575
                $qb->from('libresign_file', 'f')
1✔
576
                        ->leftJoin('f', 'libresign_sign_request', 'sr', 'sr.file_id = f.id')
1✔
577
                        ->leftJoin('f', 'libresign_identify_method', 'im', $qb->expr()->eq('sr.id', 'im.sign_request_id'))
1✔
578
                        ->leftJoin('f', 'libresign_id_docs', 'id', 'id.file_id = f.id');
1✔
579
                if ($count) {
1✔
580
                        $qb->select($qb->func()->count())
1✔
581
                                ->setFirstResult(0)
1✔
582
                                ->setMaxResults(null);
1✔
583
                } else {
584
                        $qb->select(
1✔
585
                                'f.id',
1✔
586
                                'f.node_id',
1✔
587
                                'f.signed_node_id',
1✔
588
                                'f.user_id',
1✔
589
                                'f.uuid',
1✔
590
                                'f.name',
1✔
591
                                'f.status',
1✔
592
                                'f.metadata',
1✔
593
                                'f.created_at',
1✔
594
                                'f.signature_flow',
1✔
595
                                'f.docmdp_level',
1✔
596
                                'f.node_type',
1✔
597
                                'f.parent_file_id'
1✔
598
                        )
1✔
599
                                ->groupBy(
1✔
600
                                        'f.id',
1✔
601
                                        'f.node_id',
1✔
602
                                        'f.signed_node_id',
1✔
603
                                        'f.user_id',
1✔
604
                                        'f.uuid',
1✔
605
                                        'f.name',
1✔
606
                                        'f.status',
1✔
607
                                        'f.created_at',
1✔
608
                                        'f.signature_flow',
1✔
609
                                        'f.docmdp_level',
1✔
610
                                        'f.node_type',
1✔
611
                                        'f.parent_file_id'
1✔
612
                                );
1✔
613
                        // metadata is a json column, the right way is to use f.metadata::text
614
                        // when the database is PostgreSQL. The problem is that the command
615
                        // addGroupBy add quotes over all text send as argument. With
616
                        // PostgreSQL json columns don't have problem if not added to group by.
617
                        if ($qb->getConnection()->getDatabaseProvider() !== IDBConnection::PLATFORM_POSTGRES) {
1✔
618
                                $qb->addGroupBy('f.metadata');
1✔
619
                        }
620
                        if (isset($filter['length']) && isset($filter['page'])) {
1✔
621
                                $qb->setFirstResult($filter['length'] * ($filter['page'] - 1));
1✔
622
                                $qb->setMaxResults($filter['length']);
1✔
623
                        }
624
                }
625

626
                $or = [
1✔
627
                        $qb->expr()->eq('f.user_id', $qb->createNamedParameter($userId)),
1✔
628
                        $qb->expr()->andX(
1✔
629
                                $qb->expr()->eq('im.identifier_key', $qb->createNamedParameter(IdentifyMethodService::IDENTIFY_ACCOUNT)),
1✔
630
                                $qb->expr()->eq('im.identifier_value', $qb->createNamedParameter($userId)),
1✔
631
                                $qb->expr()->neq('f.status', $qb->createNamedParameter(FileStatus::DRAFT->value)),
1✔
632
                                $qb->expr()->neq('sr.status', $qb->createNamedParameter(SignRequestStatus::DRAFT->value)),
1✔
633
                        )
1✔
634
                ];
1✔
635
                $qb->where($qb->expr()->orX(...$or))
1✔
636
                        ->andWhere($qb->expr()->isNull('id.id'));
1✔
637

638
                if ($filter) {
1✔
639
                        if (isset($filter['email']) && filter_var($filter['email'], FILTER_VALIDATE_EMAIL)) {
1✔
640
                                $or[] = $qb->expr()->andX(
×
641
                                        $qb->expr()->eq('im.identifier_key', $qb->createNamedParameter(IdentifyMethodService::IDENTIFY_EMAIL)),
×
642
                                        $qb->expr()->eq('im.identifier_value', $qb->createNamedParameter($filter['email']))
×
643
                                );
×
644
                        }
645
                        if (!empty($filter['signer_uuid']) && !empty($filter['parentFileId'])) {
1✔
646
                                $qb->leftJoin('f', 'libresign_file', 'parent', $qb->expr()->eq('f.parent_file_id', 'parent.id'));
×
647
                                $qb->innerJoin('parent', 'libresign_sign_request', 'psr', $qb->expr()->eq('psr.file_id', 'parent.id'))
×
648
                                        ->andWhere($qb->expr()->eq('psr.uuid', $qb->createNamedParameter($filter['signer_uuid'])));
×
649
                        } elseif (!empty($filter['signer_uuid'])) {
1✔
650
                                $qb->andWhere(
×
651
                                        $qb->expr()->eq('sr.uuid', $qb->createNamedParameter($filter['signer_uuid']))
×
652
                                );
×
653
                        }
654
                        if (!empty($filter['nodeIds'])) {
1✔
655
                                $qb->andWhere(
×
656
                                        $qb->expr()->orX(
×
657
                                                $qb->expr()->in('f.node_id', $qb->createNamedParameter($filter['nodeIds'], IQueryBuilder::PARAM_INT_ARRAY)),
×
658
                                                $qb->expr()->in('f.signed_node_id', $qb->createNamedParameter($filter['nodeIds'], IQueryBuilder::PARAM_INT_ARRAY))
×
659
                                        )
×
660
                                );
×
661
                        }
662
                        if (!empty($filter['fileIds'])) {
1✔
663
                                $qb->andWhere(
×
664
                                        $qb->expr()->in('f.id', $qb->createNamedParameter($filter['fileIds'], IQueryBuilder::PARAM_INT_ARRAY))
×
665
                                );
×
666
                        }
667
                        if (!empty($filter['status'])) {
1✔
668
                                $qb->andWhere(
×
669
                                        $qb->expr()->in('f.status', $qb->createNamedParameter($filter['status'], IQueryBuilder::PARAM_INT_ARRAY))
×
670
                                );
×
671
                        }
672
                        if (!empty($filter['start'])) {
1✔
673
                                $start = (new \DateTime('@' . $filter['start'], new \DateTimeZone('UTC')))->format('Y-m-d H:i:s');
×
674
                                $qb->andWhere(
×
675
                                        $qb->expr()->gte('f.created_at', $qb->createNamedParameter($start, IQueryBuilder::PARAM_STR))
×
676
                                );
×
677
                        }
678
                        if (!empty($filter['end'])) {
1✔
679
                                $end = (new \DateTime('@' . $filter['end'], new \DateTimeZone('UTC')))->format('Y-m-d H:i:s');
×
680
                                $qb->andWhere(
×
681
                                        $qb->expr()->lte('f.created_at', $qb->createNamedParameter($end, IQueryBuilder::PARAM_STR))
×
682
                                );
×
683
                        }
684
                        if (!empty($filter['fileName'])) {
1✔
NEW
685
                                $qb->andWhere(
×
NEW
686
                                        $qb->expr()->like('f.name', $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($filter['fileName']) . '%'))
×
NEW
687
                                );
×
688
                        }
689
                        if (!empty($filter['parentFileId'])) {
1✔
690
                                $qb->andWhere(
×
691
                                        $qb->expr()->eq('f.parent_file_id', $qb->createNamedParameter($filter['parentFileId'], IQueryBuilder::PARAM_INT))
×
692
                                );
×
693
                        } else {
694
                                $qb->andWhere($qb->expr()->isNull('f.parent_file_id'));
1✔
695
                        }
696
                }
697

698
                if (!empty($sort['sortBy']) && !empty($sort['sortDirection'])) {
1✔
699
                        switch ($sort['sortBy']) {
×
700
                                case 'name':
×
701
                                case 'status':
×
702
                                        $qb->orderBy(
×
703
                                                $qb->func()->lower('f.' . $sort['sortBy']),
×
704
                                                $sort['sortDirection'] == 'asc' ? 'asc' : 'desc'
×
705
                                        );
×
706
                                        break;
×
707
                                case 'created_at':
×
708
                                        $qb->orderBy(
×
709
                                                'f.' . $sort['sortBy'],
×
710
                                                $sort['sortDirection'] == 'asc' ? 'asc' : 'desc'
×
711
                                        );
×
712
                        }
713
                }
714

715
                return $qb;
1✔
716
        }
717

718
        private function getFilesAssociatedFilesWithMeStmt(
719
                string $userId,
720
                ?array $filter = [],
721
                ?array $sort = [],
722
        ): Pagination {
723
                $qb = $this->getFilesAssociatedFilesWithMeQueryBuilder($userId, $filter, false, $sort);
1✔
724

725
                $countQb = $this->getFilesAssociatedFilesWithMeQueryBuilder(
1✔
726
                        userId: $userId,
1✔
727
                        filter: $filter,
1✔
728
                        count: true,
1✔
729
                );
1✔
730

731
                $pagination = new Pagination($qb, $this->urlGenerator, $countQb);
1✔
732
                return $pagination;
1✔
733
        }
734

735
        public function getTextOfSignerStatus(int $status): string {
736
                return SignRequestStatus::from($status)->getLabel($this->l10n);
4✔
737
        }
738
}
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