Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
8.18% covered (danger)
8.18%
18 / 220
29.41% covered (danger)
29.41%
5 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
NotificationController
8.18% covered (danger)
8.18%
18 / 220
29.41% covered (danger)
29.41%
5 / 17
7081.08
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getDomain
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getModel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getModelClass
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFormType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getListData
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 listAction
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 listDataTables
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
380
 generateActionCellContent
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
72
 formPrePersistData
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 markAsReadAllAction
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
90
 markAsReadAction
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
72
 markAsUnreadAction
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
72
 getLabelAndKeysArray
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
20
 getObjectLink
38.89% covered (danger)
38.89%
7 / 18
0.00% covered (danger)
0.00%
0 / 1
58.73
 deleteConfirmationAction
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 getRouteForModule
9.52% covered (danger)
9.52%
2 / 21
0.00% covered (danger)
0.00%
0 / 1
118.65
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
22declare(strict_types=1);
23
24namespace App\Domain\Notification\Controller;
25
26use App\Application\Controller\CRUDController;
27use App\Application\Symfony\Security\UserProvider;
28use App\Application\Traits\ServersideDatatablesTrait;
29use App\Domain\Notification\Model;
30use App\Domain\Notification\Model\Notification;
31use App\Domain\Notification\Model\NotificationUser;
32use App\Domain\Notification\Repository;
33use App\Domain\User\Dictionary\UserMoreInfoDictionary;
34use App\Domain\User\Dictionary\UserRoleDictionary;
35use App\Infrastructure\ORM\AIPD\Repository\AnalyseImpact;
36use Doctrine\Common\Collections\ArrayCollection;
37use Doctrine\ORM\EntityManagerInterface;
38use Doctrine\ORM\Tools\Pagination\Paginator;
39use Knp\Snappy\Pdf;
40use Symfony\Component\HttpFoundation\JsonResponse;
41use Symfony\Component\HttpFoundation\Request;
42use Symfony\Component\HttpFoundation\Response;
43use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
44use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
45use Symfony\Component\Routing\RouterInterface;
46use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
47use Symfony\Contracts\Translation\TranslatorInterface;
48
49/**
50 * @property Repository\Notification $repository
51 */
52class NotificationController extends CRUDController
53{
54    use ServersideDatatablesTrait;
55
56    /**
57     * @var RouterInterface
58     */
59    private $router;
60
61    /**
62     * @var AuthorizationCheckerInterface
63     */
64    protected $authorizationChecker;
65
66    /**
67     * @var UserProvider
68     */
69    protected $userProvider;
70
71    protected AnalyseImpact $aipdRepository;
72
73    public function __construct(
74        RouterInterface $router,
75        EntityManagerInterface $entityManager,
76        TranslatorInterface $translator,
77        Repository\Notification $repository,
78        AnalyseImpact $aipdRepository,
79        AuthorizationCheckerInterface $authorizationChecker,
80        UserProvider $userProvider,
81        Pdf $pdf,
82    ) {
83        parent::__construct($entityManager, $translator, $repository, $pdf, $userProvider, $authorizationChecker);
84        $this->router               = $router;
85        $this->authorizationChecker = $authorizationChecker;
86        $this->userProvider         = $userProvider;
87        $this->aipdRepository       = $aipdRepository;
88    }
89
90    protected function getDomain(): string
91    {
92        return 'notification';
93    }
94
95    protected function getModel(): string
96    {
97        return 'notification';
98    }
99
100    protected function getModelClass(): string
101    {
102        return Notification::class;
103    }
104
105    protected function getFormType(): string
106    {
107        return '';
108    }
109
110    protected function getListData()
111    {
112        $order = [
113            'createdAt' => 'DESC',
114        ];
115
116        return $this->repository->findAll($order);
117    }
118
119    public function listAction(): Response
120    {
121        $user = $this->getUser();
122
123        $criteria = [];
124
125        if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) {
126            $criteria['collectivity'] = $this->userProvider->getAuthenticatedUser()->getCollectivity();
127        }
128
129        return $this->render('Notification/Notification/list.html.twig', [
130            'totalItem' => $this->repository->count($criteria),
131            'route'     => $this->router->generate('notification_notification_list_datatables'),
132        ]);
133    }
134
135    public function listDataTables(Request $request): JsonResponse
136    {
137        $user = $this->userProvider->getAuthenticatedUser();
138
139        $criteria = [];
140
141        if (!$this->authorizationChecker->isGranted('ROLE_REFERENT')) {
142            $criteria['collectivity'] = new ArrayCollection([$user->getCollectivity(), null]);
143        }
144
145        if ($user) {
146            if (\in_array(UserRoleDictionary::ROLE_REFERENT, $user->getRoles())) {
147                $criteria['collectivity'] = $user->getCollectivitesReferees();
148            }
149        }
150
151        /** @var Paginator $notifications */
152        $notifications = $this->getResults($request, $criteria);
153
154        $reponse = $this->getBaseDataTablesResponse($request, $notifications, $criteria);
155
156        /** @var Notification $notification */
157        foreach ($notifications as $notification) {
158            $read   = '<span class="badge bg-green">' . $this->translator->trans('notifications.label.read') . '</span>';
159            $unread = '<span class="badge bg-yellow">' . $this->translator->trans('notifications.label.unread') . '</span>';
160
161            $link = $this->getObjectLink($notification);
162
163            $nameHtml = '<span>' . $notification->getName() . '</span> ';
164
165            if ($link && 'notification.actions.delete' !== $notification->getAction() && $this->repository->objectExists($notification)) {
166                $nameHtml = '<a href="' . $link . '">' . $notification->getName() . '</a>'
167                ;
168            }
169
170            if ($this->authorizationChecker->isGranted('ROLE_REFERENT') || in_array(UserMoreInfoDictionary::MOREINFO_DPD, $user->getMoreInfos())) {
171                $reponse['data'][] = [
172                    'state'        => $notification->getReadAt() ? $read : $unread,
173                    'module'       => $this->translator->trans($notification->getModule()),
174                    'action'       => $this->translator->trans($notification->getAction()),
175                    'name'         => $nameHtml,
176                    'object'       => $notification->getSubject(),
177                    'collectivity' => $this->authorizationChecker->isGranted('ROLE_REFERENT') && $notification->getCollectivity() ? $notification->getCollectivity()->getName() : '',
178                    'date'         => date_format($notification->getCreatedAt(), 'd-m-Y H:i'),
179                    'user'         => $notification->getCreatedBy() ? $notification->getCreatedBy()->__toString() : '',
180                    'read_date'    => $notification->getReadAt() ? $notification->getReadAt()->format('d-m-Y H:i') : '',
181                    'read_by'      => $notification->getReadBy() ? $notification->getReadBy()->__toString() : '',
182                    'actions'      => $this->generateActionCellContent($notification),
183                ];
184            } else {
185                $notificationUser = $notification->getNotificationUsers()->filter(function (NotificationUser $nu) use ($user) {
186                    return $nu->getUser() && $nu->getUser()->getId() === $user->getId();
187                })->first();
188
189                $reponse['data'][] = [
190                    'state'   => $notificationUser->getReadAt() ? $read : $unread,
191                    'module'  => $this->translator->trans($notification->getModule()),
192                    'action'  => $this->translator->trans($notification->getAction()),
193                    'name'    => $nameHtml,
194                    'object'  => $notification->getSubject(),
195                    'date'    => date_format($notification->getCreatedAt(), 'd-m-Y H:i'),
196                    'user'    => $notification->getCreatedBy() ? $notification->getCreatedBy()->__toString() : '',
197                    'actions' => $this->generateActionCellContent($notification),
198                ];
199            }
200        }
201
202        return new JsonResponse($reponse);
203    }
204
205    private function generateActionCellContent(Notification $notification)
206    {
207        $id = $notification->getId();
208
209        $user = $this->userProvider->getAuthenticatedUser();
210        $html = '';
211
212        if (
213            in_array('ROLE_ADMIN', $user->getRoles()) || in_array('ROLE_REFERENT', $user->getRoles())
214            || in_array(UserMoreInfoDictionary::MOREINFO_DPD, $user->getMoreInfos())
215        ) {
216            if (null === $notification->getReadAt()) {
217                $html .= '<a href="' . $this->router->generate('notification_notification_mark_as_read', ['id' => $id]) . '">
218<i aria-hidden="true" class="fas fa-clipboard-check"></i>&nbsp;
219                ' . $this->translator->trans('notifications.action.mark_as_read') . '
220                </a>';
221            } else {
222                $html .= ' <a href="' . $this->router->generate('notification_notification_mark_as_unread', ['id' => $id]) . '">
223<i aria-hidden="true" class="fas fa-clipboard"></i>&nbsp;
224                ' . $this->translator->trans('notifications.action.mark_as_unread') . '
225                </a>';
226            }
227        } else {
228            $notificationUser = $notification->getNotificationUsers()->filter(function (NotificationUser $nu) use ($user) {
229                return $nu->getUser() && $nu->getUser()->getId() === $user->getId();
230            })->first();
231            if ($notificationUser && null === $notificationUser->getReadAt()) {
232                $html .= '<a href="' . $this->router->generate('notification_notification_mark_as_read', ['id' => $id]) . '">
233<i aria-hidden="true" class="fas fa-clipboard-check"></i>&nbsp;
234                ' . $this->translator->trans('notifications.action.mark_as_read') . '
235                </a>';
236            } else {
237                $html .= ' <a href="' . $this->router->generate('notification_notification_mark_as_unread', ['id' => $id]) . '">
238<i aria-hidden="true" class="fas fa-clipboard"></i>&nbsp;
239                ' . $this->translator->trans('notifications.action.mark_as_unread') . '
240                </a>';
241            }
242        }
243
244        $html .= ' <a href="' . $this->router->generate('notification_notification_delete', ['id' => $id]) . '">
245<i aria-hidden="true" class="fas fa-trash"></i>&nbsp;
246                ' . $this->translator->trans('global.action.delete') . '
247                </a>';
248
249        return $html;
250    }
251
252    /**
253     * {@inheritdoc}
254     * Here, we wanna compute maturity score.
255     *
256     * @param Notification $object
257     */
258    public function formPrePersistData($object, $form = null)
259    {
260    }
261
262    /**
263     * Update read status from notification.
264     */
265    public function markAsReadAllAction(Request $request)
266    {
267        $notifications = $this->repository->findAll();
268        $user          = $this->userProvider->getAuthenticatedUser();
269        foreach ($notifications as $notification) {
270            if (is_array($notification)) {
271                $notification = $notification[0];
272            }
273            if ($notification->getDpo() && (in_array('ROLE_ADMIN', $user->getRoles()) || in_array('ROLE_REFERENT', $user->getRoles()) || in_array(UserMoreInfoDictionary::MOREINFO_DPD, $user->getMoreInfos()))) {
274                $notification->setReadAt(new \DateTime());
275                $notification->setReadBy($this->getUser());
276            } else {
277                $nu = $notification->getNotificationUsers()->filter(function ($n) use ($user) {
278                    /* @var Model\NotificationUser $n */
279                    return $n->getUser() && $n->getUser()->getId() === $user->getId();
280                })->first();
281                if ($nu) {
282                    $nu->setReadAt(new \DateTime());
283                }
284            }
285        }
286
287        $this->entityManager->flush();
288
289        $this->addFlash('success', $this->getFlashbagMessage('success', 'markall'));
290
291        $referer = $request->headers->get('referer');
292
293        return $this->redirect($referer);
294        // return $this->redirectToRoute($this->getRouteName('list'));
295    }
296
297    /**
298     * Update read_at and read_by from notification.
299     */
300    public function markAsReadAction(Request $request, string $id)
301    {
302        $notification = $this->repository->findOneByID($id);
303        if (!$notification) {
304            throw new NotFoundHttpException('Notification introuvable');
305        }
306
307        $user = $this->userProvider->getAuthenticatedUser();
308
309        if ($notification->getDpo() && (in_array('ROLE_ADMIN', $user->getRoles()) || in_array('ROLE_REFERENT', $user->getRoles()) || in_array(UserMoreInfoDictionary::MOREINFO_DPD, $user->getMoreInfos()))) {
310            $notification->setReadAt(new \DateTime());
311            $notification->setReadBy($this->getUser());
312            $this->entityManager->flush();
313        } else {
314            $nu = $notification->getNotificationUsers()->filter(function ($n) use ($user) {
315                /* @var Model\NotificationUser $n */
316                return $n->getUser() && $n->getUser()->getId() === $user->getId();
317            })->first();
318            if ($nu) {
319                $nu->setReadAt(new \DateTime());
320                $this->entityManager->flush();
321            }
322        }
323
324        $referer = $request->headers->get('referer');
325
326        return $this->redirect($referer);
327    }
328
329    /**
330     * Update read_at and read_by from notification to null.
331     */
332    public function markAsUnreadAction(Request $request, string $id)
333    {
334        /** @var Notification $notification */
335        $notification = $this->repository->findOneByID($id);
336        if (!$notification) {
337            throw new NotFoundHttpException('Notification introuvable');
338        }
339        $user = $this->userProvider->getAuthenticatedUser();
340        if ($notification->getDpo() && (in_array('ROLE_ADMIN', $user->getRoles()) || in_array('ROLE_REFERENT', $user->getRoles()) || in_array(UserMoreInfoDictionary::MOREINFO_DPD, $user->getMoreInfos()))) {
341            $notification->setReadAt(null);
342            $notification->setReadBy(null);
343            $this->entityManager->flush();
344        } else {
345            $user = $this->userProvider->getAuthenticatedUser();
346            $nu   = $notification->getNotificationUsers()->filter(function (NotificationUser $n) use ($user) {
347                return $n->getUser() && $n->getUser()->getId() === $user->getId();
348            })->first();
349            if ($nu) {
350                $nu->setReadAt(null);
351                $this->entityManager->flush();
352            }
353        }
354        $referer = $request->headers->get('referer');
355
356        return $this->redirect($referer);
357    }
358
359    protected function getLabelAndKeysArray(): array
360    {
361        $user = $this->userProvider->getAuthenticatedUser();
362        if ($this->authorizationChecker->isGranted('ROLE_ADMIN') || $this->authorizationChecker->isGranted('ROLE_REFERENT') || in_array(UserMoreInfoDictionary::MOREINFO_DPD, $user->getMoreInfos())) {
363            return [
364                'state',
365                'module',
366                'action',
367                'name',
368                'object',
369                'collectivity',
370                'date',
371                'user',
372                'read_date',
373                'read_by',
374            ];
375        }
376
377        return [
378            'state',
379            'module',
380            'action',
381            'name',
382            'object',
383            'date',
384            'user',
385        ];
386    }
387
388    private function getObjectLink(Notification $notification): string
389    {
390        try {
391            if ('notification.modules.aipd' === $notification->getModule() && 'notification.actions.validation' === $notification->getAction()) {
392                return $this->router->generate('aipd_analyse_impact_validation', ['id' => $notification->getObject()->id], UrlGeneratorInterface::ABSOLUTE_URL);
393            }
394            if ('notification.modules.aipd' === $notification->getModule() && 'notification.actions.state_change' === $notification->getAction()) {
395                return $this->router->generate('aipd_analyse_impact_evaluation', ['id' => $notification->getObject()->id], UrlGeneratorInterface::ABSOLUTE_URL);
396            }
397            if ('notification.modules.aipd' === $notification->getModule() && 'notification.actions.validated' === $notification->getAction()) {
398                /** @var \App\Domain\AIPD\Model\AnalyseImpact $aipd */
399                $aipd = $this->aipdRepository->findOneById($notification->getObject()->id);
400                if ($aipd) {
401                    return $this->router->generate('registry_treatment_show', ['id' => $aipd->getConformiteTraitement()->getTraitement()->getId()->toString()], UrlGeneratorInterface::ABSOLUTE_URL);
402                }
403
404                return '';
405            }
406            if ('notification.modules.aipd' === $notification->getModule() && 'notifications.actions.treatment_needs_aipd' === $notification->getAction()) {
407                return $this->router->generate('registry_conformite_traitement_start_aipd', ['id' => $notification->getObject()->id], UrlGeneratorInterface::ABSOLUTE_URL);
408            }
409            if ('notification.modules.document' === $notification->getModule() && 'notification.actions.delete' !== $notification->getAction()) {
410                return $notification->getObject()->url;
411            }
412            if ('notification.modules.action_plan' === $notification->getModule()) {
413                return $this->router->generate('registry_mesurement_show', ['id' => $notification->getObject()->id], UrlGeneratorInterface::ABSOLUTE_URL);
414            }
415
416            return $this->router->generate($this->getRouteForModule($notification->getModule()), ['id' => $notification->getObject()->id], UrlGeneratorInterface::ABSOLUTE_URL);
417        } catch (\Exception $e) {
418            return '';
419        }
420    }
421
422    public function deleteConfirmationAction(string $id): Response
423    {
424        /** @var Notification $notification */
425        $notification = $this->repository->findOneById($id);
426        if (!$notification) {
427            throw new NotFoundHttpException("No object found with ID '{$id}'");
428        }
429        if ($notification->getDpo()) {
430            $this->entityManager->remove($notification);
431            $this->entityManager->flush();
432        } else {
433            $user = $this->userProvider->getAuthenticatedUser();
434            $nu   = $notification->getNotificationUsers()->filter(function ($n) use ($user) {
435                /* @var Model\NotificationUser $n */
436                return $n->getUser()->getId() === $user->getId();
437            })->first();
438            if ($nu) {
439                $this->entityManager->remove($nu);
440                $this->entityManager->flush();
441            }
442        }
443
444        $this->addFlash('success', $this->getFlashbagMessage('success', 'delete', $notification));
445
446        return $this->redirectToRoute($this->getRouteName('list'));
447    }
448
449    private function getRouteForModule($module): string
450    {
451        switch ($module) {
452            case 'notification.modules.treatment':
453                return 'registry_treatment_show';
454            case 'notification.modules.subcontractor':
455            case 'notification.modules.contractor':
456                return 'registry_contractor_show';
457            case 'notification.modules.violation':
458                return 'registry_violation_show';
459            case 'notification.modules.proof':
460                return 'registry_proof_edit';
461            case 'notification.modules.protect_action':
462                return 'registry_mesurement_show';
463            case 'notification.modules.request':
464                return 'registry_request_show';
465            case 'notification.modules.user':
466                return 'user_user_edit';
467            case 'notification.modules.documentation':
468            case 'notification.modules.document':
469                return 'documentation_document_download';
470            case 'notification.modules.maturity':
471                return 'maturity_survey_edit';
472        }
473
474        return '';
475    }
476}