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

LibreSign / libresign / 20281257316

16 Dec 2025 08:09PM UTC coverage: 43.776%. First build
20281257316

Pull #6216

github

web-flow
Merge bb224fef9 into ceddbb77b
Pull Request #6216: feat: custom message for signers

5 of 55 new or added lines in 6 files covered. (9.09%)

5926 of 13537 relevant lines covered (43.78%)

5.16 hits per line

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

0.0
/lib/Controller/IdentifyAccountController.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\Controller;
10

11
use OCA\Libresign\AppInfo\Application;
12
use OCA\Libresign\Collaboration\Collaborators\SignerPlugin;
13
use OCA\Libresign\Middleware\Attribute\RequireManager;
14
use OCA\Libresign\ResponseDefinitions;
15
use OCA\Libresign\Service\IdentifyMethod\Account;
16
use OCA\Libresign\Service\IdentifyMethod\Email;
17
use OCP\AppFramework\Http;
18
use OCP\AppFramework\Http\Attribute\ApiRoute;
19
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
20
use OCP\AppFramework\Http\DataResponse;
21
use OCP\Collaboration\Collaborators\ISearch;
22
use OCP\IConfig;
23
use OCP\IRequest;
24
use OCP\IURLGenerator;
25
use OCP\IUserManager;
26
use OCP\IUserSession;
27
use OCP\Share\IShare;
28

29
/**
30
 * @psalm-import-type LibresignIdentifyAccount from ResponseDefinitions
31
 */
32
class IdentifyAccountController extends AEnvironmentAwareController {
33
        private array $shareTypes = [];
34
        public function __construct(
35
                IRequest $request,
36
                private ISearch $collaboratorSearch,
37
                private IUserSession $userSession,
38
                private IURLGenerator $urlGenerator,
39
                private Email $identifyEmailMethod,
40
                private Account $identifyAccountMethod,
41
                private IUserManager $userManager,
42
                private IConfig $config,
43
        ) {
44
                parent::__construct(Application::APP_ID, $request);
×
45
        }
46

47
        /**
48
         * List possible signers
49
         *
50
         * Used to identify who can sign the document. The return of this endpoint is related with Administration Settiongs > LibreSign > Identify method.
51
         *
52
         * @param string $search search params
53
         * @param string $method filter by method (email, account, sms, signal, telegram, whatsapp, xmpp)
54
         * @param int $page the number of page to return. Default: 1
55
         * @param int $limit Total of elements to return. Default: 25
56
         * @return DataResponse<Http::STATUS_OK, LibresignIdentifyAccount[], array{}>
57
         *
58
         * 200: Certificate saved with success
59
         * 400: No file provided or other problem with provided file
60
         */
61
        #[NoAdminRequired]
62
        #[RequireManager]
63
        #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/identify-account/search', requirements: ['apiVersion' => '(v1)'])]
64
        public function search(string $search = '', string $method = '', int $page = 1, int $limit = 25): DataResponse {
65
                // only search for string larger than a minimum length
66
                if (strlen($search) < 1) {
×
67
                        return new DataResponse();
×
68
                }
69

70
                $shareTypes = $this->getShareTypes();
×
71
                $lookup = false;
×
72

73
                $offset = $limit * ($page - 1);
×
74
                $this->registerPlugin($method);
×
75
                [$result] = $this->collaboratorSearch->search($search, $shareTypes, $lookup, $limit, $offset);
×
76
                $result['exact'] = $this->unifyResult($result['exact']);
×
77
                $result = $this->unifyResult($result);
×
78
                $result = $this->excludeEmptyShareWith($result);
×
79
                $return = $this->formatForNcSelect($result);
×
80
                $return = $this->addHerselfAccount($return, $search);
×
81
                $return = $this->addHerselfEmail($return, $search);
×
82
                $return = $this->replaceShareTypeByMethod($return);
×
NEW
83
                $return = $this->addEmailNotificationPreference($return);
×
84
                $return = $this->excludeNotAllowed($return);
×
85

86
                return new DataResponse($return);
×
87
        }
88

89
        private function registerPlugin(string $method): void {
90
                SignerPlugin::setMethod($method);
×
91

92
                $refObject = new \ReflectionObject($this->collaboratorSearch);
×
93
                $refProperty = $refObject->getProperty('pluginList');
×
94

95
                $plugins = $refProperty->getValue($this->collaboratorSearch);
×
96
                $plugins[SignerPlugin::TYPE_SIGNER] = [SignerPlugin::class];
×
97

98
                $refProperty->setValue($this->collaboratorSearch, $plugins);
×
99
        }
100

101
        private function getShareTypes(): array {
102
                if (count($this->shareTypes) > 0) {
×
103
                        return $this->shareTypes;
×
104
                }
105
                $settings = $this->identifyEmailMethod->getSettings();
×
106
                if ($settings['enabled']) {
×
107
                        $this->shareTypes[] = IShare::TYPE_EMAIL;
×
108
                }
109
                $settings = $this->identifyAccountMethod->getSettings();
×
110
                if ($settings['enabled']) {
×
111
                        $this->shareTypes[] = IShare::TYPE_USER;
×
112
                }
113

114
                $this->shareTypes[] = SignerPlugin::TYPE_SIGNER;
×
115
                return $this->shareTypes;
×
116
        }
117

118
        private function unifyResult(array $list): array {
119
                $ids = [];
×
120
                $return = [];
×
121
                foreach ($list as $items) {
×
122
                        foreach ($items as $item) {
×
123
                                if (in_array($item['value']['shareWith'], $ids)) {
×
124
                                        continue;
×
125
                                }
126
                                $ids[] = $item['value']['shareWith'];
×
127
                                $return[] = $item;
×
128
                        }
129
                }
130
                return $return;
×
131
        }
132

133
        private function formatForNcSelect(array $list): array {
134
                $formattedList = [];
×
135
                foreach ($list as $key => $item) {
×
136
                        $formattedList[$key] = [
×
137
                                'id' => $item['value']['shareWith'],
×
138
                                'isNoUser' => $item['value']['shareType'] !== IShare::TYPE_USER
×
139
                                        && isset($item['method'])
×
140
                                        && $item['method'] !== 'account',
×
141
                                'displayName' => $item['label'],
×
142
                                'subname' => $item['shareWithDisplayNameUnique'] ?? '',
×
143
                        ];
×
144
                        if ($item['value']['shareType'] === IShare::TYPE_EMAIL) {
×
145
                                $formattedList[$key]['method'] = 'email';
×
146
                                $formattedList[$key]['icon'] = 'icon-mail';
×
147
                        } elseif ($item['value']['shareType'] === IShare::TYPE_USER) {
×
148
                                $formattedList[$key]['method'] = 'account';
×
149
                                $formattedList[$key]['icon'] = 'icon-user';
×
150
                        } elseif ($item['value']['shareType'] === SignerPlugin::TYPE_SIGNER) {
×
151
                                $formattedList[$key]['method'] = $item['method'] ?? '';
×
152
                                if ($item['method'] === 'email') {
×
153
                                        $formattedList[$key]['icon'] = 'icon-mail';
×
154
                                } elseif ($item['method'] === 'account') {
×
155
                                        $formattedList[$key]['icon'] = 'icon-user';
×
156
                                } else {
157
                                        $formattedList[$key]['iconSvg'] = 'svg' . ucfirst($item['method']);
×
158
                                        $formattedList[$key]['iconName'] = $item['method'];
×
159
                                }
160
                        }
161
                }
162
                return $formattedList;
×
163
        }
164

165
        private function addHerselfAccount(array $return, string $search): array {
166
                $settings = $this->identifyAccountMethod->getSettings();
×
167
                if (empty($settings['enabled'])) {
×
168
                        return $return;
×
169
                }
170
                $user = $this->userSession->getUser();
×
171
                $search = strtolower($search);
×
172
                if (!str_contains($user->getUID(), $search)
×
173
                        && !str_contains(strtolower($user->getDisplayName()), $search)
×
174
                        && (
175
                                $user->getEMailAddress() === null
×
176
                                || ($user->getEMailAddress() !== null && !str_contains($user->getEMailAddress(), $search))
×
177
                        )
178
                ) {
179
                        return $return;
×
180
                }
181
                $filtered = array_filter($return, fn ($i) => $i['id'] === $user->getUID());
×
182
                if (count($filtered)) {
×
183
                        return $return;
×
184
                }
185
                $return[] = [
×
186
                        'id' => $user->getUID(),
×
187
                        'isNoUser' => false,
×
188
                        'displayName' => $user->getDisplayName(),
×
189
                        'subname' => $user->getEMailAddress(),
×
190
                        'icon' => 'icon-user',
×
191
                        'method' => 'account',
×
192
                ];
×
193
                return $return;
×
194
        }
195

196
        private function addHerselfEmail(array $return, string $search): array {
197
                $settings = $this->identifyEmailMethod->getSettings();
×
198
                if (empty($settings['enabled'])) {
×
199
                        return $return;
×
200
                }
201
                $user = $this->userSession->getUser();
×
202
                if (empty($user->getEMailAddress())) {
×
203
                        return $return;
×
204
                }
205
                if (!str_contains($user->getEMailAddress(), $search)
×
206
                        && !str_contains($user->getDisplayName(), $search)
×
207
                ) {
208
                        return $return;
×
209
                }
210
                $filtered = array_filter($return, fn ($i) => $i['id'] === $user->getUID());
×
211
                if (count($filtered)) {
×
212
                        return $return;
×
213
                }
214
                $return[] = [
×
215
                        'id' => $user->getEMailAddress(),
×
216
                        'isNoUser' => true,
×
217
                        'displayName' => $user->getDisplayName(),
×
218
                        'subname' => $user->getEMailAddress(),
×
219
                        'icon' => 'icon-mail',
×
220
                        'method' => 'email',
×
221
                ];
×
222
                return $return;
×
223
        }
224

225
        private function excludeEmptyShareWith(array $list): array {
226
                return array_filter($list, fn ($result) => strlen((string)$result['value']['shareWith']) > 0);
×
227
        }
228

229
        private function excludeNotAllowed(array $list): array {
230
                return array_filter($list, fn ($result) => isset($result['method']) && !empty($result['method']));
×
231
        }
232

233
        private function replaceShareTypeByMethod(array $list): array {
234
                foreach ($list as $key => $item) {
×
235
                        if (isset($item['method']) && !empty($item['method'])) {
×
236
                                continue;
×
237
                        }
238
                        $list[$key]['method'] = match ($item['shareType']) {
×
239
                                IShare::TYPE_EMAIL => 'email',
×
240
                                IShare::TYPE_USER => 'account',
×
241
                                default => '',
×
242
                        };
×
243
                        unset($list[$key]['shareType']);
×
244
                }
245
                return $list;
×
246
        }
247

248
        private function addEmailNotificationPreference(array $list): array {
NEW
249
                foreach ($list as $key => $item) {
×
NEW
250
                        if ($item['method'] !== 'account') {
×
NEW
251
                                continue;
×
252
                        }
253

NEW
254
                        $user = $this->userManager->get($item['id']);
×
NEW
255
                        if ($user === null) {
×
NEW
256
                                $list[$key]['acceptsEmailNotifications'] = false;
×
NEW
257
                                continue;
×
258
                        }
259

NEW
260
                        $email = $user->getEMailAddress();
×
NEW
261
                        if (empty($email)) {
×
NEW
262
                                $list[$key]['acceptsEmailNotifications'] = false;
×
NEW
263
                                continue;
×
264
                        }
265

NEW
266
                        if ($this->isNotificationDisabledAtActivity($user->getUID(), 'libresign_file_to_sign')) {
×
NEW
267
                                $list[$key]['acceptsEmailNotifications'] = false;
×
NEW
268
                                continue;
×
269
                        }
270

NEW
271
                        $list[$key]['acceptsEmailNotifications'] = true;
×
272
                }
NEW
273
                return $list;
×
274
        }
275

276
        private function isNotificationDisabledAtActivity(string $userId, string $type): bool {
NEW
277
                if (!class_exists(\OCA\Activity\UserSettings::class)) {
×
NEW
278
                        return false;
×
279
                }
NEW
280
                $activityUserSettings = \OCP\Server::get(\OCA\Activity\UserSettings::class);
×
NEW
281
                if ($activityUserSettings) {
×
NEW
282
                        $adminSetting = $activityUserSettings->getAdminSetting('email', $type);
×
NEW
283
                        if (!$adminSetting) {
×
NEW
284
                                return true;
×
285
                        }
286

NEW
287
                        $notificationSetting = $activityUserSettings->getUserSetting(
×
NEW
288
                                $userId,
×
NEW
289
                                'email',
×
NEW
290
                                $type
×
NEW
291
                        );
×
NEW
292
                        if (!$notificationSetting) {
×
NEW
293
                                return true;
×
294
                        }
295
                }
NEW
296
                return false;
×
297
        }
298
}
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