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

LibreSign / libresign / 20606697273

30 Dec 2025 09:53PM UTC coverage: 44.868%. First build
20606697273

Pull #6277

github

web-flow
Merge edce7a9fa into 1098b4452
Pull Request #6277: fix: use nodeId for user element

19 of 56 new or added lines in 9 files covered. (33.93%)

6610 of 14732 relevant lines covered (44.87%)

5.08 hits per line

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

46.32
/lib/Db/FileMapper.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\NodeType;
13
use OCP\AppFramework\Db\DoesNotExistException;
14
use OCP\AppFramework\Db\QBMapper;
15
use OCP\Comments\ICommentsManager;
16
use OCP\DB\QueryBuilder\IQueryBuilder;
17
use OCP\IDBConnection;
18
use OCP\IL10N;
19

20
/**
21
 * Class FileMapper
22
 *
23
 * @package OCA\Libresign\DB
24
 * @template-extends QBMapper<File>
25
 */
26
class FileMapper extends QBMapper {
27
        /** @var File[] */
28
        private $file = [];
29

30
        public function __construct(
31
                IDBConnection $db,
32
                private IL10N $l,
33
        ) {
34
                parent::__construct($db, 'libresign_file');
47✔
35
        }
36

37
        /**
38
         * Return LibreSign file by ID
39
         *
40
         * @throws DoesNotExistException
41
         * @return File Row of table libresign_file
42
         */
43
        public function getById(int $id): File {
44
                foreach ($this->file as $file) {
17✔
45
                        if ($file->getId() === $id) {
15✔
46
                                return $file;
15✔
47
                        }
48
                }
49
                $qb = $this->db->getQueryBuilder();
15✔
50

51
                $qb->select('*')
15✔
52
                        ->from($this->getTableName())
15✔
53
                        ->where(
15✔
54
                                $qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))
15✔
55
                        );
15✔
56

57
                /** @var File */
58
                $file = $this->findEntity($qb);
15✔
59
                $this->file[] = $file;
13✔
60
                return $file;
13✔
61
        }
62

63
        /**
64
         * Return LibreSign file by signed hash
65
         *
66
         * @throws DoesNotExistException
67
         * @return File Row of table libresign_file
68
         */
69
        public function getBySignedHash(string $hash): File {
70
                foreach ($this->file as $file) {
×
71
                        if ($file->getSignedHash() === $hash) {
×
72
                                return $file;
×
73
                        }
74
                }
75
                $qb = $this->db->getQueryBuilder();
×
76

77
                $qb->select('f.*')
×
78
                        ->from($this->getTableName(), 'f')
×
79
                        ->join('f', 'libresign_sign_request', 'sr', $qb->expr()->eq('f.id', 'sr.file_id'))
×
80
                        ->where(
×
81
                                $qb->expr()->orX(
×
82
                                        $qb->expr()->eq('f.signed_hash', $qb->createNamedParameter($hash)),
×
83
                                        $qb->expr()->eq('sr.signed_hash', $qb->createNamedParameter($hash))
×
84
                                )
×
85
                        )
×
86
                        ->setMaxResults(1);
×
87

88
                /** @var File */
89
                $file = $this->findEntity($qb);
×
90
                $this->file[] = $file;
×
91
                return $file;
×
92
        }
93

94
        /**
95
         * Return LibreSign file by file UUID
96
         */
97
        public function getByUuid(?string $uuid = null): File {
98
                if (is_null($uuid) && !empty($this->file)) {
7✔
99
                        return current($this->file);
×
100
                }
101
                foreach ($this->file as $file) {
7✔
102
                        if ($file->getUuid() === $uuid) {
6✔
103
                                return $file;
6✔
104
                        }
105
                }
106
                $qb = $this->db->getQueryBuilder();
3✔
107

108
                $qb->select('*')
3✔
109
                        ->from($this->getTableName())
3✔
110
                        ->where(
3✔
111
                                $qb->expr()->eq('uuid', $qb->createNamedParameter($uuid))
3✔
112
                        );
3✔
113

114
                /** @var File */
115
                $file = $this->findEntity($qb);
3✔
116
                $this->file[] = $file;
2✔
117
                return $file;
2✔
118
        }
119

120
        /**
121
         * Return LibreSign file by signer UUID
122
         */
123
        public function getBySignerUuid(?string $uuid = null): File {
124
                if (is_null($uuid) && !empty($this->file)) {
1✔
125
                        return current($this->file);
×
126
                }
127
                $qb = $this->db->getQueryBuilder();
1✔
128

129
                $qb->select('f.*')
1✔
130
                        ->from($this->getTableName(), 'f')
1✔
131
                        ->join('f', 'libresign_sign_request', 'sr', $qb->expr()->eq('f.id', 'sr.file_id'))
1✔
132
                        ->where(
1✔
133
                                $qb->expr()->eq('sr.uuid', $qb->createNamedParameter($uuid))
1✔
134
                        );
1✔
135

136
                /** @var File */
137
                $file = $this->findEntity($qb);
1✔
138
                $this->file[] = $file;
×
139
                return $file;
×
140
        }
141

142
        /**
143
         * Return LibreSign file by nodeId
144
         */
145
        public function getByNodeId(?int $nodeId = null): File {
146
                $exists = array_filter($this->file, fn ($f) => $f->getNodeId() === $nodeId || $f->getSignedNodeId() === $nodeId);
2✔
147
                if (!empty($exists)) {
2✔
148
                        return current($exists);
1✔
149
                }
150
                foreach ($this->file as $file) {
1✔
151
                        if ($file->getNodeId() === $nodeId) {
×
152
                                return $file;
×
153
                        }
154
                }
155
                $qb = $this->db->getQueryBuilder();
1✔
156

157
                $qb->select('*')
1✔
158
                        ->from($this->getTableName())
1✔
159
                        ->where(
1✔
160
                                $qb->expr()->orX(
1✔
161
                                        $qb->expr()->eq('node_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT)),
1✔
162
                                        $qb->expr()->eq('signed_node_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT))
1✔
163
                                )
1✔
164
                        );
1✔
165

166
                /** @var File */
167
                $file = $this->findEntity($qb);
1✔
168
                $this->file[] = $file;
×
169
                return $file;
×
170
        }
171

172
        public function fileIdExists(int $nodeId): bool {
173
                $exists = array_filter($this->file, fn ($f) => $f->getNodeId() === $nodeId || $f->getSignedNodeId() === $nodeId);
×
174
                if (!empty($exists)) {
×
175
                        return true;
×
176
                }
177

178
                $qb = $this->db->getQueryBuilder();
×
179

180
                $qb->select('*')
×
181
                        ->from($this->getTableName())
×
182
                        ->where(
×
183
                                $qb->expr()->orX(
×
184
                                        $qb->expr()->eq('node_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT)),
×
185
                                        $qb->expr()->eq('signed_node_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT))
×
186
                                )
×
187
                        );
×
188

189
                $files = $this->findEntities($qb);
×
190
                if (!empty($files)) {
×
191
                        foreach ($files as $file) {
×
192
                                $this->file[] = $file;
×
193
                        }
194
                        return true;
×
195
                }
196
                return false;
×
197
        }
198

199
        /**
200
         * @return File[]
201
         */
202
        public function getFilesOfAccount(string $userId): array {
203
                $qb = $this->db->getQueryBuilder();
×
204

205
                $qb->select('lf.*')
×
206
                        ->from($this->getTableName(), 'lf')
×
207
                        ->join('lf', 'libresign_id_docs', 'lid', 'lid.file_id = lf.id')
×
208
                        ->where(
×
209
                                $qb->expr()->eq('lid.user_id', $qb->createNamedParameter($userId))
×
210
                        );
×
211

212
                $cursor = $qb->executeQuery();
×
213
                $return = [];
×
214
                while ($row = $cursor->fetch()) {
×
215
                        /** @var File */
216
                        $file = $this->mapRowToEntity($row);
×
217
                        $this->file[] = $file;
×
218
                        $return[] = $file;
×
219
                }
220
                return $return;
×
221
        }
222

223
        public function getDeletionContext(int $nodeId): array {
224
                $fullOuterJoin = $this->db->getQueryBuilder();
36✔
225
                $fullOuterJoin->select($fullOuterJoin->expr()->literal(1));
36✔
226

227
                $qb = $this->db->getQueryBuilder();
36✔
228
                $qb
36✔
229
                        ->selectAlias('f.id', 'file_id')
36✔
230
                        ->addSelect('sf.id', 'signed_file_id')
36✔
231
                        ->addSelect('ue.id', 'user_element_id')
36✔
232
                        ->addSelect('fe.file_id', 'file_element_file_id')
36✔
233
                        ->from($qb->createFunction('(' . $fullOuterJoin->getSQL() . ')'), 'foj')
36✔
234
                        ->leftJoin('foj', 'libresign_file', 'f', $qb->expr()->eq('f.node_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT)))
36✔
235
                        ->leftJoin('foj', 'libresign_file', 'sf', $qb->expr()->eq('sf.signed_node_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT)))
36✔
236
                        ->leftJoin('foj', 'libresign_user_element', 'ue', $qb->expr()->eq('ue.node_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT)))
36✔
237
                        ->leftJoin('foj', 'libresign_file_element', 'fe', $qb->expr()->eq('fe.file_id', 'f.id'))
36✔
238
                        ->setMaxResults(1);
36✔
239

240
                $row = $qb->executeQuery()->fetchAssociative();
36✔
241
                if (!$row) {
36✔
NEW
242
                        return ['type' => 'not_libresign_file', 'fileId' => null];
×
243
                }
244

245
                if (!empty($row['signed_file_id'])) {
36✔
NEW
246
                        return ['type' => 'signed_file', 'fileId' => (int)$row['signed_file_id']];
×
247
                }
248
                if (!empty($row['file_id'])) {
36✔
NEW
249
                        return ['type' => 'file', 'fileId' => (int)$row['file_id']];
×
250
                }
251
                if (!empty($row['user_element_id'])) {
36✔
NEW
252
                        return ['type' => 'user_element', 'fileId' => null];
×
253
                }
254
                if (!empty($row['file_element_file_id'])) {
36✔
NEW
255
                        return ['type' => 'file_element', 'fileId' => (int)$row['file_element_file_id']];
×
256
                }
257

258
                return ['type' => 'not_libresign_file', 'fileId' => null];
36✔
259
        }
260

261
        public function getTextOfStatus(int|FileStatus $status): string {
262
                if (is_int($status)) {
5✔
263
                        $status = FileStatus::from($status);
5✔
264
                }
265
                return $status->getLabel($this->l);
5✔
266
        }
267

268
        public function neutralizeDeletedUser(string $userId, string $displayName): void {
269
                $update = $this->db->getQueryBuilder();
×
270
                $qb = $this->db->getQueryBuilder();
×
271
                $qb->select('f.id')
×
272
                        ->addSelect('f.metadata')
×
273
                        ->from($this->getTableName(), 'f')
×
274
                        ->where($qb->expr()->eq('f.user_id', $qb->createNamedParameter($userId)));
×
275
                $cursor = $qb->executeQuery();
×
276
                while ($row = $cursor->fetch()) {
×
277
                        $row['metadata'] = json_decode((string)$row['metadata'], true);
×
278
                        $row['metadata']['deleted_account'] = [
×
279
                                'account' => $userId,
×
280
                                'display_name' => $displayName,
×
281
                        ];
×
282
                        $update->update($this->getTableName())
×
283
                                ->set('user_id', $update->createNamedParameter(ICommentsManager::DELETED_USER))
×
284
                                ->set('metadata', $update->createNamedParameter($row['metadata'], IQueryBuilder::PARAM_JSON))
×
285
                                ->where($update->expr()->eq('id', $update->createNamedParameter($row['id'])));
×
286
                        $update->executeStatement();
×
287
                }
288
        }
289

290
        /**
291
         * @return File[]
292
         */
293
        public function getChildrenFiles(int $parentId): array {
294
                $cached = array_filter($this->file, fn ($f) => $f->getParentFileId() === $parentId);
2✔
295
                if (!empty($cached) && count($cached) > 1) {
2✔
296
                        return array_values($cached);
×
297
                }
298

299
                $qb = $this->db->getQueryBuilder();
2✔
300

301
                $qb->select('*')
2✔
302
                        ->from($this->getTableName())
2✔
303
                        ->where(
2✔
304
                                $qb->expr()->eq('parent_file_id', $qb->createNamedParameter($parentId, IQueryBuilder::PARAM_INT))
2✔
305
                        )
2✔
306
                        ->andWhere(
2✔
307
                                $qb->expr()->eq('node_type', $qb->createNamedParameter(NodeType::FILE->value))
2✔
308
                        )
2✔
309
                        ->orderBy('id', 'ASC');
2✔
310

311
                $children = $this->findEntities($qb);
2✔
312

313
                foreach ($children as $child) {
2✔
314
                        $this->file[] = $child;
×
315
                }
316

317
                return $children;
2✔
318
        }
319

320
        public function getParentEnvelope(int $fileId): ?File {
321
                $file = $this->getById($fileId);
×
322

323
                if (!$file->hasParent()) {
×
324
                        return null;
×
325
                }
326

327
                return $this->getById($file->getParentFileId());
×
328
        }
329

330
        public function countChildrenFiles(int $envelopeId): int {
331
                $cached = array_filter($this->file, fn ($f) => $f->getParentFileId() === $envelopeId);
×
332
                if (!empty($cached)) {
×
333
                        return count($cached);
×
334
                }
335

336
                $qb = $this->db->getQueryBuilder();
×
337

338
                $qb->select($qb->func()->count('*', 'count'))
×
339
                        ->from($this->getTableName())
×
340
                        ->where(
×
341
                                $qb->expr()->eq('parent_file_id', $qb->createNamedParameter($envelopeId, IQueryBuilder::PARAM_INT))
×
342
                        )
×
343
                        ->andWhere(
×
344
                                $qb->expr()->eq('node_type', $qb->createNamedParameter(NodeType::FILE->value))
×
345
                        );
×
346

347
                $cursor = $qb->executeQuery();
×
348
                $row = $cursor->fetch();
×
349
                $cursor->closeCursor();
×
350

351
                return $row ? (int)$row['count'] : 0;
×
352
        }
353
}
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