Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
12.24% |
18 / 147 |
|
46.67% |
7 / 15 |
CRAP | |
0.00% |
0 / 1 |
ContractorController | |
12.24% |
18 / 147 |
|
46.67% |
7 / 15 |
962.17 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
6 / 6 |
|
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 / 8 |
|
0.00% |
0 / 1 |
2 | |||
getListData | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
reportAction | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
apiGetContractorsByCollectivity | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
20 | |||
listDataTables | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
56 | |||
isContractorInUserServices | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getLabelAndKeysArray | |
0.00% |
0 / 35 |
|
0.00% |
0 / 1 |
12 | |||
getRequestCriteria | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
getActionCellsContent | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 | |||
deleteConfirmationAction | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
42 |
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\Form\Type\ContractorType; |
31 | use App\Domain\Registry\Model\Contractor; |
32 | use App\Domain\Registry\Repository; |
33 | use App\Domain\Reporting\Handler\WordHandler; |
34 | use App\Domain\User\Dictionary\UserRoleDictionary; |
35 | use App\Domain\User\Model as UserModel; |
36 | use App\Domain\User\Model\User; |
37 | use App\Domain\User\Repository as UserRepository; |
38 | use Doctrine\ORM\EntityManagerInterface; |
39 | use Knp\Snappy\Pdf; |
40 | use Symfony\Component\HttpFoundation\JsonResponse; |
41 | use Symfony\Component\HttpFoundation\Request; |
42 | use Symfony\Component\HttpFoundation\Response; |
43 | use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; |
44 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
45 | use Symfony\Component\Routing\RouterInterface; |
46 | use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; |
47 | use Symfony\Contracts\Translation\TranslatorInterface; |
48 | use Symfony\Polyfill\Intl\Icu\Exception\MethodNotImplementedException; |
49 | |
50 | /** |
51 | * @property Repository\Contractor $repository |
52 | */ |
53 | class ContractorController extends CRUDController |
54 | { |
55 | use ServersideDatatablesTrait; |
56 | |
57 | /** |
58 | * @var UserRepository\Collectivity |
59 | */ |
60 | protected $collectivityRepository; |
61 | |
62 | /** |
63 | * @var WordHandler |
64 | */ |
65 | protected $wordHandler; |
66 | |
67 | /** |
68 | * @var AuthorizationCheckerInterface |
69 | */ |
70 | protected $authorizationChecker; |
71 | |
72 | /** |
73 | * @var UserProvider |
74 | */ |
75 | protected $userProvider; |
76 | |
77 | /** |
78 | * @var RouterInterface |
79 | */ |
80 | protected $router; |
81 | |
82 | public function __construct( |
83 | EntityManagerInterface $entityManager, |
84 | TranslatorInterface $translator, |
85 | Repository\Contractor $repository, |
86 | UserRepository\Collectivity $collectivityRepository, |
87 | WordHandler $wordHandler, |
88 | AuthorizationCheckerInterface $authorizationChecker, |
89 | UserProvider $userProvider, |
90 | Pdf $pdf, |
91 | RouterInterface $router, |
92 | ) { |
93 | parent::__construct($entityManager, $translator, $repository, $pdf, $userProvider, $authorizationChecker); |
94 | $this->collectivityRepository = $collectivityRepository; |
95 | $this->wordHandler = $wordHandler; |
96 | $this->authorizationChecker = $authorizationChecker; |
97 | $this->userProvider = $userProvider; |
98 | $this->router = $router; |
99 | } |
100 | |
101 | protected function getDomain(): string |
102 | { |
103 | return 'registry'; |
104 | } |
105 | |
106 | protected function getModel(): string |
107 | { |
108 | return 'contractor'; |
109 | } |
110 | |
111 | protected function getModelClass(): string |
112 | { |
113 | return Contractor::class; |
114 | } |
115 | |
116 | protected function getFormType(): string |
117 | { |
118 | return ContractorType::class; |
119 | } |
120 | |
121 | public function listAction(): Response |
122 | { |
123 | $category = $this->entityManager->getRepository(Category::class)->findOneBy([ |
124 | 'name' => 'Sous-traitant', |
125 | ]); |
126 | |
127 | return $this->render($this->getTemplatingBasePath('list'), [ |
128 | 'totalItem' => $this->repository->count($this->getRequestCriteria()), |
129 | 'category' => $category, |
130 | 'route' => $this->router->generate('registry_contractor_list_datatables'), |
131 | ]); |
132 | } |
133 | |
134 | protected function getListData() |
135 | { |
136 | if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) { |
137 | return $this->repository->findAll(); |
138 | } |
139 | |
140 | return $this->repository->findAllByCollectivity($this->userProvider->getAuthenticatedUser()->getCollectivity()); |
141 | } |
142 | |
143 | /** |
144 | * Generate a word report of contractors. |
145 | * |
146 | * @throws \PhpOffice\PhpWord\Exception\Exception |
147 | */ |
148 | public function reportAction(): Response |
149 | { |
150 | $objects = $this->repository->findAllByCollectivity( |
151 | $this->userProvider->getAuthenticatedUser()->getCollectivity(), |
152 | ['name' => 'asc'] |
153 | ); |
154 | |
155 | return $this->wordHandler->generateRegistryContractorReport($objects); |
156 | } |
157 | |
158 | /** |
159 | * Get all active treatments of a collectivity and return their id/name as JSON. |
160 | */ |
161 | public function apiGetContractorsByCollectivity(string $collectivityId): Response |
162 | { |
163 | if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) { |
164 | throw new AccessDeniedHttpException('You can\'t access to a collectivity contractor data'); |
165 | } |
166 | |
167 | /** @var UserModel\Collectivity|null $collectivity */ |
168 | $collectivity = $this->collectivityRepository->findOneById($collectivityId); |
169 | if (null === $collectivity) { |
170 | throw new NotFoundHttpException('Can\'t find collectivity for id ' . $collectivityId); |
171 | } |
172 | |
173 | $contractors = $this->repository->findAllByCollectivity( |
174 | $collectivity, |
175 | [ |
176 | 'name' => 'ASC', |
177 | ] |
178 | ); |
179 | $responseData = []; |
180 | |
181 | /** @var Contractor $contractor */ |
182 | foreach ($contractors as $contractor) { |
183 | $responseData[] = [ |
184 | 'value' => $contractor->getId()->toString(), |
185 | 'text' => $contractor->__toString(), |
186 | ]; |
187 | } |
188 | |
189 | return new JsonResponse($responseData); |
190 | } |
191 | |
192 | public function listDataTables(Request $request): JsonResponse |
193 | { |
194 | $criteria = $this->getRequestCriteria(); |
195 | $contractors = $this->getResults($request, $criteria); |
196 | $reponse = $this->getBaseDataTablesResponse($request, $contractors, $criteria); |
197 | |
198 | $yes = '<span class="badge bg-green">' . $this->translator->trans('global.label.yes') . '</span>'; |
199 | $no = '<span class="badge bg-red">' . $this->translator->trans('global.label.no') . '</span>'; |
200 | |
201 | /** @var Contractor $contractor */ |
202 | foreach ($contractors as $contractor) { |
203 | $contractorLink = '<a href="' . $this->router->generate('registry_contractor_show', ['id' => $contractor->getId()->toString()]) . '"> |
204 | ' . \htmlspecialchars($contractor->getName()) . ' |
205 | </a>'; |
206 | |
207 | $reponse['data'][] = [ |
208 | 'id' => $contractor->getId(), |
209 | 'nom' => $contractorLink, |
210 | 'collectivite' => $contractor->getCollectivity()->getName(), |
211 | 'service' => $contractor->getService() ? $contractor->getService()->getName() : '', |
212 | 'clauses_contractuelles' => $contractor->isContractualClausesVerified() ? $yes : $no, |
213 | 'element_securite' => $contractor->isAdoptedSecurityFeatures() ? $yes : $no, |
214 | 'registre_traitements' => $contractor->isMaintainsTreatmentRegister() ? $yes : $no, |
215 | 'donnees_hors_eu' => $contractor->isSendingDataOutsideEu() ? |
216 | '<span class="badge bg-green">' . $this->translator->trans('global.label.yes') . '</span>' : |
217 | '<span class="badge bg-red">' . $this->translator->trans('global.label.no') . '</span>', |
218 | 'createdAt' => date_format($contractor->getCreatedAt(), 'd-m-Y H:i'), |
219 | 'updatedAt' => date_format($contractor->getUpdatedAt(), 'd-m-Y H:i'), |
220 | 'actions' => $this->getActionCellsContent($contractor), |
221 | ]; |
222 | } |
223 | |
224 | $jsonResponse = new JsonResponse(); |
225 | $jsonResponse->setJson(\json_encode($reponse)); |
226 | |
227 | return $jsonResponse; |
228 | } |
229 | |
230 | private function isContractorInUserServices(Contractor $contractor): bool |
231 | { |
232 | $user = $this->userProvider->getAuthenticatedUser(); |
233 | |
234 | if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) { |
235 | return true; |
236 | } |
237 | |
238 | return $contractor->isInUserServices($user); |
239 | } |
240 | |
241 | protected function getLabelAndKeysArray(): array |
242 | { |
243 | if ($this->isGranted('ROLE_REFERENT')) { |
244 | return [ |
245 | 'nom', |
246 | 'collectivite', |
247 | 'service', |
248 | 'clauses_contractuelles', |
249 | 'element_securite', |
250 | 'registre_traitements', |
251 | 'donnees_hors_eu', |
252 | 'createdAt', |
253 | 'updatedAt', |
254 | 'actions', |
255 | ]; |
256 | } |
257 | if ($this->userProvider->getAuthenticatedUser()->hasServices()) { |
258 | return [ |
259 | 'nom', |
260 | 'service', |
261 | 'clauses_contractuelles', |
262 | 'element_securite', |
263 | 'registre_traitements', |
264 | 'donnees_hors_eu', |
265 | 'createdAt', |
266 | 'updatedAt', |
267 | 'actions', |
268 | ]; |
269 | } |
270 | |
271 | return [ |
272 | 'nom', |
273 | 'clauses_contractuelles', |
274 | 'element_securite', |
275 | 'registre_traitements', |
276 | 'donnees_hors_eu', |
277 | 'createdAt', |
278 | 'updatedAt', |
279 | 'actions', |
280 | ]; |
281 | } |
282 | |
283 | private function getRequestCriteria() |
284 | { |
285 | $criteria = []; |
286 | $user = $this->userProvider->getAuthenticatedUser(); |
287 | |
288 | if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) { |
289 | $criteria['collectivity'] = $user->getCollectivity(); |
290 | } |
291 | |
292 | if (\in_array(UserRoleDictionary::ROLE_REFERENT, $user->getRoles())) { |
293 | $criteria['collectivity'] = $user->getCollectivitesReferees(); |
294 | } |
295 | |
296 | return $criteria; |
297 | } |
298 | |
299 | private function getActionCellsContent(Contractor $sousTraitant) |
300 | { |
301 | $user = $this->userProvider->getAuthenticatedUser(); |
302 | if ($user->getServices()->isEmpty() || $this->isContractorInUserServices($sousTraitant)) { |
303 | $cellContent = '<a href="' . $this->router->generate('registry_contractor_edit', ['id' => $sousTraitant->getId()]) . '"> |
304 | <i aria-hidden="true" class="fa fa-pencil"></i> ' . |
305 | $this->translator->trans('global.action.edit') . |
306 | '</a>'; |
307 | |
308 | $cellContent .= |
309 | '<a href="' . $this->router->generate('registry_contractor_delete', ['id' => $sousTraitant->getId()]) . '"> |
310 | <i aria-hidden="true" class="fa fa-trash"></i> ' . |
311 | $this->translator->trans('global.action.delete') . |
312 | '</a>'; |
313 | |
314 | return $cellContent; |
315 | } |
316 | |
317 | return null; |
318 | } |
319 | |
320 | /** |
321 | * The deletion action |
322 | * Delete the data. |
323 | * OVERRIDE of the CRUDController to manage clone id. |
324 | * |
325 | * @throws \Exception |
326 | */ |
327 | public function deleteConfirmationAction(string $id): Response |
328 | { |
329 | $object = $this->repository->findOneById($id); |
330 | if (!$object) { |
331 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
332 | } |
333 | |
334 | /** @var User $user */ |
335 | $user = $this->getUser(); |
336 | if (!$user->hasAccessTo($object)) { |
337 | return $this->redirectToRoute($this->getRouteName('list')); |
338 | } |
339 | |
340 | if ($this->isSoftDelete()) { |
341 | if (!\method_exists($object, 'setDeletedAt')) { |
342 | throw new MethodNotImplementedException('setDeletedAt'); |
343 | } |
344 | $object->setDeletedAt(new \DateTimeImmutable()); |
345 | $this->repository->update($object); |
346 | } else { |
347 | /* Delete clonedFrom id from clone to prevent SQL error on foreign key */ |
348 | foreach ($this->repository->findBy(['clonedFrom' => $id]) as $clone) { |
349 | $clone->setClonedFrom(null); |
350 | } |
351 | $this->entityManager->remove($object); |
352 | $this->entityManager->flush(); |
353 | } |
354 | |
355 | $this->addFlash('success', $this->getFlashbagMessage('success', 'delete', $object)); |
356 | |
357 | return $this->redirectToRoute($this->getRouteName('list')); |
358 | } |
359 | } |