Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
67.21% covered (warning)
67.21%
164 / 244
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
UserMetric
67.21% covered (warning)
67.21%
164 / 244
66.67% covered (warning)
66.67%
2 / 3
166.53
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 getData
65.81% covered (warning)
65.81%
154 / 234
0.00% covered (danger)
0.00%
0 / 1
170.52
 getTemplateViewName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
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\Reporting\Metrics;
25
26use App\Application\Symfony\Security\UserProvider;
27use App\Domain\Maturity\Model\Referentiel;
28use App\Domain\Registry\Calculator\Completion\ConformiteTraitementCompletion;
29use App\Domain\Registry\Dictionary\ConformiteTraitementLevelDictionary;
30use App\Domain\Registry\Dictionary\MesurementStatusDictionary;
31use App\Domain\Registry\Dictionary\RequestStateDictionary;
32use App\Domain\Registry\Model;
33use App\Domain\Registry\Repository;
34use App\Domain\Registry\Service\ConformiteOrganisationService;
35use App\Domain\Reporting\Dictionary\LogJournalSubjectDictionary;
36use App\Domain\Reporting\Repository\LogJournal;
37use App\Infrastructure\ORM\Maturity\Repository\Survey as SurveyRepository;
38use App\Infrastructure\ORM\Registry\Repository\ConformiteOrganisation\Evaluation;
39use Doctrine\Inflector\InflectorFactory;
40use Doctrine\Inflector\Language;
41use Doctrine\ORM\EntityManagerInterface;
42
43class UserMetric implements MetricInterface
44{
45    /**
46     * @var EntityManagerInterface
47     */
48    private $entityManager;
49
50    /**
51     * @var Repository\ConformiteTraitement\ConformiteTraitement
52     */
53    private $conformiteTraitementRepository;
54
55    /**
56     * @var Evaluation
57     */
58    private $evaluationRepository;
59
60    /**
61     * @var Repository\Request
62     */
63    private $requestRepository;
64
65    /**
66     * @var Repository\Treatment
67     */
68    private $treatmentRepository;
69    /**
70     * @var SurveyRepository
71     */
72    private $surveyRepository;
73
74    /**
75     * @var UserProvider
76     */
77    private $userProvider;
78
79    /**
80     * @var LogJournal
81     */
82    private $logJournalRepository;
83
84    /**
85     * @var int
86     */
87    private $userLogJounalViewLimit;
88
89    public function __construct(
90        EntityManagerInterface $entityManager,
91        Repository\ConformiteTraitement\ConformiteTraitement $conformiteTraitementRepository,
92        Repository\Request $requestRepository,
93        Repository\Treatment $treatmentRepository,
94        UserProvider $userProvider,
95        Evaluation $evaluationRepository,
96        LogJournal $logJournalRepository,
97        SurveyRepository $surveyRepository,
98        int $userLogJounalViewLimit,
99    ) {
100        $this->entityManager                  = $entityManager;
101        $this->conformiteTraitementRepository = $conformiteTraitementRepository;
102        $this->requestRepository              = $requestRepository;
103        $this->treatmentRepository            = $treatmentRepository;
104        $this->userProvider                   = $userProvider;
105        $this->evaluationRepository           = $evaluationRepository;
106        $this->logJournalRepository           = $logJournalRepository;
107        $this->surveyRepository               = $surveyRepository;
108        $this->userLogJounalViewLimit         = $userLogJounalViewLimit;
109    }
110
111    public function getData(?Referentiel $referentiel = null): array
112    {
113        $data = [
114            'conformiteOrganisation' => [
115            ],
116            'conformiteTraitement' => [
117                'data'   => [],
118                'labels' => [],
119                'colors' => [],
120            ],
121            'contractor' => [
122                'all'     => 0,
123                'clauses' => [
124                    'yes' => 0,
125                    'no'  => 0,
126                ],
127                'adoptedSecurityFeatures' => [
128                    'yes' => 0,
129                    'no'  => 0,
130                ],
131                'maintainsTreatmentRegister' => [
132                    'yes' => 0,
133                    'no'  => 0,
134                ],
135                'sendingDataOutsideEu' => [
136                    'yes' => 0,
137                    'no'  => 0,
138                ],
139            ],
140            'maturity'   => [],
141            'mesurement' => [
142                'value' => [
143                    'applied'       => 0,
144                    'notApplied'    => 0,
145                    'notApplicable' => 0,
146                    'planified'     => 0,
147                ],
148                'percent' => [
149                    'applied'       => 0,
150                    'notApplied'    => 0,
151                    'notApplicable' => 0,
152                    'planified'     => 0,
153                ],
154            ],
155            'request' => [
156                'value' => [
157                    'all'  => 0,
158                    'type' => [
159                        'correct'           => 0,
160                        'delete'            => 0,
161                        'withdrawConsent'   => 0,
162                        'access'            => 0,
163                        'dataPortability'   => 0,
164                        'limitTreatment'    => 0,
165                        'oppositeTreatment' => 0,
166                        'other'             => 0,
167                    ],
168                    'status' => [
169                        'toProcess' => 0,
170                        'processed' => 0,
171                        'denied'    => 0,
172                    ],
173                ],
174            ],
175            'treatment' => [
176                'value' => [
177                    'active'  => 0,
178                    'numeric' => 0,
179                    'data'    => [
180                        'securityAccessControl' => [
181                            'yes' => 0,
182                            'no'  => 0,
183                        ],
184                        'securityUpdate' => [
185                            'yes' => 0,
186                            'no'  => 0,
187                        ],
188                        'securitySaving' => [
189                            'yes' => 0,
190                            'no'  => 0,
191                        ],
192                        'securityTracability' => [
193                            'yes' => 0,
194                            'no'  => 0,
195                        ],
196                    ],
197                ],
198            ],
199            'violation' => [
200                'value' => [
201                    'all' => 0,
202                ],
203            ],
204            'aipd' => [
205                'toDo' => 0,
206            ],
207        ];
208
209        $collectivity = $this->userProvider->getAuthenticatedUser()->getCollectivity();
210
211        $conformiteOrganisationEvaluation = $this->evaluationRepository->findLastByOrganisation($collectivity);
212
213        $contractors = $this->entityManager->getRepository(Model\Contractor::class)->findBy(
214            ['collectivity' => $collectivity]
215        );
216
217        $data['logJournal'] = $this->logJournalRepository
218            ->findAllByCollectivityWithoutSubjects(
219                $collectivity,
220                $this->userLogJounalViewLimit,
221                [
222                    LogJournalSubjectDictionary::USER_COLLECTIVITY,
223                    LogJournalSubjectDictionary::USER_EMAIL,
224                    LogJournalSubjectDictionary::USER_FIRSTNAME,
225                    LogJournalSubjectDictionary::USER_LASTNAME,
226                    LogJournalSubjectDictionary::USER_PASSWORD,
227                    LogJournalSubjectDictionary::USER_USER,
228                    LogJournalSubjectDictionary::ADMIN_DUPLICATION,
229                ]
230            );
231
232        if ($referentiel) {
233            $maturity = $this->surveyRepository->findLatestByReferentialAndCollectivity(
234                $referentiel,
235                $collectivity
236            );
237        }
238
239        $mesurements = $this->entityManager->getRepository(Model\Mesurement::class)->findBy(
240            ['collectivity' => $collectivity]
241        );
242        $requests   = $this->requestRepository->findAllByCollectivity($collectivity);
243        $treatments = $this->entityManager->getRepository(Model\Treatment::class)->findBy(
244            ['collectivity' => $collectivity]
245        );
246        $violations = $this->entityManager->getRepository(Model\Violation::class)->findBy(
247            ['collectivity' => $collectivity]
248        );
249
250        // =========================
251        // PROCESS DATA MANIPULATION
252        // =========================
253
254        // CONTRACTOR
255        /** @var Model\Contractor $contractor */
256        foreach ($contractors as $contractor) {
257            ++$data['contractor']['all'];
258            if ($contractor->isContractualClausesVerified()) {
259                ++$data['contractor']['clauses']['yes'];
260            } else {
261                ++$data['contractor']['clauses']['no'];
262            }
263            if ($contractor->isAdoptedSecurityFeatures()) {
264                ++$data['contractor']['adoptedSecurityFeatures']['yes'];
265            } else {
266                ++$data['contractor']['adoptedSecurityFeatures']['no'];
267            }
268            if ($contractor->isMaintainsTreatmentRegister()) {
269                ++$data['contractor']['maintainsTreatmentRegister']['yes'];
270            } else {
271                ++$data['contractor']['maintainsTreatmentRegister']['no'];
272            }
273            if ($contractor->isSendingDataOutsideEu()) {
274                ++$data['contractor']['sendingDataOutsideEu']['yes'];
275            } else {
276                ++$data['contractor']['sendingDataOutsideEu']['no'];
277            }
278        }
279
280        // MATURITY
281        if (isset($maturity) && isset($maturity[0]) && null !== $maturity[0]->getReferentiel()) {
282            $data['maturity']['new']['name'] = $maturity[0]->getCreatedAt()->format('d/m/Y');
283            foreach ($maturity[0]->getMaturity() as $item) {
284                $data['maturity']['new']['data'][$item->getDomain()->getPosition()]['name']  = $item->getDomain()->getName();
285                $data['maturity']['new']['data'][$item->getDomain()->getPosition()]['score'] = $item->getScore() / 10;
286            }
287            if (isset($data['maturity']['new']['data']) && is_array($data['maturity']['new']['data'])) {
288                \ksort($data['maturity']['new']['data']);
289            }
290        }
291        if (isset($maturity) && isset($maturity[1]) && null !== $maturity[0]->getReferentiel()) {
292            $data['maturity']['old']['name'] = $maturity[1]->getCreatedAt()->format('d/m/Y');
293            foreach ($maturity[1]->getMaturity() as $item) {
294                $data['maturity']['old']['data'][$item->getDomain()->getPosition()]['name']  = $item->getDomain()->getName();
295                $data['maturity']['old']['data'][$item->getDomain()->getPosition()]['score'] = $item->getScore() / 10;
296            }
297            if (isset($data['maturity']['old']['data']) && is_array($data['maturity']['old']['data'])) {
298                \ksort($data['maturity']['old']['data']);
299            }
300        }
301
302        // MESUREMENT
303        foreach ($mesurements as $mesurement) {
304            switch ($mesurement->getStatus()) {
305                case MesurementStatusDictionary::STATUS_APPLIED:
306                    $data['mesurement']['value']['applied']++;
307                    break;
308                case MesurementStatusDictionary::STATUS_NOT_APPLIED:
309                    $data['mesurement']['value']['notApplied']++;
310                    if (!\is_null($mesurement->getPlanificationDate())) {
311                        ++$data['mesurement']['value']['planified'];
312                    }
313                    break;
314                case MesurementStatusDictionary::STATUS_NOT_APPLICABLE:
315                    $data['mesurement']['value']['notApplicable']++;
316            }
317        }
318        // Only percent if there is non zero values
319        if (0 < $data['mesurement']['value']['applied']) {
320            $data['mesurement']['percent']['applied'] = $data['mesurement']['value']['applied'] * 100 / (\count($mesurements) - $data['mesurement']['value']['notApplicable']);
321        }
322        if (0 < $data['mesurement']['value']['notApplied']) {
323            $data['mesurement']['percent']['notApplied'] = $data['mesurement']['value']['notApplied'] * 100 / (\count($mesurements) - $data['mesurement']['value']['notApplicable']);
324        }
325        if (0 < $data['mesurement']['value']['notApplicable']) {
326            $data['mesurement']['percent']['notApplicable'] = $data['mesurement']['value']['notApplicable'] * 100 / \count($mesurements);
327        }
328        if (0 < $data['mesurement']['value']['planified']) {
329            $data['mesurement']['percent']['planified'] = $data['mesurement']['value']['planified'] * 100 / (\count($mesurements) - $data['mesurement']['value']['notApplicable']);
330        }
331
332        // REQUEST
333        $data['request']['value']['all'] = \count($requests);
334        foreach ($requests as $request) {
335            // Only take under account active requests
336            if (!\is_null($request->getDeletedAt())) {
337                continue;
338            }
339
340            // Type
341            if ($request->getObject()) {
342                $inflector = InflectorFactory::createForLanguage(Language::FRENCH)->build();
343                if (isset($data['request']['value']['type'][$inflector->camelize($request->getObject())])) {
344                    ++$data['request']['value']['type'][$inflector->camelize($request->getObject())];
345                } else {
346                    $data['request']['value']['type'][$inflector->camelize($request->getObject())] = 1;
347                }
348            }
349
350            // Status
351            if (!is_null($request->getAnswer()->getDate()) && ('completed_closed' == $request->getState(RequestStateDictionary::STATE_COMPLETED_CLOSED))) {
352                ++$data['request']['value']['status']['processed'];
353            } elseif (!is_null($request->getAnswer()->getDate()) && ('denied' == $request->getState(RequestStateDictionary::STATE_DENIED))) {
354                ++$data['request']['value']['status']['denied'];
355            } else {
356                ++$data['request']['value']['status']['toProcess'];
357            }
358        }
359
360        // TREATMENT
361        foreach ($treatments as $treatment) {
362            // Only take under account active treatments
363            if (!$treatment->isActive()) {
364                continue;
365            }
366
367            ++$data['treatment']['value']['active'];
368
369            // Numeric treatment
370            if (!\is_null($treatment->getToolsString()) && strlen($treatment->getToolsString()) > 0) {
371                ++$data['treatment']['value']['numeric'];
372
373                if ($treatment->getSecurityAccessControl()->isCheck()) {
374                    ++$data['treatment']['value']['data']['securityAccessControl']['yes'];
375                } else {
376                    ++$data['treatment']['value']['data']['securityAccessControl']['no'];
377                }
378                if ($treatment->getSecurityUpdate()->isCheck()) {
379                    ++$data['treatment']['value']['data']['securityUpdate']['yes'];
380                } else {
381                    ++$data['treatment']['value']['data']['securityUpdate']['no'];
382                }
383                if ($treatment->getSecuritySaving()->isCheck()) {
384                    ++$data['treatment']['value']['data']['securitySaving']['yes'];
385                } else {
386                    ++$data['treatment']['value']['data']['securitySaving']['no'];
387                }
388                if ($treatment->getSecurityTracability()->isCheck()) {
389                    ++$data['treatment']['value']['data']['securityTracability']['yes'];
390                } else {
391                    ++$data['treatment']['value']['data']['securityTracability']['no'];
392                }
393            }
394        }
395
396        // VIOLATION
397        foreach ($violations as $violation) {
398            // Only take under account active violations
399            if (\is_null($violation->getDeletedAt())) {
400                ++$data['violation']['value']['all'];
401            }
402        }
403
404        // CONFORMITE TRAITEMENT
405        if ($collectivity->isHasModuleConformiteTraitement()) {
406            foreach (ConformiteTraitementLevelDictionary::getConformites() as $key => $label) {
407                $data['conformiteTraitement']['data'][$key] = 0;
408                $data['conformiteTraitement']['labels'][]   = $label;
409                $data['conformiteTraitement']['colors'][]   = ConformiteTraitementLevelDictionary::getRgbConformitesColorsForChartView()[$key];
410            }
411
412            $conformiteTraitements                                                                 = $this->conformiteTraitementRepository->findActiveByCollectivity($collectivity);
413            $nbTreatmentWithNoConformiteTraitements                                                = $this->treatmentRepository->countAllWithNoConformiteTraitementByCollectivity($collectivity);
414            $data['conformiteTraitement']['data'][ConformiteTraitementLevelDictionary::NON_EVALUE] = $nbTreatmentWithNoConformiteTraitements;
415
416            /** @var Model\ConformiteTraitement\ConformiteTraitement $conformiteTraitement */
417            foreach ($conformiteTraitements as $conformiteTraitement) {
418                $level = ConformiteTraitementCompletion::getConformiteTraitementLevel($conformiteTraitement);
419                ++$data['conformiteTraitement']['data'][$level];
420
421                if (
422                    $conformiteTraitement->getNeedsAipd()
423                ) {
424                    ++$data['aipd']['toDo'];
425                }
426            }
427
428            // reset data if all values equal zéro. Need to hide the chart.
429            if (empty(array_filter($data['conformiteTraitement']['data']))) {
430                $data['conformiteTraitement']['data'] = [];
431            } else {
432                $data['conformiteTraitement']['data'] = \array_values($data['conformiteTraitement']['data']);
433            }
434        }
435
436        // CONFORMITE ORGANISATION
437        if ($collectivity->isHasModuleConformiteOrganisation() && null !== $conformiteOrganisationEvaluation) {
438            $conformites = ConformiteOrganisationService::getOrderedConformites($conformiteOrganisationEvaluation);
439
440            foreach ($conformites as $conformite) {
441                $data['conformiteOrganisation'][$conformite->getProcessus()->getPosition()]['processus']  = $conformite->getProcessus()->getNom();
442                $data['conformiteOrganisation'][$conformite->getProcessus()->getPosition()]['conformite'] = $conformite->getConformite();
443            }
444        }
445
446        return $data;
447    }
448
449    public function getTemplateViewName(): string
450    {
451        return 'Reporting/Dashboard/index.html.twig';
452    }
453}