Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
7.59% |
12 / 158 |
|
40.00% |
6 / 15 |
CRAP | |
0.00% |
0 / 1 |
UserController | |
7.59% |
12 / 158 |
|
40.00% |
6 / 15 |
1642.76 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
7 / 7 |
|
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 | |||
isSoftDelete | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
unarchiveAction | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
unarchiveConfirmationAction | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
listAction | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
listDataTables | |
0.00% |
0 / 44 |
|
0.00% |
0 / 1 |
156 | |||
getLabelAndKeysArray | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
2 | |||
getRequestCriteria | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
getActionCellsContent | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
72 | |||
getServicesContent | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
30 | |||
getRolesColor | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
30 |
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\Symfony\Security\UserProvider; |
28 | use App\Application\Traits\ServersideDatatablesTrait; |
29 | use App\Domain\User\Dictionary\UserMoreInfoDictionary; |
30 | use App\Domain\User\Dictionary\UserRoleDictionary; |
31 | use App\Domain\User\Form\Type\UserType; |
32 | use App\Domain\User\Model\Collectivity; |
33 | use App\Domain\User\Model\Service; |
34 | use App\Domain\User\Model\User; |
35 | use App\Domain\User\Repository; |
36 | use Doctrine\ORM\EntityManagerInterface; |
37 | use Knp\Snappy\Pdf; |
38 | use Symfony\Component\HttpFoundation\JsonResponse; |
39 | use Symfony\Component\HttpFoundation\Request; |
40 | use Symfony\Component\HttpFoundation\RequestStack; |
41 | use Symfony\Component\HttpFoundation\Response; |
42 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
43 | use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; |
44 | use Symfony\Component\Routing\RouterInterface; |
45 | use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; |
46 | use Symfony\Component\Security\Core\Security; |
47 | use Symfony\Contracts\Translation\TranslatorInterface; |
48 | use Symfony\Polyfill\Intl\Icu\Exception\MethodNotImplementedException; |
49 | |
50 | /** |
51 | * @property Repository\User $repository |
52 | */ |
53 | class UserController extends CRUDController |
54 | { |
55 | use ServersideDatatablesTrait; |
56 | |
57 | private PasswordHasherFactoryInterface $passwordHasherFactory; |
58 | |
59 | /** |
60 | * @var RequestStack |
61 | */ |
62 | private $requestStack; |
63 | |
64 | /** |
65 | * @var RouterInterface |
66 | */ |
67 | protected $router; |
68 | |
69 | /** |
70 | * @var Security |
71 | */ |
72 | protected $security; |
73 | |
74 | /** |
75 | * @var UserProvider |
76 | */ |
77 | protected $userProvider; |
78 | |
79 | public function __construct( |
80 | EntityManagerInterface $entityManager, |
81 | TranslatorInterface $translator, |
82 | Repository\User $repository, |
83 | RequestStack $requestStack, |
84 | PasswordHasherFactoryInterface $passwordHasherFactory, |
85 | Pdf $pdf, |
86 | RouterInterface $router, |
87 | Security $security, |
88 | UserProvider $userProvider, |
89 | AuthorizationCheckerInterface $authorizationChecker, |
90 | ) { |
91 | parent::__construct($entityManager, $translator, $repository, $pdf, $userProvider, $authorizationChecker); |
92 | $this->requestStack = $requestStack; |
93 | $this->passwordHasherFactory = $passwordHasherFactory; |
94 | $this->router = $router; |
95 | $this->security = $security; |
96 | $this->userProvider = $userProvider; |
97 | $this->authorizationChecker = $authorizationChecker; |
98 | } |
99 | |
100 | protected function getDomain(): string |
101 | { |
102 | return 'user'; |
103 | } |
104 | |
105 | protected function getModel(): string |
106 | { |
107 | return 'user'; |
108 | } |
109 | |
110 | protected function getModelClass(): string |
111 | { |
112 | return User::class; |
113 | } |
114 | |
115 | protected function getFormType(): string |
116 | { |
117 | return UserType::class; |
118 | } |
119 | |
120 | protected function isSoftDelete(): bool |
121 | { |
122 | return true; |
123 | } |
124 | |
125 | /** |
126 | * The unarchive action view |
127 | * Display a confirmation message to confirm data un-archivage. |
128 | */ |
129 | public function unarchiveAction(string $id): Response |
130 | { |
131 | $object = $this->repository->findOneById($id); |
132 | if (!$object) { |
133 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
134 | } |
135 | |
136 | return $this->render($this->getTemplatingBasePath('unarchive'), [ |
137 | 'object' => $object, |
138 | ]); |
139 | } |
140 | |
141 | /** |
142 | * The unarchive action |
143 | * Unarchive the data. |
144 | * |
145 | * @throws \Exception |
146 | */ |
147 | public function unarchiveConfirmationAction(string $id): Response |
148 | { |
149 | $object = $this->repository->findOneById($id); |
150 | if (!$object) { |
151 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
152 | } |
153 | |
154 | if (!\method_exists($object, 'setDeletedAt')) { |
155 | throw new MethodNotImplementedException('setDeletedAt'); |
156 | } |
157 | $object->setDeletedAt(null); |
158 | $this->repository->update($object); |
159 | |
160 | $this->addFlash('success', $this->getFlashbagMessage('success', 'unarchive', $object)); |
161 | |
162 | return $this->redirectToRoute($this->getRouteName('list')); |
163 | } |
164 | |
165 | public function listAction(): Response |
166 | { |
167 | $criteria = $this->getRequestCriteria(); |
168 | |
169 | return $this->render($this->getTemplatingBasePath('list'), [ |
170 | 'totalItem' => $this->repository->count($criteria), |
171 | 'route' => $this->router->generate('user_user_list_datatables', ['archive' => $criteria['archive']]), |
172 | ]); |
173 | } |
174 | |
175 | public function listDataTables(Request $request): JsonResponse |
176 | { |
177 | $criteria = $this->getRequestCriteria(); |
178 | $users = $this->getResults($request, $criteria); |
179 | $reponse = $this->getBaseDataTablesResponse($request, $users, $criteria); |
180 | |
181 | /** @var User $user */ |
182 | foreach ($users as $user) { |
183 | $roles = ''; |
184 | foreach ($user->getRoles() as $role) { |
185 | $span = '<span class="badge ' . $this->getRolesColor($role) . '">' . UserRoleDictionary::getFullRoles()[$role] . '</span>'; |
186 | $roles .= $span; |
187 | } |
188 | |
189 | $infos = ''; |
190 | foreach ($user->getMoreInfos() as $info) { |
191 | $span = '<span class="badge">' . UserMoreInfoDictionary::getMoreInfos()[$info] . '</span>'; |
192 | $infos .= $span; |
193 | } |
194 | |
195 | $userActifBgColor = 'bg-green'; |
196 | if (!$user->isEnabled()) { |
197 | $userActifBgColor = 'bg-red'; |
198 | } |
199 | |
200 | $collectivityActifBgColor = 'bg-green'; |
201 | if (!$user->getCollectivity() || !$user->getCollectivity()->isActive()) { |
202 | $collectivityActifBgColor = 'bg-red'; |
203 | } |
204 | |
205 | $actif = ' |
206 | <span class="badge ' . $userActifBgColor . '">' . $this->translator->trans('user.user.list.user') . '</span> |
207 | <span class="badge ' . $collectivityActifBgColor . '">' . $this->translator->trans('global.label.organization') . '</span>' |
208 | ; |
209 | |
210 | $services = '<ul>'; |
211 | foreach ($user->getServices() as $service) { |
212 | $services .= '<li>' . $service->getName() . '</li>'; |
213 | } |
214 | $services .= '</ul>'; |
215 | |
216 | $europeTimezone = new \DateTimeZone('Europe/Paris'); |
217 | $reponse['data'][] = [ |
218 | 'prenom' => $user->getFirstName(), |
219 | 'nom' => $user->getLastName(), |
220 | 'email' => $user->getEmail(), |
221 | 'collectivite' => $user->getCollectivity() ? $user->getCollectivity()->getName() : '[Structure supprimée]', |
222 | 'roles' => $roles, |
223 | 'moreInfos' => $infos, |
224 | 'actif' => $actif, |
225 | 'connexion' => !\is_null($user->getLastLogin()) ? $user->getLastLogin()->setTimezone($europeTimezone)->format('Y-m-d H:i') : null, |
226 | 'services' => $services, |
227 | 'createdAt' => $user->getCreatedAt() ? date_format($user->getCreatedAt(), 'd-m-Y H:i') : null, |
228 | 'updatedAt' => $user->getUpdatedAt() ? date_format($user->getUpdatedAt(), 'd-m-Y H:i') : null, |
229 | 'actions' => $this->getActionCellsContent($user), |
230 | ]; |
231 | } |
232 | |
233 | $jsonResponse = new JsonResponse(); |
234 | $jsonResponse->setJson(\json_encode($reponse)); |
235 | |
236 | return $jsonResponse; |
237 | } |
238 | |
239 | protected function getLabelAndKeysArray(): array |
240 | { |
241 | return [ |
242 | 'prenom', |
243 | 'nom', |
244 | 'email', |
245 | 'collectivite', |
246 | 'roles', |
247 | 'moreInfos', |
248 | 'actif', |
249 | 'connexion', |
250 | 'services', |
251 | 'createdAt', |
252 | 'updatedAt', |
253 | 'actions', |
254 | ]; |
255 | } |
256 | |
257 | private function getRequestCriteria() |
258 | { |
259 | $criteria = []; |
260 | $request = $this->requestStack->getMainRequest(); |
261 | $criteria['archive'] = $request->query->getBoolean('archive'); |
262 | |
263 | if (!$this->security->isGranted('ROLE_ADMIN')) { |
264 | /** @var User $user */ |
265 | $user = $this->security->getUser(); |
266 | $criteria['collectivitesReferees'] = $user->getCollectivitesReferees(); |
267 | } |
268 | |
269 | return $criteria; |
270 | } |
271 | |
272 | private function getActionCellsContent(User $user) |
273 | { |
274 | $cellContent = ''; |
275 | if ($this->security->getUser() !== $user && \is_null($user->getDeletedAt()) && !$this->isGranted('IS_IMPERSONATOR')) { |
276 | $cellContent .= |
277 | '<a href="' . $this->router->generate('reporting_dashboard_index', ['_switch_user' => $user->getUsername()]) . '"> |
278 | <i aria-hidden="true" class="fa fa-user-lock"></i> ' . |
279 | $this->translator->trans('global.action.impersonate') . |
280 | '</a> '; |
281 | } |
282 | |
283 | if ($this->security->isGranted('ROLE_ADMIN')) { |
284 | if (\is_null($user->getDeletedAt())) { |
285 | $cellContent .= |
286 | '<a href="' . $this->router->generate('user_user_edit', ['id' => $user->getId()]) . '"> |
287 | <i aria-hidden="true" class="fa fa-pencil"></i> ' . |
288 | $this->translator->trans('global.action.edit') . |
289 | '</a> '; |
290 | } |
291 | |
292 | if ($this->security->getUser() !== $user) { |
293 | if (\is_null($user->getDeletedAt())) { |
294 | $cellContent .= |
295 | '<a href="' . $this->router->generate('user_user_delete', ['id' => $user->getId()]) . '"> |
296 | <i aria-hidden="true" class="fa fa-archive"></i> ' . |
297 | $this->translator->trans('global.action.archive') . |
298 | '</a> '; |
299 | } else { |
300 | $cellContent .= |
301 | '<a href="' . $this->router->generate('user_user_unarchive', ['id' => $user->getId()]) . '"> |
302 | <i aria-hidden="true" class="fa fa-archive"></i> ' . |
303 | $this->translator->trans('global.action.unarchive') . |
304 | '</a> '; |
305 | } |
306 | |
307 | // $cellContent .= |
308 | // '<a href="' . $this->router->generate('user_user_delete', ['id' => $user->getId()]) . '"> |
309 | // <i aria-hidden="true" class="fa fa-trash"></i> ' . |
310 | // $this->translator->trans('global.action.delete') . |
311 | // '</a> '; |
312 | } |
313 | } |
314 | |
315 | return $cellContent; |
316 | } |
317 | |
318 | public function getServicesContent(string $collectivityId, string $userId): Response |
319 | { |
320 | $collectivity = $this->entityManager->getRepository(Collectivity::class)->findOneBy(['id' => $collectivityId]); |
321 | if (null === $collectivity) { |
322 | throw new NotFoundHttpException('Can\'t find collectivity for id ' . $collectivityId); |
323 | } |
324 | |
325 | $services = $this |
326 | ->entityManager |
327 | ->getRepository(Service::class) |
328 | ->findBy( |
329 | ['collectivity' => $collectivity], |
330 | ['name' => 'ASC'] |
331 | ); |
332 | |
333 | $serviceIdsSelected = []; |
334 | |
335 | if ('creer' !== $userId) { |
336 | $user = $this |
337 | ->entityManager |
338 | ->getRepository(User::class) |
339 | ->find($userId); |
340 | |
341 | $servicesAlreadySelected = $user->getServices()->getValues(); |
342 | |
343 | foreach ($servicesAlreadySelected as $service) { |
344 | $serviceIdsSelected[] = $service->getId(); |
345 | } |
346 | } |
347 | |
348 | $responseData = []; |
349 | |
350 | foreach ($services as $service) { |
351 | $responseData[] = [ |
352 | 'value' => $service->getId()->toString(), |
353 | 'text' => $service->__toString(), |
354 | 'selected' => in_array($service->getId(), $serviceIdsSelected), |
355 | ]; |
356 | } |
357 | |
358 | return new JsonResponse($responseData); |
359 | } |
360 | |
361 | private function getRolesColor(string $role) |
362 | { |
363 | switch ($role) { |
364 | case UserRoleDictionary::ROLE_ADMIN: |
365 | return 'bg-red'; |
366 | case UserRoleDictionary::ROLE_USER: |
367 | return 'bg-blue'; |
368 | case UserRoleDictionary::ROLE_API: |
369 | return 'bg-green'; |
370 | default: |
371 | return 'bg-red'; |
372 | } |
373 | } |
374 | } |