Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 225 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
ViolationGenerator | |
0.00% |
0 / 225 |
|
0.00% |
0 / 5 |
1122 | |
0.00% |
0 / 1 |
addGlobalOverview | |
0.00% |
0 / 58 |
|
0.00% |
0 / 1 |
210 | |||
addSyntheticView | |
0.00% |
0 / 22 |
|
0.00% |
0 / 1 |
12 | |||
addDetailedView | |
0.00% |
0 / 108 |
|
0.00% |
0 / 1 |
30 | |||
translateWithDictionary | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 | |||
AnnexeList | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
56 |
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\Reporting\Generator\Word; |
25 | |
26 | use App\Domain\Registry\Dictionary\ViolationCauseDictionary; |
27 | use App\Domain\Registry\Dictionary\ViolationCommunicationDictionary; |
28 | use App\Domain\Registry\Dictionary\ViolationConcernedDataDictionary; |
29 | use App\Domain\Registry\Dictionary\ViolationConcernedPeopleDictionary; |
30 | use App\Domain\Registry\Dictionary\ViolationGravityDictionary; |
31 | use App\Domain\Registry\Dictionary\ViolationImpactDictionary; |
32 | use App\Domain\Registry\Dictionary\ViolationNatureDictionary; |
33 | use App\Domain\Registry\Dictionary\ViolationNotificationDictionary; |
34 | use App\Domain\Registry\Dictionary\ViolationOriginDictionary; |
35 | use App\Domain\Registry\Model\Violation; |
36 | use PhpOffice\PhpWord\Element\Section; |
37 | |
38 | class ViolationGenerator extends AbstractGenerator implements ImpressionGeneratorInterface |
39 | { |
40 | /** |
41 | * Global overview : Information to display for violation in overview report. |
42 | * |
43 | * @throws \Exception |
44 | */ |
45 | public function addGlobalOverview(Section $section, array $data): void |
46 | { |
47 | if ($this->collectivity) { |
48 | $collectivity = $this->collectivity; |
49 | } else { |
50 | $collectivity = $this->userProvider->getAuthenticatedUser()->getCollectivity(); |
51 | } |
52 | |
53 | $nbTotal = \count($data); |
54 | |
55 | foreach ($data as $violation) { |
56 | $cellDate = $this->getDate($violation->getDate(), 'd/m/Y'); |
57 | if ($violation->isInProgress()) { |
58 | $cellDate .= ' (Toujours en cours)'; |
59 | } |
60 | |
61 | $violationNatures = $violation->getViolationNatures(); |
62 | $violationNaturesArray = []; |
63 | foreach ($violationNatures as $violationNature) { |
64 | $violationNaturesArray[] = ViolationNatureDictionary::getNatures()[$violationNature]; |
65 | } |
66 | |
67 | $tableData[] = [ |
68 | $cellDate, |
69 | $violationNaturesArray, |
70 | ViolationCauseDictionary::getNatures()[$violation->getCause()], |
71 | ViolationGravityDictionary::getGravities()[$violation->getGravity()], |
72 | ViolationNotificationDictionary::getNotifications()[$violation->getNotification()], |
73 | ViolationCommunicationDictionary::getCommunications()[$violation->getCommunication()], |
74 | ]; |
75 | } |
76 | |
77 | $section->addTitle('Registre des violations de données', 2); |
78 | |
79 | $section->addText('Un registre des violations de données à caractère personnel est disponible et tenu à jour.'); |
80 | |
81 | if (0 === $nbTotal) { |
82 | $section->addText('À ce jour, il n’y a pas eu de violation de données à caractère personnel.'); |
83 | } else { |
84 | if (1 === $nbTotal) { |
85 | $section->addText("Il y a eu {$nbTotal} violation de données à caractère personnel."); |
86 | } else { |
87 | $section->addText("Il y a eu {$nbTotal} violations de données à caractère personnel."); |
88 | } |
89 | $violationTable = $section->addTable($this->tableStyle); |
90 | $violationTable->addRow(null, ['tblHeader' => true, 'cantsplit' => true]); |
91 | $ViolationNames = [ |
92 | ['name' => 'Date', 'width' => 1000, 'merge' => 'restart'], |
93 | ['name' => 'Nature', 'width' => 1500, 'merge' => 'restart'], |
94 | ['name' => 'Cause', 'width' => 1500, 'merge' => 'restart'], |
95 | ['name' => 'Niveau de gravité', 'width' => 1500, 'merge' => 'restart'], |
96 | ['name' => 'Notification', 'width' => 3000, 'merge' => null], |
97 | ]; |
98 | foreach ($ViolationNames as $item) { |
99 | $cell = $violationTable->addCell($item['width'], ['bgColor' => '3c8dbc', 'vMerge' => $item['merge']]); |
100 | if ('Notification' === $item['name']) { |
101 | $cell->getStyle()->setGridSpan(2); |
102 | } |
103 | $cell->addText($item['name'], $this->textHeadStyle); |
104 | } |
105 | $violationTable->addRow(null, ['tblHeader' => true, 'cantsplit' => true]); |
106 | $violationTable->addCell(1000, ['vMerge' => 'continue']); |
107 | $violationTable->addCell(1500, ['vMerge' => 'continue']); |
108 | $violationTable->addCell(1500, ['vMerge' => 'continue']); |
109 | $violationTable->addCell(1500, ['vMerge' => 'continue']); |
110 | $cell = $violationTable->addCell(1500, ['bgColor' => '3c8dbc', 'vAlign' => 'center']); |
111 | $cell->addText('CNIL', $this->textHeadStyle); |
112 | $cell = $violationTable->addCell(1500, ['bgColor' => '3c8dbc', 'vAlign' => 'center']); |
113 | $cell->addText('Concernés', $this->textHeadStyle); |
114 | |
115 | foreach ($tableData as $key => $row) { |
116 | $violationTable->addRow(null, ['cantsplit' => true]); |
117 | foreach ($row as $cellItem) { |
118 | $cell = $violationTable->addCell(0 === $key ? 1000 : 1500); |
119 | if (is_array($cellItem)) { |
120 | foreach ($cellItem as $item) { |
121 | $cell->addListItem($item, (int) null, [], [], ['spaceAfter' => 0]); |
122 | } |
123 | } else { |
124 | $cell->addText($cellItem); |
125 | } |
126 | } |
127 | } |
128 | } |
129 | } |
130 | |
131 | public function addSyntheticView(Section $section, array $data): void |
132 | { |
133 | $section->addTitle('Liste des violations', 1); |
134 | |
135 | // Aggregate data before rendering |
136 | $tableData = [ |
137 | [ |
138 | 'Date', |
139 | 'Natures', |
140 | 'Cause', |
141 | 'Niveau de gravité', |
142 | ], |
143 | ]; |
144 | |
145 | foreach ($data as $violation) { |
146 | /** @var Violation $violation */ |
147 | $cellDate = $this->getDate($violation->getDate(), 'd/m/Y'); |
148 | if ($violation->isInProgress()) { |
149 | $cellDate .= ' (Toujours en cours)'; |
150 | } |
151 | |
152 | $natures = join(', ', array_map(function ($n) { return ViolationNatureDictionary::getNatures()[$n] ?? $n; }, (array) $violation->getViolationNatures())); |
153 | $tableData[] = [ |
154 | $cellDate, |
155 | $natures, |
156 | ViolationCauseDictionary::getNatures()[$violation->getCause()], |
157 | ViolationGravityDictionary::getGravities()[$violation->getGravity()], |
158 | ]; |
159 | } |
160 | |
161 | // Rendering |
162 | $this->addTable($section, $tableData, true, self::TABLE_ORIENTATION_HORIZONTAL); |
163 | $section->addPageBreak(); |
164 | } |
165 | |
166 | public function addDetailedView(Section $section, array $data): void |
167 | { |
168 | $section->addTitle('Détail des violations', 1); |
169 | |
170 | foreach ($data as $key => $violation) { |
171 | if (0 !== $key) { |
172 | $section->addPageBreak(); |
173 | } |
174 | |
175 | $section->addTitle((string) $violation, 2); |
176 | |
177 | $cellDate = $this->getDate($violation->getDate(), 'd/m/Y'); |
178 | |
179 | $generalInformationsData = [ |
180 | [ |
181 | 'Date de la violation', |
182 | $cellDate, |
183 | ], |
184 | ]; |
185 | |
186 | // Ajouter les services si le module est actif |
187 | if ($violation->getCollectivity()->getIsServicesEnabled()) { |
188 | $generalInformationsData[] = [ |
189 | 'Service', |
190 | $violation->getService(), |
191 | ]; |
192 | } |
193 | |
194 | $natures = join(', ', array_map(function ($n) { return ViolationNatureDictionary::getNatures()[$n] ?? $n; }, (array) $violation->getViolationNatures())); |
195 | $generalInformationsData = array_merge($generalInformationsData, [ |
196 | [ |
197 | 'Violation en cours', |
198 | $violation->isInProgress() ? 'Oui' : 'Non', |
199 | ], |
200 | [ |
201 | 'Natures de la violation', |
202 | $natures, |
203 | ], |
204 | [ |
205 | 'Origine de la perte de données', |
206 | $this->translateWithDictionary(ViolationOriginDictionary::getOrigins(), $violation->getOrigins()), |
207 | ], |
208 | [ |
209 | 'Cause de la violation', |
210 | $this->translateWithDictionary(ViolationCauseDictionary::getNatures(), $violation->getCause()), |
211 | ], |
212 | [ |
213 | 'Nature des données concernées', |
214 | $this->translateWithDictionary(ViolationConcernedDataDictionary::getConcernedData(), $violation->getConcernedDataNature()), |
215 | ], |
216 | [ |
217 | 'Catégorie des personnes concernées', |
218 | $this->translateWithDictionary(ViolationConcernedPeopleDictionary::getConcernedPeople(), $violation->getConcernedPeopleCategories()), |
219 | ], |
220 | [ |
221 | 'Nombre approximatif d\'enregistrements concernés par la violation', |
222 | $violation->getNbAffectedRows(), |
223 | ], |
224 | [ |
225 | 'Nombre approximatif de personnes concernées par la violation', |
226 | $violation->getNbAffectedPersons(), |
227 | ], |
228 | ]); |
229 | |
230 | $consequenceData = [ |
231 | [ |
232 | 'Nature des impacts potentiels pour les personnes', |
233 | $this->translateWithDictionary(ViolationImpactDictionary::getImpacts(), $violation->getPotentialImpactsNature()), |
234 | ], |
235 | [ |
236 | 'Niveau de gravité', |
237 | $this->translateWithDictionary(ViolationGravityDictionary::getGravities(), $violation->getGravity()), |
238 | ], |
239 | [ |
240 | 'Communications aux personnes concernées', |
241 | $this->translateWithDictionary(ViolationCommunicationDictionary::getCommunications(), $violation->getCommunication()), |
242 | ], |
243 | [ |
244 | 'Précisions sur les communications', |
245 | $violation->getCommunicationPrecision(), |
246 | ], |
247 | [ |
248 | 'Mesures techniques et organisationnelles appliquées suite à la violation', |
249 | $violation->getAppliedMeasuresAfterViolation(), |
250 | ], |
251 | [ |
252 | 'Notification', |
253 | $this->translateWithDictionary(ViolationNotificationDictionary::getNotifications(), $violation->getNotification()), |
254 | ], |
255 | [ |
256 | 'Précisions sur les notifications', |
257 | $violation->getNotificationDetails(), |
258 | ], |
259 | [ |
260 | 'Commentaire', |
261 | $violation->getComment(), |
262 | ], |
263 | ]; |
264 | |
265 | $historyData = [ |
266 | [ |
267 | 'Date de création', |
268 | $this->getDate($violation->getCreatedAt()), |
269 | ], |
270 | [ |
271 | 'Date de modification', |
272 | $this->getDate($violation->getUpdatedAt()), |
273 | ], |
274 | [ |
275 | 'Modifié par', |
276 | $violation->getUpdatedBy(), |
277 | ], |
278 | ]; |
279 | |
280 | $section->addTitle('Informations sur la violation', 3); |
281 | $this->addTable($section, $generalInformationsData, false, self::TABLE_ORIENTATION_VERTICAL); |
282 | |
283 | $section->addTitle('Conséquences de la violation', 3); |
284 | $this->addTable($section, $consequenceData, false, self::TABLE_ORIENTATION_VERTICAL); |
285 | |
286 | $section->addTitle('Éléments associés', 3); |
287 | $this->addLinkedData($section, $violation); |
288 | |
289 | $section->addTitle('Historique', 3); |
290 | $this->addTable($section, $historyData, false, self::TABLE_ORIENTATION_VERTICAL); |
291 | } |
292 | } |
293 | |
294 | private function translateWithDictionary(array $dictionaryData = [], $value = null): array |
295 | { |
296 | if (\is_null($value)) { |
297 | return []; |
298 | } |
299 | |
300 | if (!\is_array($value)) { |
301 | return [$dictionaryData[$value]]; |
302 | } |
303 | |
304 | // Value is iterable |
305 | $translatedValues = []; |
306 | foreach ($value as $item) { |
307 | $translatedValues[] = "- {$dictionaryData[$item]}"; |
308 | } |
309 | |
310 | return $translatedValues; |
311 | } |
312 | |
313 | public function AnnexeList($section, $violations) |
314 | { |
315 | $section->addTitle('Liste des violations de données', 2); |
316 | $tableViolationAnnexeApplied = $section->addTable($this->tableStyle); |
317 | $tableViolationAnnexeApplied->addRow(null, ['tblHeader' => true, 'cantSplit' => true]); |
318 | $cell = $tableViolationAnnexeApplied->addCell(1000, $this->cellHeadStyle); |
319 | $cell->addText('Date', $this->textHeadStyle); |
320 | $cell = $tableViolationAnnexeApplied->addCell(1000, $this->cellHeadStyle); |
321 | $cell->addText('Communication aux personnes', $this->textHeadStyle); |
322 | $cell = $tableViolationAnnexeApplied->addCell(2000, $this->cellHeadStyle); |
323 | $cell->addText('Notification autorité de contrôle', $this->textHeadStyle); |
324 | $cell = $tableViolationAnnexeApplied->addCell(2000, $this->cellHeadStyle); |
325 | $cell->addText('Sous-traitants', $this->textHeadStyle); |
326 | $cell = $tableViolationAnnexeApplied->addCell(2000, $this->cellHeadStyle); |
327 | $cell->addText('Traitements associés', $this->textHeadStyle); |
328 | |
329 | /** @var Violation $line */ |
330 | foreach ($violations as $line) { |
331 | $tableViolationAnnexeApplied->addRow(null, ['cantSplit' => true]); |
332 | $cell = $tableViolationAnnexeApplied->addCell(1000); |
333 | $date = !$line->isInProgress() ? $line->getDate()->format('d/m/Y') : $line->getDate()->format('d/m/Y') . ' (En cours)'; |
334 | $cell->addText($date); |
335 | $cell = $tableViolationAnnexeApplied->addCell(1000); |
336 | $cell->addText($line->getCommunication() ? ViolationCommunicationDictionary::getCommunications()[$line->getCommunication()] : ''); |
337 | $cell = $tableViolationAnnexeApplied->addCell(2000); |
338 | $cell->addText($line->getNotification() ? ViolationNotificationDictionary::getNotifications()[$line->getNotification()] : ''); |
339 | $cell = $tableViolationAnnexeApplied->addCell(2000); |
340 | foreach ($line->getContractors() as $item) { |
341 | $cell->addListItem($item->getName(), null, [], [], ['spaceAfter' => 0]); |
342 | } |
343 | $cell = $tableViolationAnnexeApplied->addCell(2000); |
344 | foreach ($line->getTreatments() as $item) { |
345 | $cell->addListItem($item->getName(), null, [], [], ['spaceAfter' => 0]); |
346 | } |
347 | } |
348 | $section->addPageBreak(); |
349 | } |
350 | } |