Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
10.45% |
23 / 220 |
|
27.78% |
5 / 18 |
CRAP | |
0.00% |
0 / 1 |
CollectivityController | |
10.45% |
23 / 220 |
|
27.78% |
5 / 18 |
4005.82 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
1 | |||
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 | |||
listAction | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
listDataTables | |
0.00% |
0 / 24 |
|
0.00% |
0 / 1 |
56 | |||
getActionCellsContent | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
6 | |||
getLabelAndKeysArray | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
2 | |||
getRequestCriteria | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 | |||
showAction | |
24.14% |
7 / 29 |
|
0.00% |
0 / 1 |
74.87 | |||
editAction | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
20 | |||
deleteAction | |
0.00% |
0 / 33 |
|
0.00% |
0 / 1 |
156 | |||
formPrePersistData | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
30 | |||
deleteConfirmationAction | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
clonedFromOnNullAction | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
deleteRelatedObjectsAction | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
182 | |||
deleteCollectivityAction | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 |
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\User\Controller; |
25 | |
26 | use App\Application\Controller\CRUDController; |
27 | use App\Application\Interfaces\CollectivityRelated; |
28 | use App\Application\Symfony\Security\UserProvider; |
29 | use App\Application\Traits\ServersideDatatablesTrait; |
30 | use App\Domain\Registry\Model\Mesurement; |
31 | use App\Domain\Registry\Model\Treatment; |
32 | use App\Domain\Registry\Repository as RegistryRepository; |
33 | use App\Domain\User\Dictionary\CollectivityTypeDictionary; |
34 | use App\Domain\User\Dictionary\UserRoleDictionary; |
35 | use App\Domain\User\Form\Type\CollectivityType; |
36 | use App\Domain\User\Form\Type\ReviewDataType; |
37 | use App\Domain\User\Model; |
38 | use App\Domain\User\Model\Collectivity; |
39 | use App\Domain\User\Model\User; |
40 | use App\Domain\User\Repository; |
41 | use Doctrine\ORM\EntityManagerInterface; |
42 | use Gaufrette\FilesystemInterface; |
43 | use Knp\Snappy\Pdf; |
44 | use Symfony\Component\Form\Form; |
45 | use Symfony\Component\HttpFoundation\File\UploadedFile; |
46 | use Symfony\Component\HttpFoundation\JsonResponse; |
47 | use Symfony\Component\HttpFoundation\Request; |
48 | use Symfony\Component\HttpFoundation\Response; |
49 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
50 | use Symfony\Component\Routing\RouterInterface; |
51 | use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; |
52 | use Symfony\Component\Security\Core\Security; |
53 | use Symfony\Component\String\Slugger\SluggerInterface; |
54 | use Symfony\Contracts\Translation\TranslatorInterface; |
55 | |
56 | /** |
57 | * @property Repository\Collectivity $repository |
58 | */ |
59 | class CollectivityController extends CRUDController |
60 | { |
61 | use ServersideDatatablesTrait; |
62 | |
63 | /** |
64 | * @var RouterInterface |
65 | */ |
66 | protected $router; |
67 | |
68 | /** |
69 | * @var FilesystemInterface |
70 | */ |
71 | protected $logoFilesystem; |
72 | |
73 | /** |
74 | * @var SluggerInterface |
75 | */ |
76 | protected $slugger; |
77 | |
78 | /** |
79 | * @var Security |
80 | */ |
81 | protected $security; |
82 | |
83 | protected RegistryRepository\Treatment $treatmentRepository; |
84 | |
85 | protected Repository\User $userRepository; |
86 | |
87 | protected RegistryRepository\Proof $proofRepository; |
88 | |
89 | protected RegistryRepository\Contractor $contractorRepository; |
90 | |
91 | protected RegistryRepository\Mesurement $mesurementRepository; |
92 | |
93 | public function __construct( |
94 | EntityManagerInterface $entityManager, |
95 | TranslatorInterface $translator, |
96 | Repository\Collectivity $repository, |
97 | Pdf $pdf, |
98 | RouterInterface $router, |
99 | Security $security, |
100 | RegistryRepository\Treatment $treatmentRepository, |
101 | RegistryRepository\Contractor $contractorRepository, |
102 | RegistryRepository\Proof $proofRepository, |
103 | RegistryRepository\Mesurement $mesurementRepository, |
104 | Repository\User $userRepository, |
105 | UserProvider $userProvider, |
106 | FilesystemInterface $logoFilesystem, |
107 | SluggerInterface $slugger, |
108 | AuthorizationCheckerInterface $authorizationChecker, |
109 | ) { |
110 | parent::__construct($entityManager, $translator, $repository, $pdf, $userProvider, $authorizationChecker); |
111 | $this->router = $router; |
112 | $this->security = $security; |
113 | $this->treatmentRepository = $treatmentRepository; |
114 | $this->contractorRepository = $contractorRepository; |
115 | $this->proofRepository = $proofRepository; |
116 | $this->userRepository = $userRepository; |
117 | $this->mesurementRepository = $mesurementRepository; |
118 | $this->userProvider = $userProvider; |
119 | $this->logoFilesystem = $logoFilesystem; |
120 | $this->slugger = $slugger; |
121 | $this->authorizationChecker = $authorizationChecker; |
122 | } |
123 | |
124 | protected function getDomain(): string |
125 | { |
126 | return 'user'; |
127 | } |
128 | |
129 | protected function getModel(): string |
130 | { |
131 | return 'collectivity'; |
132 | } |
133 | |
134 | protected function getModelClass(): string |
135 | { |
136 | return Collectivity::class; |
137 | } |
138 | |
139 | protected function getFormType(): string |
140 | { |
141 | return CollectivityType::class; |
142 | } |
143 | |
144 | public function listAction(): Response |
145 | { |
146 | $criteria = $this->getRequestCriteria(); |
147 | |
148 | return $this->render($this->getTemplatingBasePath('list'), [ |
149 | 'totalItem' => $this->repository->count($criteria), |
150 | 'route' => $this->router->generate('user_collectivity_list_datatables'), |
151 | ]); |
152 | } |
153 | |
154 | public function listDataTables(Request $request): JsonResponse |
155 | { |
156 | $criteria = $this->getRequestCriteria(); |
157 | $collectivities = $this->getResults($request, $criteria); |
158 | $reponse = $this->getBaseDataTablesResponse($request, $collectivities, $criteria); |
159 | |
160 | $active = '<span class="badge bg-green">' . $this->translator->trans('global.label.active') . '</span>'; |
161 | $inactive = '<span class="badge bg-red">' . $this->translator->trans('global.label.inactive') . '</span>'; |
162 | /** @var Collectivity $collectivity */ |
163 | foreach ($collectivities as $collectivity) { |
164 | $reponse['data'][] = [ |
165 | 'nom' => '<a href="' . $this->router->generate('user_collectivity_show', ['id' => $collectivity->getId()]) . '">' . $collectivity->getName() . '</a>', |
166 | 'nom_court' => $collectivity->getShortName(), |
167 | 'type' => !\is_null($collectivity->getType()) ? CollectivityTypeDictionary::getTypes()[$collectivity->getType()] ?? $collectivity->getType() : null, |
168 | 'informations_complementaires' => !\is_null($collectivity->getInformationsComplementaires()) ? nl2br($collectivity->getInformationsComplementaires()) : null, |
169 | 'siren' => $collectivity->getSiren(), |
170 | 'statut' => $collectivity->isActive() ? $active : $inactive, |
171 | 'nbr_cnil' => $collectivity->getNbrCnil(), |
172 | 'nbr_agents' => $collectivity->getNbrAgents(), |
173 | 'population' => $collectivity->getPopulation(), |
174 | // 'tel_referent_rgpd' => !\is_null($collectivity->getDpo()) ? ($collectivity->getDpo())->getPhoneNumber() : null, |
175 | 'createdAt' => !\is_null($collectivity->getCreatedAt()) ? $collectivity->getCreatedAt()->format('d-m-Y H:i') : null, |
176 | 'updatedAt' => !\is_null($collectivity->getUpdatedAt()) ? $collectivity->getUpdatedAt()->format('d-m-Y H:i') : null, |
177 | 'actions' => $this->getActionCellsContent($collectivity), |
178 | 'id' => $collectivity->getId(), |
179 | ]; |
180 | } |
181 | |
182 | $jsonResponse = new JsonResponse(); |
183 | $jsonResponse->setJson(\json_encode($reponse)); |
184 | |
185 | return $jsonResponse; |
186 | } |
187 | |
188 | private function getActionCellsContent(Collectivity $collectivity) |
189 | { |
190 | if (!$this->security->isGranted('ROLE_ADMIN')) { |
191 | return; |
192 | } |
193 | |
194 | $cellContent = '<a href="' . $this->router->generate('user_collectivity_edit', ['id' => $collectivity->getId()]) . '"> |
195 | <i aria-hidden="true" class="fa fa-pencil"></i> ' . |
196 | $this->translator->trans('global.action.edit') . |
197 | '</a>'; |
198 | |
199 | $cellContent .= '<a href="' . $this->router->generate('user_collectivity_delete', ['id' => $collectivity->getId()]) . '"> |
200 | <i aria-hidden="true" class="fa fa-trash"></i> ' . |
201 | $this->translator->trans('global.action.delete') . |
202 | '</a>'; |
203 | |
204 | return $cellContent; |
205 | } |
206 | |
207 | protected function getLabelAndKeysArray(): array |
208 | { |
209 | return [ |
210 | 'nom', |
211 | 'nom_court', |
212 | 'type', |
213 | 'informations_complementaires', |
214 | 'siren', |
215 | 'statut', |
216 | 'nbr_cnil', |
217 | 'nbr_agents', |
218 | 'population', |
219 | 'createdAt', |
220 | 'updatedAt', |
221 | 'actions', |
222 | 'id', |
223 | ]; |
224 | } |
225 | |
226 | private function getRequestCriteria() |
227 | { |
228 | $criteria = []; |
229 | |
230 | if (!$this->security->isGranted('ROLE_ADMIN') && $this->security->isGranted('ROLE_REFERENT')) { |
231 | /** @var User $user */ |
232 | $user = $this->security->getUser(); |
233 | $criteria['collectivitesReferees'] = $user->getCollectivitesReferees(); |
234 | } |
235 | if (!$this->security->isGranted('ROLE_REFERENT')) { |
236 | /** @var User $user */ |
237 | $user = $this->security->getUser(); |
238 | $criteria['id'] = $user->getCollectivity()->getid(); |
239 | } |
240 | |
241 | return $criteria; |
242 | } |
243 | |
244 | public function showAction(string $id): Response |
245 | { |
246 | /** @var User $user */ |
247 | $user = $this->security->getUser(); |
248 | if (\in_array(UserRoleDictionary::ROLE_REFERENT, $user->getRoles())) { |
249 | $collectivities = \array_filter(\iterable_to_array($user->getCollectivitesReferees()), function (Collectivity $collectivity) use ($id) { |
250 | return $collectivity->getId()->toString() === $id; |
251 | }); |
252 | |
253 | if (empty($collectivities)) { |
254 | throw $this->createAccessDeniedException(); |
255 | } |
256 | } |
257 | |
258 | $object = $this->repository->findOneById($id); |
259 | if (!$object) { |
260 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
261 | } |
262 | /** |
263 | * @var User $user |
264 | */ |
265 | $user = $this->getUser(); |
266 | if (!$user->hasAccessTo($object, false)) { |
267 | throw $this->createAccessDeniedException(); |
268 | } |
269 | $serviceEnabled = false; |
270 | if ($object instanceof Collectivity) { |
271 | $serviceEnabled = $object->getIsServicesEnabled(); |
272 | } elseif ($object instanceof CollectivityRelated && $object->getCollectivity()) { |
273 | $serviceEnabled = $object->getCollectivity()->getIsServicesEnabled(); |
274 | } |
275 | |
276 | $actionEnabled = true; |
277 | |
278 | if ($object instanceof CollectivityRelated && !$this->authorizationChecker->isGranted('ROLE_ADMIN') && !$user->getServices()->isEmpty()) { |
279 | $actionEnabled = $object->isInUserServices($this->userProvider->getAuthenticatedUser()); |
280 | } |
281 | |
282 | if (!$this->isGranted('ROLE_USER')) { |
283 | $actionEnabled = false; |
284 | } |
285 | |
286 | return $this->render($this->getTemplatingBasePath('show'), [ |
287 | 'object' => $object, |
288 | 'actionEnabled' => $actionEnabled, |
289 | 'serviceEnabled' => $serviceEnabled, |
290 | 'sections' => ReviewDataType::getSections(), |
291 | ]); |
292 | } |
293 | |
294 | public function editAction(Request $request, string $id): Response |
295 | { |
296 | // /** @var CollectivityRelated $object */ |
297 | $object = $this->repository->findOneById($id); |
298 | if (!$object) { |
299 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
300 | } |
301 | |
302 | /** @var User $user */ |
303 | $user = $this->getUser(); |
304 | if (!$user->hasAccessTo($object) || !$this->security->isGranted('ROLE_REFERENT')) { |
305 | return $this->redirectToRoute($this->getRouteName('list')); |
306 | } |
307 | |
308 | return parent::editAction($request, $id); |
309 | } |
310 | |
311 | /** |
312 | * The delete action view |
313 | * Display a confirmation message to confirm data deletion. |
314 | * |
315 | * @Override |
316 | */ |
317 | public function deleteAction(string $id): Response |
318 | { |
319 | $object = $this->repository->findOneById($id); |
320 | if (!$object) { |
321 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
322 | } |
323 | |
324 | /** @var User $user */ |
325 | $user = $this->getUser(); |
326 | if (!$user->hasAccessTo($object) || !$this->security->isGranted('ROLE_REFERENT')) { |
327 | return $this->redirectToRoute($this->getRouteName('list')); |
328 | } |
329 | |
330 | $stringObjects = []; |
331 | |
332 | $deletedTreaments = $this->treatmentRepository->findBy(['collectivity' => $object]); |
333 | foreach ($deletedTreaments as $deletedTreament) { |
334 | $stringObjects[] = 'Traitement - ' . $deletedTreament->getName(); |
335 | /** |
336 | * @var Treatment |
337 | */ |
338 | $aipds = $deletedTreament->getConformiteTraitement() ? $deletedTreament->getConformiteTraitement()->getAnalyseImpacts() : []; |
339 | foreach ($aipds as $aipd) { |
340 | $stringObjects[] = 'AIPD - ' . $aipd->__toString(); |
341 | } |
342 | } |
343 | |
344 | $deletedContractors = $this->contractorRepository->findBy(['collectivity' => $object]); |
345 | foreach ($deletedContractors as $deletedContractor) { |
346 | $stringObjects[] = 'Sous-traitant - ' . $deletedContractor->getName(); |
347 | } |
348 | |
349 | $deletedProofs = $this->proofRepository->findBy(['collectivity' => $object]); |
350 | foreach ($deletedProofs as $deletedProof) { |
351 | $stringObjects[] = 'Preuve - ' . $deletedProof->getName(); |
352 | } |
353 | |
354 | $deletedUsers = $this->userRepository->findBy(['collectivity' => $object]); |
355 | foreach ($deletedUsers as $deletedUser) { |
356 | $stringObjects[] = 'Utilisateur - ' . $deletedUser->getFirstname() . ' ' . $deletedUser->getLastname(); |
357 | } |
358 | |
359 | $deletedMesurements = $this->mesurementRepository->findBy(['collectivity' => $object]); |
360 | foreach ($deletedMesurements as $deletedMesurement) { |
361 | /* |
362 | * @var Mesurement |
363 | */ |
364 | if ($deletedMesurement->getClonedFrom()) { |
365 | $stringObjects[] = 'Action de protection - ' . $deletedMesurement->getClonedFrom()->getName(); |
366 | } |
367 | $stringObjects[] = 'Action de protection - ' . $deletedMesurement->getName(); |
368 | } |
369 | |
370 | return $this->render($this->getTemplatingBasePath('delete'), [ |
371 | 'object' => $object, |
372 | 'deletedObjects' => $stringObjects, |
373 | 'deletedTreatments' => $deletedTreaments, |
374 | 'deletedContractors' => $deletedContractors, |
375 | ]); |
376 | } |
377 | |
378 | public function formPrePersistData($object, $form = null) |
379 | { |
380 | /** @var Form $reviewDataForm */ |
381 | $reviewDataForm = $form->get('reviewData'); |
382 | if ($reviewDataForm) { |
383 | /** @var UploadedFile $logoFile */ |
384 | $logoFile = $reviewDataForm->get('logo')->getData(); |
385 | if ($logoFile) { |
386 | $originalFilename = pathinfo($logoFile->getClientOriginalName(), PATHINFO_FILENAME); |
387 | // this is needed to safely include the file name as part of the URL |
388 | $safeFilename = $this->slugger->slug($originalFilename); |
389 | $newFilename = $safeFilename . '-' . uniqid() . '.' . $logoFile->guessExtension(); |
390 | $this->logoFilesystem->write($newFilename, \fopen($logoFile->getRealPath(), 'r')); |
391 | |
392 | // updates the 'brochureFilename' property to store the PDF file name |
393 | // instead of its contents |
394 | /** @var Model\ReviewData $reviewData */ |
395 | $reviewData = $object->getReviewData(); |
396 | $reviewData->setLogo('/uploads/collectivity/logos/' . $newFilename); |
397 | $object->setReviewData($reviewData); |
398 | } |
399 | |
400 | if ($reviewDataForm->has('deleteLogo')) { |
401 | $deleteLogo = $reviewDataForm->get('deleteLogo')->getData(); |
402 | if ($deleteLogo) { |
403 | /** @var Model\ReviewData $reviewData */ |
404 | $reviewData = $object->getReviewData(); |
405 | $reviewData->setLogo(null); |
406 | $object->setReviewData($reviewData); |
407 | } |
408 | } |
409 | } |
410 | } |
411 | |
412 | public function deleteConfirmationAction(string $id): Response |
413 | { |
414 | $object = $this->repository->findOneById($id); |
415 | if (!$object) { |
416 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
417 | } |
418 | |
419 | /** @var User $user */ |
420 | $user = $this->getUser(); |
421 | if (!$user->hasAccessTo($object)) { |
422 | return $this->redirectToRoute($this->getRouteName('list')); |
423 | } |
424 | |
425 | return $this->render($this->getTemplatingBasePath('delete_processing'), [ |
426 | 'object' => $object, |
427 | ]); |
428 | } |
429 | |
430 | public function clonedFromOnNullAction(string $id) |
431 | { |
432 | $object = $this->repository->findOneById($id); |
433 | if (!$object) { |
434 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
435 | } |
436 | |
437 | $this->treatmentRepository->resetClonedFromCollectivity($object); |
438 | $this->mesurementRepository->resetClonedFromCollectivity($object); |
439 | $this->contractorRepository->resetClonedFromCollectivity($object); |
440 | |
441 | $this->entityManager->flush(); |
442 | |
443 | return new JsonResponse(); |
444 | } |
445 | |
446 | public function deleteRelatedObjectsAction($id, string $objectType) |
447 | { |
448 | $object = $this->repository->findOneById($id); |
449 | if (!$object) { |
450 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
451 | } |
452 | |
453 | /** @var User $user */ |
454 | $user = $this->getUser(); |
455 | if (!$user->hasAccessTo($object)) { |
456 | return new JsonResponse(); |
457 | } |
458 | |
459 | switch ($objectType) { |
460 | case 'treatments': |
461 | foreach ($this->treatmentRepository->findAllByCollectivity($object) as $treatment) { |
462 | $this->entityManager->remove($treatment); |
463 | } |
464 | break; |
465 | case 'mesurements': |
466 | foreach ($this->mesurementRepository->findAllByCollectivity($object) as $mesurement) { |
467 | $this->entityManager->remove($mesurement); |
468 | } |
469 | break; |
470 | case 'contractors': |
471 | foreach ($this->contractorRepository->findAllByCollectivity($object) as $mesurement) { |
472 | $this->entityManager->remove($mesurement); |
473 | } |
474 | break; |
475 | case 'users': |
476 | foreach ($this->userRepository->findBy(['collectivity' => $object]) as $user) { |
477 | $this->entityManager->remove($user); |
478 | } |
479 | break; |
480 | case 'proofs': |
481 | foreach ($this->proofRepository->findBy(['collectivity' => $object]) as $proof) { |
482 | $this->entityManager->remove($proof); |
483 | } |
484 | break; |
485 | } |
486 | $this->entityManager->flush(); |
487 | |
488 | return new JsonResponse(); |
489 | } |
490 | |
491 | public function deleteCollectivityAction(string $id) |
492 | { |
493 | $object = $this->repository->findOneById($id); |
494 | if (!$object) { |
495 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
496 | } |
497 | |
498 | /** @var User $user */ |
499 | $user = $this->getUser(); |
500 | if (!$user->hasAccessTo($object)) { |
501 | return $this->redirectToRoute($this->getRouteName('list')); |
502 | } |
503 | |
504 | $this->entityManager->remove($object); |
505 | $this->entityManager->flush(); |
506 | |
507 | $this->addFlash('success', $this->getFlashbagMessage('success', 'delete', $object)); |
508 | |
509 | return $this->redirectToRoute($this->getRouteName('list')); |
510 | } |
511 | } |