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

LibreSign / libresign / 21191404942

20 Jan 2026 11:40PM UTC coverage: 44.316%. First build
21191404942

Pull #6461

github

web-flow
Merge f848257c7 into ec977726d
Pull Request #6461: fix: visible elements in envelope context

76 of 169 new or added lines in 5 files covered. (44.97%)

7076 of 15967 relevant lines covered (44.32%)

4.93 hits per line

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

76.0
/lib/Service/FileElementService.php
1
<?php
2

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

9
namespace OCA\Libresign\Service;
10

11
use OCA\Libresign\Db\File;
12
use OCA\Libresign\Db\FileElement;
13
use OCA\Libresign\Db\FileElementMapper;
14
use OCA\Libresign\Db\FileMapper;
15
use OCA\Libresign\ResponseDefinitions;
16
use OCP\AppFramework\Utility\ITimeFactory;
17

18
/**
19
 * @psalm-import-type LibresignVisibleElement from ResponseDefinitions
20
 */
21
class FileElementService {
22
        public function __construct(
23
                private FileMapper $fileMapper,
24
                private FileElementMapper $fileElementMapper,
25
                private ITimeFactory $timeFactory,
26
        ) {
27
        }
36✔
28

29
        public function saveVisibleElement(array $element): FileElement {
30
                $fileElement = $this->getVisibleElementFromProperties($element);
2✔
31
                if ($fileElement->getId()) {
2✔
32
                        $this->fileElementMapper->update($fileElement);
1✔
33
                } else {
34
                        $this->fileElementMapper->insert($fileElement);
1✔
35
                }
36
                return $fileElement;
2✔
37
        }
38

39
        private function getVisibleElementFromProperties(array $properties): FileElement {
40
                if (!empty($properties['elementId'])) {
2✔
41
                        $fileElement = $this->fileElementMapper->getById($properties['elementId']);
1✔
42
                } else {
43
                        $fileElement = new FileElement();
1✔
44
                        $fileElement->setCreatedAt($this->timeFactory->getDateTime());
1✔
45
                }
46
                $file = null;
2✔
47
                if (!empty($properties['uuid'])) {
2✔
48
                        $file = $this->fileMapper->getByUuid($properties['uuid']);
2✔
49
                        $fileElement->setFileId($file->getId());
2✔
50
                } elseif (!empty($properties['fileId'])) {
×
51
                        $file = $this->fileMapper->getById($properties['fileId']);
×
52
                        $fileElement->setFileId($properties['fileId']);
×
53
                }
54
                if (!$file) {
2✔
55
                        throw new \InvalidArgumentException('File not found for visible element');
×
56
                }
57
                $coordinates = $this->translateCoordinatesToInternalNotation($properties, $file);
2✔
58
                $fileElement->setSignRequestId($properties['signRequestId']);
2✔
59
                $fileElement->setType($properties['type']);
2✔
60
                $fileElement->setPage($coordinates['page']);
2✔
61
                $fileElement->setUrx($coordinates['urx']);
2✔
62
                $fileElement->setUry($coordinates['ury']);
2✔
63
                $fileElement->setLlx($coordinates['llx']);
2✔
64
                $fileElement->setLly($coordinates['lly']);
2✔
65
                $fileElement->setMetadata($properties['metadata'] ?? null);
2✔
66
                return $fileElement;
2✔
67
        }
68

69
        private function translateCoordinatesToInternalNotation(array $properties, File $file): array {
70
                $translated['page'] = $properties['coordinates']['page'] ?? 1;
2✔
71
                $metadata = $file->getMetadata();
2✔
72
                $dimension = $metadata['d'][$translated['page'] - 1];
2✔
73

74
                if (isset($properties['coordinates']['ury'])) {
2✔
75
                        $translated['ury'] = $properties['coordinates']['ury'];
×
76
                } elseif (isset($properties['coordinates']['top'])) {
2✔
77
                        $translated['ury'] = $dimension['h'] - $properties['coordinates']['top'];
2✔
78
                } else {
79
                        $translated['ury'] = 0;
×
80
                }
81

82
                if (isset($properties['coordinates']['lly'])) {
2✔
83
                        $translated['lly'] = $properties['coordinates']['lly'];
×
84
                } elseif (isset($properties['coordinates']['height'])) {
2✔
85
                        if ($properties['coordinates']['height'] > $translated['ury']) {
2✔
86
                                $translated['ury'] = $properties['coordinates']['height'];
×
87
                                $translated['lly'] = 0;
×
88
                        } else {
89
                                $translated['lly'] = $translated['ury'] - $properties['coordinates']['height'];
2✔
90
                        }
91
                } else {
92
                        $translated['lly'] = 0;
×
93
                }
94

95
                if (isset($properties['coordinates']['llx'])) {
2✔
96
                        $translated['llx'] = $properties['coordinates']['llx'];
×
97
                } elseif (isset($properties['coordinates']['left'])) {
2✔
98
                        $translated['llx'] = $properties['coordinates']['left'];
2✔
99
                } else {
100
                        $translated['llx'] = 0;
×
101
                }
102

103
                if (isset($properties['coordinates']['urx'])) {
2✔
104
                        $translated['urx'] = $properties['coordinates']['urx'];
×
105
                } elseif (isset($properties['coordinates']['width'])) {
2✔
106
                        $translated['urx'] = $translated['llx'] + $properties['coordinates']['width'];
2✔
107
                } else {
108
                        $translated['urx'] = 0;
×
109
                }
110
                if ($translated['ury'] < $translated['lly']) {
2✔
111
                        $temp = $translated['ury'];
×
112
                        $translated['ury'] = $translated['lly'];
×
113
                        $translated['lly'] = $temp;
×
114
                }
115
                if ($translated['urx'] < $translated['llx']) {
2✔
116
                        $temp = $translated['urx'];
×
117
                        $translated['urx'] = $translated['llx'];
×
118
                        $translated['llx'] = $temp;
×
119
                }
120

121
                return $translated;
2✔
122
        }
123

124
        public function deleteVisibleElement(int $elementId): void {
125
                $fileElement = new FileElement();
1✔
126
                $fileElement = $fileElement->fromRow(['id' => $elementId]);
1✔
127
                $this->fileElementMapper->delete($fileElement);
1✔
128
        }
129

130
        public function deleteVisibleElements(int $fileId): void {
131
                $visibleElements = $this->fileElementMapper->getByFileId($fileId);
1✔
132
                foreach ($visibleElements as $visibleElement) {
1✔
133
                        $this->fileElementMapper->delete($visibleElement);
×
134
                }
135
        }
136

137
        /**
138
         * @param int[] $fileIds
139
         * @return FileElement[]
140
         */
141
        public function getByFileIds(array $fileIds): array {
NEW
142
                return $this->fileElementMapper->getByFileIds($fileIds);
×
143
        }
144

145
        /**
146
         * Return visible elements formatted for API responses for given file and signRequestId
147
         *
148
         * @psalm-return list<LibresignVisibleElement>
149
         */
150
        public function getVisibleElementsForSignRequest(File $file, int $signRequestId): array {
151
                $rows = $this->fileElementMapper->getByFileIdAndSignRequestId($file->getId(), $signRequestId);
×
152
                return $this->formatVisibleElements($rows, $file->getMetadata());
×
153
        }
154

155
        /**
156
         * Format visible elements returned from DB rows for API responses.
157
         *
158
         * @param array<int, FileElement> $visibleElements Array of file elements as returned by mappers
159
         * @param array $fileMetadata Metadata of the file (expects page dimensions under key 'd')
160
         * @psalm-return list<LibresignVisibleElement>
161
         */
162
        public function formatVisibleElements(array $visibleElements, array $fileMetadata = []): array {
163
                $result = [];
3✔
164
                foreach ($visibleElements as $fileElement) {
3✔
165
                        $elementMetadata = $fileElement->getMetadata();
3✔
166
                        $metadata = $fileMetadata ?: (is_array($elementMetadata) ? $elementMetadata : []);
3✔
167
                        $dimension = $metadata['d'][$fileElement->getPage() - 1] ?? ['h' => 0];
3✔
168
                        $height = (int)abs($fileElement->getUry() - $fileElement->getLly());
3✔
169
                        $width = (int)abs($fileElement->getUrx() - $fileElement->getLlx());
3✔
170
                        $top = (int)abs($dimension['h'] - $fileElement->getUry());
3✔
171
                        $left = (int)$fileElement->getLlx();
3✔
172
                        $result[] = [
3✔
173
                                'elementId' => $fileElement->getId(),
3✔
174
                                'signRequestId' => $fileElement->getSignRequestId(),
3✔
175
                                'fileId' => $fileElement->getFileId(),
3✔
176
                                'type' => $fileElement->getType(),
3✔
177
                                'coordinates' => [
3✔
178
                                        'page' => $fileElement->getPage(),
3✔
179
                                        'urx' => $fileElement->getUrx(),
3✔
180
                                        'ury' => $fileElement->getUry(),
3✔
181
                                        'llx' => (int)$fileElement->getLlx(),
3✔
182
                                        'lly' => (int)$fileElement->getLly(),
3✔
183
                                        'left' => $left,
3✔
184
                                        'top' => $top,
3✔
185
                                        'width' => $width,
3✔
186
                                        'height' => $height,
3✔
187
                                ],
3✔
188
                        ];
3✔
189
                }
190
                return $result;
3✔
191
        }
192
}
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