Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
8.56% covered (danger)
8.56%
19 / 222
20.00% covered (danger)
20.00%
4 / 20
CRAP
0.00% covered (danger)
0.00%
0 / 1
ToolController
8.56% covered (danger)
8.56%
19 / 222
20.00% covered (danger)
20.00%
4 / 20
3499.25
0.00% covered (danger)
0.00%
0 / 1
 __construct
90.00% covered (success)
90.00%
9 / 10
0.00% covered (danger)
0.00%
0 / 1
3.01
 getDomain
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getModel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getModelClass
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFormType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getListData
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 listAction
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 showAction
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 editAction
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 deleteAction
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 createAction
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 pdfAction
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 getRequestCriteria
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
20
 reportAction
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 getLabelAndKeysArray
0.00% covered (danger)
0.00%
0 / 68
0.00% covered (danger)
0.00%
0 / 1
12
 listDataTables
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
240
 generateShowLink
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 generateActionCell
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
56
 apiGetToolsByCollectivity
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 deleteConfirmationAction
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
56
1<?php
2
3/**
4 * This file is part of the MADIS - RGPD Management application.
5 *
6 * @copyright Copyright (c) 2018-2019 Soluris - Solutions Numériques Territoriales Innovantes
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22declare(strict_types=1);
23
24namespace App\Domain\Registry\Controller;
25
26use App\Application\Controller\CRUDController;
27use App\Application\Symfony\Security\UserProvider;
28use App\Application\Traits\ServersideDatatablesTrait;
29use App\Domain\Documentation\Model\Category;
30use App\Domain\Registry\Dictionary\MesurementStatusDictionary;
31use App\Domain\Registry\Dictionary\ToolTypeDictionary;
32use App\Domain\Registry\Form\Type\ToolType;
33use App\Domain\Registry\Model;
34use App\Domain\Registry\Repository;
35use App\Domain\Reporting\Handler\WordHandler;
36use App\Domain\User\Dictionary\UserRoleDictionary;
37use App\Domain\User\Model\Collectivity;
38use App\Domain\User\Model\User;
39use App\Domain\User\Repository as UserRepository;
40use Doctrine\ORM\EntityManagerInterface;
41use Knp\Snappy\Pdf;
42use Symfony\Component\HttpFoundation\JsonResponse;
43use Symfony\Component\HttpFoundation\Request;
44use Symfony\Component\HttpFoundation\RequestStack;
45use Symfony\Component\HttpFoundation\Response;
46use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
47use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
48use Symfony\Component\Routing\RouterInterface;
49use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
50use Symfony\Contracts\Translation\TranslatorInterface;
51use Symfony\Polyfill\Intl\Icu\Exception\MethodNotImplementedException;
52
53/**
54 * @property Repository\Tool $repository
55 */
56class ToolController extends CRUDController
57{
58    use ServersideDatatablesTrait;
59
60    /**
61     * @var UserRepository\Collectivity
62     */
63    protected $collectivityRepository;
64
65    /**
66     * @var WordHandler
67     */
68    protected $wordHandler;
69
70    /**
71     * @var AuthorizationCheckerInterface
72     */
73    protected $authorizationChecker;
74
75    /**
76     * @var UserProvider
77     */
78    protected $userProvider;
79
80    protected RequestStack $requestStack;
81
82    /**
83     * @var RouterInterface
84     */
85    protected $router;
86
87    public function __construct(
88        EntityManagerInterface $entityManager,
89        TranslatorInterface $translator,
90        Repository\Tool $repository,
91        UserRepository\Collectivity $collectivityRepository,
92        WordHandler $wordHandler,
93        AuthorizationCheckerInterface $authorizationChecker,
94        UserProvider $userProvider,
95        RouterInterface $router,
96        Pdf $pdf,
97        RequestStack $requestStack,
98    ) {
99        parent::__construct($entityManager, $translator, $repository, $pdf, $userProvider, $authorizationChecker);
100        $this->collectivityRepository = $collectivityRepository;
101        $this->wordHandler            = $wordHandler;
102        $this->authorizationChecker   = $authorizationChecker;
103        $this->userProvider           = $userProvider;
104        $this->router                 = $router;
105        $this->requestStack           = $requestStack;
106        // Deny access to single collectivity users if tool module is disabled
107        // Fixes https://gitlab.adullact.net/soluris/madis/-/issues/949
108        $user = $userProvider->getAuthenticatedUser();
109        if ($user && !$user->hasModuleTools()) {
110            throw new AccessDeniedHttpException('Ce module est désactivé sur votre structure');
111        }
112    }
113
114    protected function getDomain(): string
115    {
116        return 'registry';
117    }
118
119    protected function getModel(): string
120    {
121        return 'tool';
122    }
123
124    protected function getModelClass(): string
125    {
126        return Model\Tool::class;
127    }
128
129    protected function getFormType(): string
130    {
131        return ToolType::class;
132    }
133
134    protected function getListData()
135    {
136        $request  = $this->requestStack->getCurrentRequest();
137        $criteria = $this->getRequestCriteria($request);
138
139        return $this->repository->findBy($criteria);
140    }
141
142    public function listAction(): Response
143    {
144        $request  = $this->requestStack->getCurrentRequest();
145        $category = $this->entityManager->getRepository(Category::class)->findOneBy([
146            'name' => 'Logiciels',
147        ]);
148
149        return $this->render($this->getTemplatingBasePath('list'), [
150            'totalItem' => $this->repository->count($this->getRequestCriteria($request)),
151            'category'  => $category,
152            'route'     => $this->router->generate('registry_tool_list_datatables'),
153        ]);
154    }
155
156    // Override default actions to disable access if tool module is disabled in the collectivity
157
158    public function showAction(string $id): Response
159    {
160        /** @var Model\Tool $object */
161        $object = $this->repository->findOneById($id);
162        if ($object->getCollectivity() && $object->getCollectivity()->isHasModuleTools()) {
163            return parent::showAction($id);
164        }
165
166        return $this->redirectToRoute('registry_tool_list');
167    }
168
169    public function editAction(Request $request, string $id): Response
170    {
171        /** @var Model\Tool $object */
172        $object = $this->repository->findOneById($id);
173        if ($object->getCollectivity() && $object->getCollectivity()->isHasModuleTools()) {
174            return parent::editAction($request, $id);
175        }
176
177        return $this->redirectToRoute('registry_tool_list');
178    }
179
180    public function deleteAction(string $id): Response
181    {
182        /** @var Model\Tool $object */
183        $object = $this->repository->findOneById($id);
184        if ($object->getCollectivity() && $object->getCollectivity()->isHasModuleTools()) {
185            return parent::deleteAction($id);
186        }
187
188        return $this->redirectToRoute('registry_tool_list');
189    }
190
191    public function createAction(Request $request): Response
192    {
193        $collectivity = $this->userProvider->getAuthenticatedUser()->getCollectivity();
194        if ($collectivity && $collectivity->isHasModuleTools()) {
195            return parent::createAction($request);
196        }
197
198        return $this->redirectToRoute('registry_tool_list');
199    }
200
201    public function pdfAction(string $id)
202    {
203        /** @var Model\Tool $object */
204        $object = $this->repository->findOneById($id);
205        if ($object->getCollectivity() && $object->getCollectivity()->isHasModuleTools()) {
206            return parent::pdfAction($id);
207        }
208
209        return $this->redirectToRoute('registry_tool_list');
210    }
211
212    private function getRequestCriteria(Request $request)
213    {
214        $criteria = [];
215        $user     = $this->userProvider->getAuthenticatedUser();
216
217        if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) {
218            $criteria['collectivity'] = $user->getCollectivity();
219        }
220
221        if (\in_array(UserRoleDictionary::ROLE_REFERENT, $user->getRoles())) {
222            $criteria['collectivity'] = $user->getCollectivitesReferees();
223        }
224
225        if ($request->query->getBoolean('action_plan')) {
226            // Since we have to display planified & not-applied mesurement, filter
227            $criteria['planificationDate'] = 'null';
228            $criteria['status']            = MesurementStatusDictionary::STATUS_NOT_APPLIED;
229        }
230
231        return $criteria;
232    }
233
234    /**
235     * Generate a word report of tools.
236     *
237     * @throws \PhpOffice\PhpWord\Exception\Exception
238     */
239    public function reportAction(): Response
240    {
241        if (!$this->userProvider->getAuthenticatedUser()->getCollectivity()->isHasModuleTools()) {
242            return $this->redirectToRoute('registry_tool_list');
243        }
244        $objects = $this->repository->findAllByCollectivity(
245            $this->userProvider->getAuthenticatedUser()->getCollectivity(),
246            ['name' => 'asc']
247        );
248
249        return $this->wordHandler->generateRegistryToolReport($objects, $this->userProvider->getAuthenticatedUser()->getCollectivity());
250    }
251
252    protected function getLabelAndKeysArray(): array
253    {
254        if ($this->isGranted('ROLE_REFERENT')) {
255            return [
256                'name',
257                'collectivity',
258                'service',
259                'type',
260                'editor',
261                'archival',
262                'encrypted',
263                'access_control',
264                'update',
265                'backup',
266                'deletion',
267                'tracking',
268                'has_comment',
269                'other',
270                'treatments',
271                'contractors',
272                'proofs',
273                'mesurements',
274                'createdAt',
275                'updatedAt',
276                'actions',
277            ];
278        }
279        if ($this->userProvider->getAuthenticatedUser()->hasServices()) {
280            return [
281                'name',
282                'service',
283                'type',
284                'editor',
285                'archival',
286                'encrypted',
287                'access_control',
288                'update',
289                'backup',
290                'deletion',
291                'tracking',
292                'has_comment',
293                'other',
294                'treatments',
295                'contractors',
296                'proofs',
297                'mesurements',
298                'createdAt',
299                'updatedAt',
300                'actions',
301            ];
302        }
303
304        return [
305            'name',
306            'type',
307            'editor',
308            'archival',
309            'encrypted',
310            'access_control',
311            'update',
312            'backup',
313            'deletion',
314            'tracking',
315            'has_comment',
316            'other',
317            'treatments',
318            'contractors',
319            'proofs',
320            'mesurements',
321            'createdAt',
322            'updatedAt',
323            'actions',
324        ];
325    }
326
327    public function listDataTables(Request $request): JsonResponse
328    {
329        $criteria = $this->getRequestCriteria($request);
330        $tools    = $this->getResults($request, $criteria);
331        $reponse  = $this->getBaseDataTablesResponse($request, $tools, $criteria);
332
333        $yes = '<span class="badge bg-green">' . $this->translator->trans('global.label.yes') . '</span>';
334        $no  = '<span class="badge bg-yellow">' . $this->translator->trans('global.label.no') . '</span>';
335
336        /** @var Model\Tool $tool */
337        foreach ($tools as $tool) {
338            try {
339                $col = $tool->getCollectivity() ? $tool->getCollectivity()->getName() : '';
340            } catch (\Exception $e) {
341                $col = '';
342            }
343            $reponse['data'][] = [
344                'id'             => $tool->getId(),
345                'name'           => $this->generateShowLink($tool),
346                'collectivity'   => $this->authorizationChecker->isGranted('ROLE_REFERENT') ? $col : '',
347                'service'        => $tool->getService() ? $tool->getService()->getName() : '',
348                'type'           => ToolTypeDictionary::getTypes()[$tool->getType()],
349                'editor'         => $tool->getEditor(),
350                'archival'       => $tool->getArchival()->isCheck() ? $yes : $no,
351                'encrypted'      => $tool->getEncrypted()->isCheck() ? $yes : $no,
352                'access_control' => $tool->getAccessControl()->isCheck() ? $yes : $no,
353                'update'         => $tool->getUpdate()->isCheck() ? $yes : $no,
354                'backup'         => $tool->getBackup()->isCheck() ? $yes : $no,
355                'deletion'       => $tool->getDeletion()->isCheck() ? $yes : $no,
356                'tracking'       => $tool->getTracking()->isCheck() ? $yes : $no,
357                'has_comment'    => $tool->getHasComment()->isCheck() ? $yes : $no,
358                'other'          => $tool->getOther()->isCheck() ? $yes : $no,
359                'treatments'     => Model\Tool::generateLinkedDataColumn($tool->getTreatments()),
360                'contractors'    => Model\Tool::generateLinkedDataColumn($tool->getContractors()),
361                'proofs'         => Model\Tool::generateLinkedDataColumn($tool->getProofs()),
362                'mesurements'    => Model\Tool::generateLinkedDataColumn($tool->getMesurements()),
363                'createdAt'      => $tool->getCreatedAt()->format('d-m-Y H:i'),
364                'updatedAt'      => $tool->getUpdatedAt()->format('d-m-Y H:i'),
365                'actions'        => $this->generateActionCell($tool),
366                'updatedBy'      => $tool->getUpdatedBy(),
367            ];
368        }
369
370        $jsonResponse = new JsonResponse();
371        $jsonResponse->setJson(json_encode($reponse));
372
373        return $jsonResponse;
374    }
375
376    private function generateShowLink(Model\Tool $tool)
377    {
378        return '<a href="' .
379            $this->router->generate('registry_tool_show', ['id' => $tool->getId()]) .
380            '">' . \htmlspecialchars($tool->getName()) . '</a>';
381    }
382
383    private function generateActionCell(Model\Tool $tool)
384    {
385        $user = $this->userProvider->getAuthenticatedUser();
386        if (
387            (
388                $this->authorizationChecker->isGranted('ROLE_USER')
389                && $tool->getCollectivity()->getIsServicesEnabled()
390                && ($user->getServices()->isEmpty() || $tool->isInUserServices($user))
391            )
392            || $this->authorizationChecker->isGranted('ROLE_ADMIN')
393            || !$tool->getCollectivity()->getIsServicesEnabled()
394        ) {
395            return '<a href="' .
396                $this->router->generate('registry_tool_edit', ['id' => $tool->getId()]) . '">
397            <i aria-hidden="true" class="fa fa-pencil"></i> ' .
398                $this->translator->trans('global.action.edit')
399                . '</a>
400
401            <a href="' .
402                $this->router->generate('registry_tool_delete', ['id' => $tool->getId()]) .
403                '"><i aria-hidden="true" class="fa fa-trash"></i> ' .
404                $this->translator->trans('global.action.delete')
405                . '</a>';
406        }
407    }
408
409    public function apiGetToolsByCollectivity(string $collectivityId): Response
410    {
411        if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) {
412            throw new AccessDeniedHttpException('You can\'t access to a collectivity mesurement data');
413        }
414
415        /** @var Collectivity|null $collectivity */
416        $collectivity = $this->collectivityRepository->findOneById($collectivityId);
417        if (null === $collectivity) {
418            throw new NotFoundHttpException('Can\'t find collectivity for id ' . $collectivityId);
419        }
420
421        $tools = $this->repository->findAllByCollectivity(
422            $collectivity,
423            [
424                'name' => 'ASC',
425            ]
426        );
427
428        $responseData = [];
429
430        /** @var Model\Tool $tool */
431        foreach ($tools as $tool) {
432            $responseData[] = [
433                'value' => $tool->getId()->toString(),
434                'text'  => $tool->__toString(),
435            ];
436        }
437
438        return new JsonResponse($responseData);
439    }
440
441    /**
442     * The deletion action
443     * Delete the data.
444     * OVERRIDE of the CRUDController to manage clone id.
445     *
446     * @throws \Exception
447     */
448    public function deleteConfirmationAction(string $id): Response
449    {
450        $object = $this->repository->findOneById($id);
451        if (!$object) {
452            throw new NotFoundHttpException("No object found with ID '{$id}'");
453        }
454        if ($object->getCollectivity() && !$object->getCollectivity()->isHasModuleTools()) {
455            throw new AccessDeniedHttpException('Ce module est désactivé sur la structure');
456        }
457        /** @var User $user */
458        $user = $this->getUser();
459        if (!$user->hasAccessTo($object)) {
460            return $this->redirectToRoute($this->getRouteName('list'));
461        }
462
463        if ($this->isSoftDelete()) {
464            if (!\method_exists($object, 'setDeletedAt')) {
465                throw new MethodNotImplementedException('setDeletedAt');
466            }
467            $object->setDeletedAt(new \DateTimeImmutable());
468            $this->repository->update($object);
469        } else {
470            $this->entityManager->remove($object);
471            $this->entityManager->flush();
472        }
473
474        $this->addFlash('success', $this->getFlashbagMessage('success', 'delete', $object));
475
476        return $this->redirectToRoute($this->getRouteName('list'));
477    }
478}