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