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

IGNF / validator-api / 24443938672

15 Apr 2026 08:17AM UTC coverage: 51.256% (-2.4%) from 53.632%
24443938672

push

github

web-flow
pdf generator (#85)

* pdf generator

* feat: pdf rapport

* feat: client for pdf rapport

0 of 30 new or added lines in 2 files covered. (0.0%)

347 of 677 relevant lines covered (51.26%)

2.61 hits per line

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

63.45
/src/Controller/Api/ValidationsController.php
1
<?php
2

3
namespace App\Controller\Api;
4

5
use App\Entity\Validation;
6
use App\Exception\ApiException;
7
use App\Export\CsvReportWriter;
8
use App\Export\PdfReportWriter;
9
use App\Repository\ValidationRepository;
10
use App\Service\MimeTypeGuesserService;
11
use App\Service\ValidatorArgumentsService;
12
use App\Storage\ValidationsStorage;
13
use JMS\Serializer\SerializerInterface;
14
use Psr\Log\LoggerInterface;
15
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
16
use Symfony\Component\Filesystem\Filesystem;
17
use Symfony\Component\HttpFoundation\JsonResponse;
18
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\HttpFoundation\Response;
20
use Symfony\Component\HttpFoundation\StreamedResponse;
21
use Symfony\Component\Routing\Annotation\Route;
22

23
/**
24
 * @Route("/api/validations")
25
 */
26
class ValidationsController extends AbstractController
27
{
28
    public function __construct(
29
        private ValidationRepository $repository,
30
        private SerializerInterface $serializer,
31
        private ValidationsStorage $storage,
32
        private ValidatorArgumentsService $valArgsService,
33
        private MimeTypeGuesserService $mimeTypeGuesserService,
34
        private LoggerInterface $logger,
35
    ) {}
22✔
36

37
    /**
38
     * @Route(
39
     *      "/",
40
     *      name="validator_api_disabled_routes",
41
     *      methods={"GET","DELETE","PATCH","PUT"}
42
     * )
43
     */
44
    public function disabledRoutes()
45
    {
46
        return new JsonResponse(['error' => 'This route is not allowed'], Response::HTTP_METHOD_NOT_ALLOWED);
1✔
47
    }
48

49
    /**
50
     * @Route(
51
     *      "/{uid}",
52
     *      name="validator_api_get_validation",
53
     *      methods={"GET"}
54
     * )
55
     */
56
    public function getValidation($uid)
57
    {
58
        $validation = $this->repository->findOneByUid($uid);
2✔
59
        if (!$validation) {
2✔
60
            throw new ApiException("No record found for uid=$uid", Response::HTTP_NOT_FOUND);
1✔
61
        }
62

63
        return new JsonResponse($this->serializer->toArray($validation), Response::HTTP_OK);
1✔
64
    }
65

66
    /**
67
     * @Route(
68
     *      "/{uid}/logs",
69
     *      name="validator_api_read_logs",
70
     *      methods={"GET"}
71
     * )
72
     */
73
    public function readConsole($uid)
74
    {
75
        $validation = $this->repository->findOneByUid($uid);
×
76
        if (!$validation) {
×
77
            throw new ApiException("No record found for uid=$uid", Response::HTTP_NOT_FOUND);
×
78
        }
79

80
        if (Validation::STATUS_ARCHIVED == $validation->getStatus()) {
×
81
            throw new ApiException('Validation has been archived', Response::HTTP_FORBIDDEN);
×
82
        }
83

84
        $outputDirectory = $this->storage->getOutputDirectory($validation);
×
85
        $filepath = $outputDirectory . '/validator-debug.log';
×
86

87
        $content = $this->storage->getStorage()->read($filepath);
×
88

89
        return new Response(
×
90
            $content,
×
91
            Response::HTTP_CREATED
×
92
        );
×
93
    }
94

95
    /**
96
     * @Route(
97
     *      "/{uid}/results.csv",
98
     *      name="validator_api_get_validation_csv",
99
     *      methods={"GET"}
100
     * )
101
     */
102
    public function getValidationCsv($uid, CsvReportWriter $csvWriter)
103
    {
104
        $validation = $this->repository->findOneByUid($uid);
×
105
        if (!$validation) {
×
106
            throw new ApiException("No record found for uid=$uid", Response::HTTP_NOT_FOUND);
×
107
        }
108

109
        $response = new StreamedResponse(function () use ($validation, $csvWriter) {
×
110
            $csvWriter->write($validation);
×
111
        });
×
112
        $response->headers->set('Content-Type', 'application/force-download');
×
113
        $filename = $uid . '-results.csv';
×
114
        $response->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"');
×
115

116
        return $response;
×
117
    }
118

119
    /**
120
     * @Route(
121
     *      "/",
122
     *      name="validator_api_upload_dataset",
123
     *      methods={"POST"}
124
     * )
125
     */
126
    public function uploadDataset(Request $request)
127
    {
128
        $files = $request->files;
4✔
129
        /*
130
         * Ensure that input file is submitted
131
         */
132
        $file = $files->get('dataset');
4✔
133
        if (!$file) {
4✔
134
            throw new ApiException('Argument [dataset] is missing', Response::HTTP_BAD_REQUEST);
2✔
135
        }
136

137
        $this->logger->info('handle new upload...', [
2✔
138
            'path_name' => $file->getPathName(),
2✔
139
            'client_original_name' => $file->getClientOriginalName(),
2✔
140
        ]);
2✔
141

142
        /*
143
         * Ensure that input file is a ZIP file.
144
         */
145
        $mimeType = $this->mimeTypeGuesserService->guessMimeType($file->getPathName());
2✔
146
        if ('application/zip' !== $mimeType) {
2✔
147
            throw new ApiException('Dataset must be in a compressed [.zip] file', Response::HTTP_BAD_REQUEST);
1✔
148
        }
149

150
        /*
151
         * create validation and same validation
152
         */
153
        $validation = new Validation();
1✔
154
        // TODO : check getClientOriginalName
155
        $datasetName = str_replace('.zip', '', $file->getClientOriginalName());
1✔
156
        $validation->setDatasetName($datasetName);
1✔
157

158
        // Save file to storage
159
        $uploadDirectory = $this->storage->getUploadDirectory($validation);
1✔
160
        if (!$this->storage->getStorage()->directoryExists($uploadDirectory)) {
1✔
161
            $this->storage->getStorage()->createDirectory($uploadDirectory);
1✔
162
        }
163
        $fileLocation = $uploadDirectory . $validation->getDatasetName() . '.zip';
1✔
164
        if ($this->storage->getStorage()->fileExists($fileLocation)) {
1✔
165
            $this->storage->getStorage()->delete($fileLocation);
×
166
        }
167
        $stream = fopen($file->getRealPath(), 'r+');
1✔
168
        $this->storage->getStorage()->writeStream($fileLocation, $stream);
1✔
169
        fclose($stream);
1✔
170

171
        $fs = new Filesystem();
1✔
172
        if ($fs->exists($file->getRealPath())) {
1✔
173
            $this->logger->debug('Validation[{uid}] : rm -rf {path}...', [
1✔
174
                'uid' => $validation->getUid(),
1✔
175
                'path' => $file->getRealPath(),
1✔
176
            ]);
1✔
177
            $fs->remove($file->getRealPath());
1✔
178
        }
179

180
        $em = $this->getDoctrine()->getManager();
1✔
181
        $em->persist($validation);
1✔
182
        $em->flush();
1✔
183
        $em->refresh($validation);
1✔
184

185
        return new JsonResponse(
1✔
186
            $this->serializer->toArray($validation),
1✔
187
            Response::HTTP_CREATED
1✔
188
        );
1✔
189
    }
190

191
    /**
192
     * @Route(
193
     *      "/{uid}",
194
     *      name="validator_api_update_arguments",
195
     *      methods={"PATCH"}
196
     * )
197
     */
198
    public function updateArguments(Request $request, $uid)
199
    {
200
        $data = $request->getContent();
10✔
201

202
        if (!json_decode($data, true)) {
10✔
203
            throw new ApiException('Request body must be a valid JSON string', Response::HTTP_BAD_REQUEST);
2✔
204
        }
205

206
        $validation = $this->repository->findOneByUid($uid);
8✔
207
        if (!$validation) {
8✔
208
            throw new ApiException("No record found for uid=$uid", Response::HTTP_NOT_FOUND);
1✔
209
        }
210

211
        if (Validation::STATUS_ARCHIVED == $validation->getStatus()) {
7✔
212
            throw new ApiException('Validation has been archived', Response::HTTP_FORBIDDEN);
1✔
213
        }
214
        // TODO : review (json_decode in this method and inside of validate)
215
        $arguments = $this->valArgsService->validate($data);
6✔
216

217
        // checks if we need to keep data
218
        $validation->setDeleteData($arguments['delete-data']);
1✔
219
        unset($arguments['delete-data']);
1✔
220

221
        $validation->reset();
1✔
222
        $validation->setArguments($arguments);
1✔
223
        $validation->setStatus(Validation::STATUS_PENDING);
1✔
224

225
        $em = $this->getDoctrine()->getManager();
1✔
226
        $em->flush();
1✔
227
        $em->refresh($validation);
1✔
228

229
        return new JsonResponse(
1✔
230
            $this->serializer->toArray($validation),
1✔
231
            Response::HTTP_OK
1✔
232
        );
1✔
233
    }
234

235
    /**
236
     * @Route(
237
     *      "/{uid}",
238
     *      name="validator_api_delete_validation",
239
     *      methods={"DELETE"}
240
     * )
241
     */
242
    public function deleteValidation($uid)
243
    {
244
        $validation = $this->repository->findOneByUid($uid);
1✔
245
        if (!$validation) {
1✔
246
            throw new ApiException("No record found for uid=$uid", Response::HTTP_NOT_FOUND);
1✔
247
        }
248

249
        $this->logger->info('Validation[{uid}] : removing all saved data...', [
1✔
250
            'uid' => $validation->getUid(),
1✔
251
            'datasetName' => $validation->getDatasetName(),
1✔
252
        ]);
1✔
253

254
        $em = $this->getDoctrine()->getManager();
1✔
255
        $em->remove($validation);
1✔
256
        $em->flush();
1✔
257

258
        // Delete from storage
259
        $uploadDirectory = $this->storage->getUploadDirectory($validation);
1✔
260
        if ($this->storage->getStorage()->directoryExists($uploadDirectory)) {
1✔
261
            $this->storage->getStorage()->deleteDirectory($uploadDirectory);
×
262
        }
263
        $outputDirectory = $this->storage->getOutputDirectory($validation);
1✔
264
        if ($this->storage->getStorage()->directoryExists($outputDirectory)) {
1✔
265
            $this->storage->getStorage()->deleteDirectory($outputDirectory);
×
266
        }
267

268
        return new JsonResponse(null, Response::HTTP_NO_CONTENT);
1✔
269
    }
270

271
    /**
272
     * @Route(
273
     *      "/{uid}/files/normalized",
274
     *      name="validator_api_download_normalized_data",
275
     *      methods={"GET"}
276
     * )
277
     */
278
    public function downloadNormalizedData($uid)
279
    {
280
        $validation = $this->repository->findOneByUid($uid);
2✔
281
        if (!$validation) {
2✔
282
            throw new ApiException("No record found for uid=$uid", Response::HTTP_NOT_FOUND);
1✔
283
        }
284

285
        if (Validation::STATUS_ARCHIVED == $validation->getStatus()) {
1✔
286
            throw new ApiException('Validation has been archived', Response::HTTP_FORBIDDEN);
1✔
287
        }
288

289
        if (Validation::STATUS_ERROR == $validation->getStatus()) {
1✔
290
            throw new ApiException('Validation failed, no normalized data', Response::HTTP_FORBIDDEN);
×
291
        }
292

293
        if (in_array($validation->getStatus(), [Validation::STATUS_PENDING, Validation::STATUS_PROCESSING, Validation::STATUS_WAITING_ARGS])) {
1✔
294
            throw new ApiException("Validation hasn't been executed yet", Response::HTTP_FORBIDDEN);
1✔
295
        }
296

297
        $outputDirectory = $this->storage->getOutputDirectory($validation);
×
298
        $zipFilepath = $outputDirectory . $validation->getDatasetName() . '.zip';
×
299

300
        return $this->getDownloadResponse($zipFilepath, $validation->getDatasetName() . '-normalized.zip');
×
301
    }
302

303
    /**
304
     * @Route(
305
     *      "/{uid}/files/source",
306
     *      name="validator_api_download_source_data",
307
     *      methods={"GET"}
308
     * )
309
     */
310
    public function downloadSourceData($uid)
311
    {
312
        $validation = $this->repository->findOneByUid($uid);
2✔
313
        if (!$validation) {
2✔
314
            throw new ApiException("No record found for uid=$uid", Response::HTTP_NOT_FOUND);
1✔
315
        }
316

317
        if (Validation::STATUS_ARCHIVED == $validation->getStatus()) {
1✔
318
            throw new ApiException('Validation has been archived', Response::HTTP_FORBIDDEN);
1✔
319
        }
320

321
        $uploadDirectory = $this->storage->getUploadDirectory($validation);
×
322
        $zipFilepath = $uploadDirectory . $validation->getDatasetName() . '.zip';
×
323

324
        return $this->getDownloadResponse($zipFilepath, $validation->getDatasetName() . '-source.zip');
×
325
    }
326

327
    /**
328
     * @Route(
329
     *      "/{uid}/results.pdf",
330
     *      name="validator_api_get_validation_pdf",
331
     *      methods={"GET"}
332
     * )
333
     */
334
    public function generatePdf($uid, PdfReportWriter $writer,
335
    ): Response {
NEW
336
        $validation = $this->repository->findOneByUid($uid);
×
NEW
337
        if (!$validation) {
×
NEW
338
            throw new ApiException("No record found for uid=$uid", Response::HTTP_NOT_FOUND);
×
339
        }
340

NEW
341
        $pdf = $writer->generate($validation);
×
342

NEW
343
        return new Response($pdf, Response::HTTP_OK, [
×
NEW
344
            'Content-Type'        => 'application/pdf',
×
NEW
345
            'Content-Disposition' => 'inline; filename="' . $validation->getDatasetName() . '.pdf"',
×
NEW
346
        ]);
×
347
    }
348

349
    /**
350
     * Returns binary response of the specified file.
351
     *
352
     * @param string $filename
353
     *
354
     * @return StreamedResponse
355
     */
356
    private function getDownloadResponse($filepath, $filename)
357
    {
358
        if (!$this->storage->getStorage()->has($filepath)) {
×
359
            throw new ApiException('Requested files not found for this validation', Response::HTTP_FORBIDDEN);
×
360
        }
361

362
        $stream = $this->storage->getStorage()->readStream($filepath);
×
363

364
        return new StreamedResponse(function () use ($stream) {
×
365
            fpassthru($stream);
×
366
            exit;
×
367
        }, 200, [
×
368
            'Content-Transfer-Encoding',
×
369
            'binary',
×
370
            'Content-Type' => 'application/zip',
×
371
            'Content-Disposition' => sprintf('attachment; filename="%s"', $filename),
×
372
            'Content-Length' => fstat($stream)['size'],
×
373
        ]);
×
374
    }
375
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc