Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
53.16% covered (warning)
53.16%
101 / 190
16.67% covered (danger)
16.67%
2 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
NotificationEventSubscriber
53.16% covered (warning)
53.16%
101 / 190
16.67% covered (danger)
16.67%
2 / 12
284.81
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 getSubscribedEvents
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 onNeedsAIPD
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
12
 onLateSurvey
95.45% covered (success)
95.45%
21 / 22
0.00% covered (danger)
0.00%
0 / 1
3
 onLateAction
96.00% covered (success)
96.00%
24 / 25
0.00% covered (danger)
0.00%
0 / 1
3
 onLateRequest
95.83% covered (success)
95.83%
23 / 24
0.00% covered (danger)
0.00%
0 / 1
3
 onNoLogin
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
6
 saveEmailNotificationForRefOp
55.56% covered (warning)
55.56%
5 / 9
0.00% covered (danger)
0.00%
0 / 1
11.30
 saveEmailNotificationForRespTrait
55.56% covered (warning)
55.56%
5 / 9
0.00% covered (danger)
0.00%
0 / 1
11.30
 saveEmailNotificationForDPOs
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
90
 saveEmailNotifications
7.14% covered (danger)
7.14%
1 / 14
0.00% covered (danger)
0.00%
0 / 1
34.82
 normalizerOptions
53.33% covered (warning)
53.33%
8 / 15
0.00% covered (danger)
0.00%
0 / 1
3.91
1<?php
2
3namespace App\Domain\Notification\Subscriber;
4
5use App\Application\Interfaces\CollectivityRelated;
6use App\Domain\Notification\Dictionary\NotificationModuleDictionary;
7use App\Domain\Notification\Event\ConformiteTraitementNeedsAIPDEvent;
8use App\Domain\Notification\Event\LateActionEvent;
9use App\Domain\Notification\Event\LateRequestEvent;
10use App\Domain\Notification\Event\LateSurveyEvent;
11use App\Domain\Notification\Event\NoLoginEvent;
12use App\Domain\Notification\Model\Notification;
13use App\Domain\Notification\Model\NotificationUser;
14use App\Domain\Notification\Serializer\NotificationNormalizer;
15use App\Domain\Registry\Model\ConformiteTraitement\ConformiteTraitement;
16use App\Domain\User\Dictionary\UserMoreInfoDictionary;
17use App\Domain\User\Model\Collectivity;
18use App\Domain\User\Model\User;
19use App\Domain\User\Repository\User as UserRepository;
20use App\Infrastructure\ORM\Notification\Repository\Notification as NotificationRepository;
21use App\Infrastructure\ORM\Notification\Repository\NotificationUser as NotificationUserRepository;
22use Symfony\Component\EventDispatcher\EventSubscriberInterface;
23use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
24use Symfony\Contracts\Translation\TranslatorInterface;
25
26/**
27 * This event subscriber creates notification for things that are trigerred by a cron job.
28 */
29class NotificationEventSubscriber implements EventSubscriberInterface
30{
31    protected NotificationRepository $notificationRepository;
32    protected NotificationUserRepository $notificationUserRepository;
33    protected NotificationNormalizer $normalizer;
34    protected UserRepository $userRepository;
35    protected TranslatorInterface $translator;
36    protected string $requestDays;
37    protected string $surveyDays;
38
39    public function __construct(
40        NotificationRepository $notificationRepository,
41        NotificationUserRepository $notificationUserRepository,
42        NotificationNormalizer $normalizer,
43        UserRepository $userRepository,
44        TranslatorInterface $translator,
45        string $requestDays,
46        string $surveyDays,
47    ) {
48        $this->notificationRepository     = $notificationRepository;
49        $this->notificationUserRepository = $notificationUserRepository;
50        $this->normalizer                 = $normalizer;
51        $this->userRepository             = $userRepository;
52        $this->translator                 = $translator;
53        $this->requestDays                = $requestDays;
54        $this->surveyDays                 = $surveyDays;
55    }
56
57    public static function getSubscribedEvents()
58    {
59        return [
60            LateActionEvent::class                    => 'onLateAction',
61            LateRequestEvent::class                   => 'onLateRequest',
62            NoLoginEvent::class                       => 'onNoLogin',
63            LateSurveyEvent::class                    => 'onLateSurvey',
64            ConformiteTraitementNeedsAIPDEvent::class => 'onNeedsAIPD',
65        ];
66    }
67
68    public function onNeedsAIPD(ConformiteTraitementNeedsAIPDEvent $event)
69    {
70        $conformite = $event->getConformiteTraitement();
71
72        $collectivity = $conformite->getTraitement()->getCollectivity();
73        $existing     = $this->notificationRepository->findBy([
74            'module'       => 'notification.modules.aipd',
75            'collectivity' => $collectivity,
76            'action'       => 'notifications.actions.treatment_needs_aipd',
77            'name'         => $conformite->__toString(),
78        ]);
79
80        if ($existing && count($existing)) {
81            return;
82        }
83
84        $norm  = $this->normalizer->normalize($conformite, null, self::normalizerOptions());
85        $users = $this->userRepository->findNonDpoUsersForCollectivity($collectivity);
86
87        $notification = new Notification();
88        $notification->setModule('notification.modules.aipd');
89        $notification->setCollectivity($collectivity);
90        $notification->setAction('notifications.actions.treatment_needs_aipd');
91        $notification->setName($conformite->__toString());
92        $notification->setObject((object) $norm);
93        $notification->setDpo(true);
94        $notification->setSubject('');
95        // $this->notificationRepository->insert($notification);
96
97        $nus = $this->notificationUserRepository->saveUsers($notification, $users);
98
99        $notification->setNotificationUsers($nus);
100        $this->notificationRepository->insert($notification);
101        $this->saveEmailNotificationForDPOs($notification, $conformite);
102    }
103
104    /**
105     * Indice de maturité non réalisé depuis plus de...
106     *
107     * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface
108     */
109    public function onLateSurvey(LateSurveyEvent $event)
110    {
111        $survey   = $event->getSurvey();
112        $existing = $this->notificationRepository->findBy([
113            'module'       => 'notification.modules.maturity',
114            'collectivity' => $survey->getCollectivity(),
115            'action'       => 'notifications.actions.late_survey',
116            'name'         => $survey->__toString(),
117        ]);
118        if ($existing && count($existing)) {
119            return;
120        }
121        $norm = $this->normalizer->normalize($survey, null, self::normalizerOptions());
122
123        $users = $this->userRepository->findNonDpoUsersForCollectivity($survey->getCollectivity());
124
125        $notification = new Notification();
126        $notification->setModule('notification.modules.maturity');
127        $notification->setCollectivity($survey->getCollectivity());
128        $notification->setAction('notifications.actions.late_survey');
129        $notification->setName($survey->__toString());
130        $notification->setObject((object) $norm);
131        $notification->setDpo(true);
132        $notification->setSubject($this->translator->trans('notifications.subject.late_survey', ['%days%' => $this->surveyDays]));
133        $nus = $this->notificationUserRepository->saveUsers($notification, $users);
134
135        $notification->setNotificationUsers($nus);
136        $this->notificationRepository->insert($notification);
137    }
138
139    /**
140     * Action planifiée en retard.
141     *
142     * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface
143     */
144    public function onLateAction(LateActionEvent $event)
145    {
146        $action   = $event->getMesurement();
147        $existing = $this->notificationRepository->findBy([
148            'module'       => 'notification.modules.' . NotificationModuleDictionary::ACTION_PLAN,
149            'collectivity' => $action->getCollectivity(),
150            'action'       => 'notifications.actions.late_action',
151            'name'         => $action->getName(),
152        ]);
153        if ($existing && count($existing)) {
154            return;
155        }
156
157        $norm = $this->normalizer->normalize($action, null, self::normalizerOptions());
158
159        $users        = $this->userRepository->findNonDpoUsersForCollectivity($action->getCollectivity());
160        $notification = new Notification();
161        $notification->setModule('notification.modules.' . NotificationModuleDictionary::ACTION_PLAN);
162        $notification->setCollectivity($action->getCollectivity());
163        $notification->setAction('notifications.actions.late_action');
164        $notification->setName($action->getName());
165        $notification->setObject((object) $norm);
166        $notification->setDpo(true);
167        $ob   = $notification->getObject();
168        $date = \DateTime::createFromFormat(DATE_ATOM, $ob->planificationDate)->format('d/m/Y');
169
170        $notification->setSubject($this->translator->trans('notifications.subject.late_action', ['%date%' => $date]));
171        $nus = $this->notificationUserRepository->saveUsers($notification, $users);
172
173        $notification->setNotificationUsers($nus);
174        $this->notificationRepository->insert($notification);
175
176        // Send email to référent opérationnel
177        $this->saveEmailNotificationForRefOp($notification, $action);
178    }
179
180    public function onLateRequest(LateRequestEvent $event)
181    {
182        $request  = $event->getRequest();
183        $existing = $this->notificationRepository->findBy([
184            'module'       => 'notification.modules.request',
185            'collectivity' => $request->getCollectivity(),
186            'action'       => 'notifications.actions.late_request',
187            'name'         => $request->__toString(),
188        ]);
189        if ($existing && count($existing)) {
190            return;
191        }
192
193        $norm = $this->normalizer->normalize($request, null, self::normalizerOptions());
194
195        $users = $this->userRepository->findNonDpoUsersForCollectivity($request->getCollectivity());
196
197        $notification = new Notification();
198        $notification->setModule('notification.modules.request');
199        $notification->setCollectivity($request->getCollectivity());
200        $notification->setAction('notifications.actions.late_request');
201        $notification->setName($request->__toString());
202        $notification->setObject((object) $norm);
203        $notification->setDpo(true);
204        $notification->setSubject($this->translator->trans('notifications.subject.late_request', ['%days%' => $this->requestDays]));
205        $nus = $this->notificationUserRepository->saveUsers($notification, $users);
206
207        $notification->setNotificationUsers($nus);
208        $this->notificationRepository->insert($notification);
209        // Send email to référent opérationnel and responsable de traitement
210        $this->saveEmailNotificationForRefOp($notification, $request);
211        $this->saveEmailNotificationForRespTrait($notification, $request);
212    }
213
214    public function onNoLogin(NoLoginEvent $event)
215    {
216        // Send email to référent opérationnel
217        // Add notification for DPD
218        $user     = $event->getUser();
219        $existing = $this->notificationRepository->findBy([
220            'module'       => 'notification.modules.user',
221            'collectivity' => $user->getCollectivity(),
222            'action'       => 'notifications.actions.no_login',
223            'name'         => $user->getFullName(),
224        ]);
225        if (count($existing)) {
226            return;
227        }
228        $notification = new Notification();
229
230        $notification->setModule('notification.modules.user');
231        $notification->setCollectivity($user->getCollectivity());
232        $notification->setAction('notifications.actions.no_login');
233        $notification->setName($user->getFullName());
234        // $notification->setCreatedBy($user);
235        $notification->setObject((object) $this->normalizer->normalize($user, null, self::normalizerOptions()));
236        $notification->setDpo(true);
237        $notification->setSubject($this->translator->trans('notifications.subject.no_login'));
238        $this->notificationRepository->insert($notification);
239
240        $this->saveEmailNotificationForRefOp($notification, $user);
241        // If no NotificationUser, this means the notification is for all DPOs
242        // The emails will be sent with notifications:send command to all users that have a unsent NotificationUser with an email address
243    }
244
245    private function saveEmailNotificationForRefOp(Notification $notification, CollectivityRelated $object)
246    {
247        // Get referent operationnels for this collectivity
248        $refs = $object->getCollectivity()->getUsers()->filter(function (User $u) {
249            $mi = $u->getMoreInfos();
250
251            return $mi && isset($mi[UserMoreInfoDictionary::MOREINFO_OPERATIONNAL]) && $mi[UserMoreInfoDictionary::MOREINFO_OPERATIONNAL];
252        });
253        if (0 === $refs->count()) {
254            // No ref OP, get from collectivity
255            if ($object->getCollectivity() && $object->getCollectivity()->getReferent()) {
256                if ($object->getCollectivity()->getReferent()->getNotification()) {
257                    $refs = [$object->getCollectivity()->getReferent()->getMail()];
258                }
259            }
260        }
261        // Add notification with email address for the référents
262        $this->saveEmailNotifications($notification, $refs);
263    }
264
265    private function saveEmailNotificationForRespTrait(Notification $notification, CollectivityRelated $object)
266    {
267        // Get referent operationnels for this collectivity
268        $refs = $object->getCollectivity()->getUsers()->filter(function (User $u) {
269            $mi = $u->getMoreInfos();
270
271            return $mi && isset($mi[UserMoreInfoDictionary::MOREINFO_TREATMENT]) && $mi[UserMoreInfoDictionary::MOREINFO_TREATMENT];
272        });
273        if (0 === $refs->count()) {
274            // No ref OP, get from collectivity
275            if ($object->getCollectivity() && $object->getCollectivity()->getLegalManager()) {
276                if ($object->getCollectivity()->getLegalManager()->getNotification()) {
277                    $refs = [$object->getCollectivity()->getLegalManager()->getMail()];
278                }
279            }
280        }
281
282        $this->saveEmailNotifications($notification, $refs);
283    }
284
285    private function saveEmailNotificationForDPOs(Notification $notification, ConformiteTraitement $object)
286    {
287        // TODO envoyer à tous les ADMINS + MOREINFO_DPD
288        // Get DPOs
289        $t            = $object->getTraitement();
290        $collectivity = $t->getCollectivity();
291        $refs         = $collectivity->getUsers()->filter(function (User $u) use ($collectivity) {
292            $mi = $u->getMoreInfos();
293
294            $refColIds = [];
295            /** @var Collectivity $col */
296            foreach ($u->getCollectivitesReferees() as $col) {
297                $refColIds[] = $col->getId()->toString();
298            }
299
300            return in_array('ROLE_ADMIN', $u->getRoles())
301                || (in_array('ROLE_REFERENT', $u->getRoles()) && in_array($collectivity->getId()->toString(), $refColIds))
302                || ($mi && isset($mi[UserMoreInfoDictionary::MOREINFO_DPD]) && $mi[UserMoreInfoDictionary::MOREINFO_DPD]);
303        });
304
305        // Also get DPOs from collectivity
306        if ($collectivity->getDpo()) {
307            if ($collectivity->getDpo()->getNotification()) {
308                $refs[] = $t->getCollectivity()->getDpo()->getMail();
309            }
310        }
311
312        $this->saveEmailNotifications($notification, $refs);
313    }
314
315    private function saveEmailNotifications(Notification $notification, $refs)
316    {
317        // Add notification with email address for the référents
318        foreach ($refs as $ref) {
319            $nu = new NotificationUser();
320            if (is_object($ref) && User::class === get_class($ref)) {
321                $nu->setMail($ref->getEmail());
322                $nu->setUser($ref);
323            } elseif (method_exists($ref, 'getEmail')) {
324                $nu->setMail($ref->getEmail());
325            } elseif (str_contains((string) $ref, '@')) {
326                // Only add it if it contains an '@'
327                $nu->setMail((string) $ref);
328            }
329
330            $nu->setToken(sha1($notification->getName() . microtime() . $nu->getMail()));
331            $nu->setNotification($notification);
332            $nu->setActive(false);
333            $nu->setSent(false);
334            $this->notificationUserRepository->persist($nu);
335        }
336    }
337
338    public static function normalizerOptions(): array
339    {
340        return [
341            AbstractObjectNormalizer::ENABLE_MAX_DEPTH           => true,
342            AbstractObjectNormalizer::CIRCULAR_REFERENCE_LIMIT   => 1,
343            AbstractObjectNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($o) {
344                return NotificationNormalizer::getObjectSimpleValue($o);
345            },
346            AbstractObjectNormalizer::MAX_DEPTH_HANDLER => function ($o) {
347                if (is_iterable($o)) {
348                    $d = [];
349                    foreach ($o as $item) {
350                        $d[] = NotificationNormalizer::getObjectSimpleValue($item);
351                    }
352
353                    return $d;
354                }
355
356                return NotificationNormalizer::getObjectSimpleValue($o);
357            },
358        ];
359    }
360}