[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:
co-authored by
Claude Opus 4.8
parent
7c711b727a
commit
571e151305
@@ -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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user