[FEAT] Rischi #500 fase 2 backend: endpoint /api/risks/derived (rischi dai requisiti LEX&ISO, codifica RSK-<misura>Com.N)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-07-27 13:41:11 +02:00
co-authored by Claude Opus 4.8
parent 7c711b727a
commit 571e151305
3 changed files with 71 additions and 1 deletions
@@ -48,6 +48,75 @@ class RiskController extends BaseController
$this->jsonPaginated($risks, $total, $pagination['page'], $pagination['per_page']);
}
/**
* GET /api/risks/derived
*
* Ticket #500 (fase 2, punti 1-2-3): elenco dei rischi DERIVATO dai requisiti
* del framework LEX&ISO (Determinazione ACN n. 164179 del 14 aprile 2025).
* Ogni requisito del catalogo diventa un rischio con codifica
* RSK-<misura>Com.<N> (es. requisito "comma 1." della misura GV.OC-04 ->
* RSK-GV.OC-04Com.1). Read-only: NON scrive nulla e NON tocca la tabella `risks`.
* La valutazione per-org (stato/valutazione) proviene da org_requisito_state (mig.047).
*/
public function derivedList(): void
{
$this->requireOrgAccess();
$orgId = $this->getCurrentOrgId();
$row = Database::fetchOne('SELECT entity_type FROM organizations WHERE id = ?', [$orgId]);
$orgClass = $row['entity_type'] ?? null; // essential | important | not_applicable
$rows = Database::fetchAll(
"SELECT q.id AS requisito_id, q.n, q.misura_code, q.requisito_code,
q.requisito_descr, q.applies_important, q.applies_essential,
m.misura_descr, m.nist_code, m.area_politica, m.ord,
s.stato, s.valutazione_rischio, s.note
FROM cfg_nis2_requisiti q
JOIN cfg_nis2_misure m ON m.misura_code = q.misura_code
LEFT JOIN org_requisito_state s
ON s.requisito_id = q.id AND s.organization_id = ?
ORDER BY m.ord ASC, q.n ASC, q.id ASC",
[$orgId]
);
$risks = [];
foreach ($rows as $q) {
// requisito_code es. "comma 1." -> N=1 ; fallback: slug alfanumerico del codice
$commaN = null;
if (preg_match('/(\d+)/', (string) $q['requisito_code'], $mm)) {
$commaN = (int) $mm[1];
}
$suffix = $commaN !== null
? 'Com.' . $commaN
: preg_replace('/[^A-Za-z0-9]+/', '', (string) $q['requisito_code']);
$risks[] = [
'risk_code' => 'RSK-' . $q['misura_code'] . $suffix,
'requisito_id' => (int) $q['requisito_id'],
'misura_code' => $q['misura_code'],
'misura_descr' => $q['misura_descr'],
'nist_code' => $q['nist_code'],
'area_politica' => $q['area_politica'],
'requisito_code' => $q['requisito_code'],
'comma' => $commaN,
'requisito_descr' => $q['requisito_descr'],
'applies_important' => (int) $q['applies_important'],
'applies_essential' => (int) $q['applies_essential'],
'stato' => $q['stato'] ?? 'da_valutare',
'valutazione_rischio' => $q['valutazione_rischio'] ?? null,
'note' => $q['note'] ?? null,
];
}
$this->jsonSuccess([
'org_class' => $orgClass,
'risks' => $risks,
'total' => count($risks),
'readonly' => true,
'source' => 'Determinazione ACN n. 164179 del 14 aprile 2025',
]);
}
/**
* POST /api/risks/create
*/