Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
8.56% |
19 / 222 |
|
20.00% |
4 / 20 |
CRAP | |
0.00% |
0 / 1 |
ToolController | |
8.56% |
19 / 222 |
|
20.00% |
4 / 20 |
3499.25 | |
0.00% |
0 / 1 |
__construct | |
90.00% |
9 / 10 |
|
0.00% |
0 / 1 |
3.01 | |||
getDomain | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getModel | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getModelClass | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getFormType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getListData | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
listAction | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
showAction | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
editAction | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
deleteAction | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
createAction | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
pdfAction | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
getRequestCriteria | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
20 | |||
reportAction | |
85.71% |
6 / 7 |
|
0.00% |
0 / 1 |
2.01 | |||
getLabelAndKeysArray | |
0.00% |
0 / 68 |
|
0.00% |
0 / 1 |
12 | |||
listDataTables | |
0.00% |
0 / 37 |
|
0.00% |
0 / 1 |
240 | |||
generateShowLink | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
generateActionCell | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
56 | |||
apiGetToolsByCollectivity | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
20 | |||
deleteConfirmationAction | |
0.00% |
0 / 17 |
|
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 | |
22 | declare(strict_types=1); |
23 | |
24 | namespace App\Domain\Registry\Controller; |
25 | |
26 | use App\Application\Controller\CRUDController; |
27 | use App\Application\Symfony\Security\UserProvider; |
28 | use App\Application\Traits\ServersideDatatablesTrait; |
29 | use App\Domain\Documentation\Model\Category; |
30 | use App\Domain\Registry\Dictionary\MesurementStatusDictionary; |
31 | use App\Domain\Registry\Dictionary\ToolTypeDictionary; |
32 | use App\Domain\Registry\Form\Type\ToolType; |
33 | use App\Domain\Registry\Model; |
34 | use App\Domain\Registry\Repository; |
35 | use App\Domain\Reporting\Handler\WordHandler; |
36 | use App\Domain\User\Dictionary\UserRoleDictionary; |
37 | use App\Domain\User\Model\Collectivity; |
38 | use App\Domain\User\Model\User; |
39 | use App\Domain\User\Repository as UserRepository; |
40 | use Doctrine\ORM\EntityManagerInterface; |
41 | use Knp\Snappy\Pdf; |
42 | use Symfony\Component\HttpFoundation\JsonResponse; |
43 | use Symfony\Component\HttpFoundation\Request; |
44 | use Symfony\Component\HttpFoundation\RequestStack; |
45 | use Symfony\Component\HttpFoundation\Response; |
46 | use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; |
47 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
48 | use Symfony\Component\Routing\RouterInterface; |
49 | use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; |
50 | use Symfony\Contracts\Translation\TranslatorInterface; |
51 | use Symfony\Polyfill\Intl\Icu\Exception\MethodNotImplementedException; |
52 | |
53 | /** |
54 | * @property Repository\Tool $repository |
55 | */ |
56 | class 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 | } |