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

LibreSign / libresign / 25521310733

07 May 2026 08:49PM UTC coverage: 56.843%. First build
25521310733

Pull #7668

github

web-flow
Merge 97a720789 into eb2d0b4fe
Pull Request #7668: fix: align OpenAPI contract and frontend to string-only signatureFlow

16 of 29 new or added lines in 9 files covered. (55.17%)

10741 of 18896 relevant lines covered (56.84%)

6.97 hits per line

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

32.89
/lib/Controller/IdDocsController.php
1
<?php
2

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

9
namespace OCA\Libresign\Controller;
10

11
use Exception;
12
use OCA\Libresign\AppInfo\Application;
13
use OCA\Libresign\Helper\ValidateHelper;
14
use OCA\Libresign\Middleware\Attribute\RequireSignRequestUuid;
15
use OCA\Libresign\Service\IdDocsService;
16
use OCA\Libresign\Service\SignFileService;
17
use OCP\AppFramework\Http;
18
use OCP\AppFramework\Http\Attribute\AnonRateLimit;
19
use OCP\AppFramework\Http\Attribute\ApiRoute;
20
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
21
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
22
use OCP\AppFramework\Http\Attribute\PublicPage;
23
use OCP\AppFramework\Http\DataResponse;
24
use OCP\IL10N;
25
use OCP\IRequest;
26
use OCP\IUserSession;
27
use Psr\Log\LoggerInterface;
28

29
/**
30
 * @psalm-import-type LibresignFile from \OCA\Libresign\ResponseDefinitions
31
 * @psalm-import-type LibresignIdDocs from \OCA\Libresign\ResponseDefinitions
32
 * @psalm-import-type LibresignIdDocsApprovalListResponse from \OCA\Libresign\ResponseDefinitions
33
 * @psalm-import-type LibresignIdDocsListResponse from \OCA\Libresign\ResponseDefinitions
34
 * @psalm-import-type LibresignIdDocsUploadErrorResponse from \OCA\Libresign\ResponseDefinitions
35
 * @psalm-import-type LibresignMessageResponse from \OCA\Libresign\ResponseDefinitions
36
 * @psalm-import-type LibresignMessagesResponse from \OCA\Libresign\ResponseDefinitions
37
 */
38
class IdDocsController extends AEnvironmentAwareController implements ISignatureUuid {
39
        use LibresignTrait;
40
        public function __construct(
41
                IRequest $request,
42
                protected SignFileService $signFileService,
43
                protected IL10N $l10n,
44
                protected IdDocsService $idDocsService,
45
                protected IUserSession $userSession,
46
                protected ValidateHelper $validateHelper,
47
                protected LoggerInterface $logger,
48
        ) {
49
                parent::__construct(Application::APP_ID, $request);
3✔
50
        }
51

52
        /**
53
         * Add identification documents to user profile
54
         *
55
         * @param LibresignIdDocs[] $files The list of files to add to profile
56
         * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>|DataResponse<Http::STATUS_UNAUTHORIZED, LibresignIdDocsUploadErrorResponse, array{}>
57
         *
58
         * 200: Certificate saved with success
59
         * 401: No file provided or other problem with provided file
60
         */
61
        #[PublicPage]
62
        #[AnonRateLimit(limit: 30, period: 60)]
63
        #[NoAdminRequired]
64
        #[NoCSRFRequired]
65
        #[RequireSignRequestUuid(skipIfAuthenticated: true)]
66
        #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/id-docs', requirements: ['apiVersion' => '(v1)'])]
67
        public function addFiles(array $files): DataResponse {
68
                try {
69
                        if ($user = $this->userSession->getUser()) {
2✔
70
                                $this->idDocsService->addIdDocs($files, $user);
2✔
71
                        } elseif ($signRequest = $this->getSignRequestEntity()) {
×
72
                                $this->idDocsService->addFilesToDocumentFolder($files, $signRequest);
×
73
                        } else {
74
                                throw new Exception('Invalid data');
×
75
                        }
76
                        return new DataResponse();
1✔
77
                } catch (\Exception $exception) {
1✔
78
                        $exceptionData = json_decode($exception->getMessage());
1✔
79
                        if (isset($exceptionData->file)) {
1✔
80
                                $message = [
1✔
81
                                        'file' => $exceptionData->file,
1✔
82
                                        'type' => $exceptionData->type,
1✔
83
                                        'message' => $exceptionData->message
1✔
84
                                ];
1✔
85
                        } else {
86
                                $message = [
×
87
                                        'file' => null,
×
88
                                        'type' => null,
×
89
                                        'message' => $exception->getMessage()
×
90
                                ];
×
91
                        }
92
                        return new DataResponse(
1✔
93
                                $message,
1✔
94
                                Http::STATUS_UNAUTHORIZED
1✔
95
                        );
1✔
96
                }
97
        }
98

99
        /**
100
         * Delete file from account
101
         *
102
         * @param int $nodeId the nodeId of file to be delete
103
         * @param string|null $uuid Sign request UUID for unauthenticated access
104
         *
105
         * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>|DataResponse<Http::STATUS_UNAUTHORIZED, LibresignMessagesResponse, array{}>
106
         *
107
         * 200: File deleted with success
108
         * 401: Failure to delete file from account
109
         */
110
        #[PublicPage]
111
        #[AnonRateLimit(limit: 30, period: 60)]
112
        #[NoAdminRequired]
113
        #[NoCSRFRequired]
114
        #[RequireSignRequestUuid(skipIfAuthenticated: true)]
115
        #[ApiRoute(verb: 'DELETE', url: '/api/{apiVersion}/id-docs/{nodeId}', requirements: ['apiVersion' => '(v1)'])]
116
        public function delete(int $nodeId, ?string $uuid = null): DataResponse {
117
                try {
118
                        if ($user = $this->userSession->getUser()) {
×
119
                                $this->idDocsService->deleteIdDoc($nodeId, $user);
×
120
                        } elseif ($signRequest = $this->getSignRequestEntity()) {
×
121
                                $this->idDocsService->deleteIdDocBySignRequest($nodeId, $signRequest);
×
122
                        } else {
123
                                throw new Exception('Invalid data');
×
124
                        }
125
                        return new DataResponse();
×
126
                } catch (\Exception $exception) {
×
127
                        return new DataResponse(
×
128
                                [
×
129
                                        'messages' => [
×
130
                                                $exception->getMessage(),
×
131
                                        ],
×
132
                                ],
×
133
                                Http::STATUS_UNAUTHORIZED,
×
134
                        );
×
135
                }
136
        }
137

138
        /**
139
         * List files of unauthenticated account
140
         *
141
         * @param string|null $userId User ID to filter by
142
         * @param int|null $signRequestId Sign request ID to filter by
143
         * @param int|null $page the number of page to return
144
         * @param int|null $length Total of elements to return
145
         * @return DataResponse<Http::STATUS_OK, LibresignIdDocsListResponse, array{}>|DataResponse<Http::STATUS_NOT_FOUND, LibresignMessageResponse, array{}>
146
         *
147
         * 200: Certificate saved with success
148
         * 404: No file provided or other problem with provided file
149
         */
150
        #[PublicPage]
151
        #[AnonRateLimit(limit: 30, period: 60)]
152
        #[NoCSRFRequired]
153
        #[RequireSignRequestUuid(skipIfAuthenticated: true)]
154
        #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/id-docs', requirements: ['apiVersion' => '(v1)'])]
155
        public function listUnauthenticatedSignerDocuments(
156
                ?string $userId = null,
157
                ?int $signRequestId = null,
158
                ?int $page = null,
159
                ?int $length = null,
160
        ): DataResponse {
161
                try {
162
                        if ($user = $this->userSession->getUser()) {
×
163
                                $userId = $user->getUID();
×
164
                        } elseif ($signRequest = $this->getSignRequestEntity()) {
×
165
                                $signRequestId = $signRequest->getId();
×
166
                        } elseif (!$userId && !$signRequestId) {
×
167
                                throw new Exception('Invalid data');
×
168
                        }
169

170
                        $filter = array_filter([
×
171
                                'userId' => $userId,
×
172
                                'signRequestId' => $signRequestId,
×
173
                        ], static fn ($var) => $var !== null);
×
174

175
                        $return = $this->idDocsService->list($filter, $page, $length);
×
176
                        return new DataResponse($return, Http::STATUS_OK);
×
177
                } catch (\Throwable $th) {
×
178
                        return new DataResponse(
×
179
                                [
×
180
                                        'message' => $th->getMessage()
×
181
                                ],
×
182
                                Http::STATUS_NOT_FOUND
×
183
                        );
×
184
                }
185
        }
186

187
        public function listOfUnauthenticatedSigner(
188
                ?string $userId = null,
189
                ?int $signRequestId = null,
190
                ?int $page = null,
191
                ?int $length = null,
192
        ): DataResponse {
NEW
193
                return $this->listUnauthenticatedSignerDocuments($userId, $signRequestId, $page, $length);
×
194
        }
195

196
        /**
197
         * List files that need to be approved
198
         *
199
         * @param string|null $userId User ID to filter by
200
         * @param int|null $signRequestId Sign request ID to filter by
201
         * @param int|null $page the number of page to return
202
         * @param int|null $length Total of elements to return
203
         * @param string|null $sortBy Sort field (e.g., 'owner', 'file_type', 'status')
204
         * @param string|null $sortOrder Sort order (ASC or DESC)
205
         * @return DataResponse<Http::STATUS_OK, LibresignIdDocsApprovalListResponse, array{}>|DataResponse<Http::STATUS_NOT_FOUND, LibresignMessageResponse, array{}>
206
         *
207
         * 200: OK
208
         * 404: Account not found
209
         */
210
        #[NoAdminRequired]
211
        #[NoCSRFRequired]
212
        #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/id-docs/approval/list', requirements: ['apiVersion' => '(v1)'])]
213
        public function listToApproval(
214
                ?string $userId = null,
215
                ?int $signRequestId = null,
216
                ?int $page = null,
217
                ?int $length = null,
218
                ?string $sortBy = null,
219
                ?string $sortOrder = null,
220
        ): DataResponse {
221
                try {
222
                        $this->validateHelper->userCanApproveValidationDocuments($this->userSession->getUser());
1✔
223
                        $filter = array_filter([
1✔
224
                                'userId' => $userId,
1✔
225
                                'signRequestId' => $signRequestId,
1✔
226
                        ], static fn ($var) => $var !== null);
1✔
227
                        $sort = [];
1✔
228
                        if ($sortBy !== null) {
1✔
229
                                $sort[$sortBy] = $sortOrder ?? 'DESC';
×
230
                        }
231
                        $return = $this->idDocsService->list($filter, $page, $length, $sort);
1✔
232
                        return new DataResponse($return, Http::STATUS_OK);
1✔
233
                } catch (\Throwable $th) {
×
234
                        return new DataResponse(
×
235
                                [
×
236
                                        'message' => $th->getMessage()
×
237
                                ],
×
238
                                Http::STATUS_NOT_FOUND
×
239
                        );
×
240
                }
241
        }
242
}
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