Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
53.16% |
101 / 190 |
|
16.67% |
2 / 12 |
CRAP | |
0.00% |
0 / 1 |
NotificationEventSubscriber | |
53.16% |
101 / 190 |
|
16.67% |
2 / 12 |
284.81 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
getSubscribedEvents | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
onNeedsAIPD | |
0.00% |
0 / 24 |
|
0.00% |
0 / 1 |
12 | |||
onLateSurvey | |
95.45% |
21 / 22 |
|
0.00% |
0 / 1 |
3 | |||
onLateAction | |
96.00% |
24 / 25 |
|
0.00% |
0 / 1 |
3 | |||
onLateRequest | |
95.83% |
23 / 24 |
|
0.00% |
0 / 1 |
3 | |||
onNoLogin | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
6 | |||
saveEmailNotificationForRefOp | |
55.56% |
5 / 9 |
|
0.00% |
0 / 1 |
11.30 | |||
saveEmailNotificationForRespTrait | |
55.56% |
5 / 9 |
|
0.00% |
0 / 1 |
11.30 | |||
saveEmailNotificationForDPOs | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
90 | |||
saveEmailNotifications | |
7.14% |
1 / 14 |
|
0.00% |
0 / 1 |
34.82 | |||
normalizerOptions | |
53.33% |
8 / 15 |
|
0.00% |
0 / 1 |
3.91 |
1 | <?php |
2 | |
3 | namespace App\Domain\Notification\Subscriber; |
4 | |
5 | use App\Application\Interfaces\CollectivityRelated; |
6 | use App\Domain\Notification\Dictionary\NotificationModuleDictionary; |
7 | use App\Domain\Notification\Event\ConformiteTraitementNeedsAIPDEvent; |
8 | use App\Domain\Notification\Event\LateActionEvent; |
9 | use App\Domain\Notification\Event\LateRequestEvent; |
10 | use App\Domain\Notification\Event\LateSurveyEvent; |
11 | use App\Domain\Notification\Event\NoLoginEvent; |
12 | use App\Domain\Notification\Model\Notification; |
13 | use App\Domain\Notification\Model\NotificationUser; |
14 | use App\Domain\Notification\Serializer\NotificationNormalizer; |
15 | use App\Domain\Registry\Model\ConformiteTraitement\ConformiteTraitement; |
16 | use App\Domain\User\Dictionary\UserMoreInfoDictionary; |
17 | use App\Domain\User\Model\Collectivity; |
18 | use App\Domain\User\Model\User; |
19 | use App\Domain\User\Repository\User as UserRepository; |
20 | use App\Infrastructure\ORM\Notification\Repository\Notification as NotificationRepository; |
21 | use App\Infrastructure\ORM\Notification\Repository\NotificationUser as NotificationUserRepository; |
22 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
23 | use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; |
24 | use Symfony\Contracts\Translation\TranslatorInterface; |
25 | |
26 | /** |
27 | * This event subscriber creates notification for things that are trigerred by a cron job. |
28 | */ |
29 | class 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 | } |