[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']);
|
$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
|
* POST /api/risks/create
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -324,6 +324,7 @@ $actionMap = [
|
|||||||
// ── RiskController ──────────────────────────────
|
// ── RiskController ──────────────────────────────
|
||||||
'risks' => [
|
'risks' => [
|
||||||
'GET:list' => 'list',
|
'GET:list' => 'list',
|
||||||
|
'GET:derived' => 'derivedList', // #500 fase 2: rischi derivati dai requisiti LEX&ISO
|
||||||
'POST:create' => 'create',
|
'POST:create' => 'create',
|
||||||
'GET:{id}' => 'get',
|
'GET:{id}' => 'get',
|
||||||
'PUT:{id}' => 'update',
|
'PUT:{id}' => 'update',
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
{"version": "1.25.2", "build": "2026-07-27-v1.25.2", "date": "2026-07-27", "changelog": "Gestione Rischi - pagina semplificata: la matrice 5x5 e' ora sempre visibile sotto la tabella dei rischi (niente piu' bottone 'Matrice'); rimosse le viste 'Quantitativo (FAIR)' e 'KRI' e i relativi bottoni. Prossimo passo: i rischi verranno derivati dai requisiti LEX&ISO con codifica RSK-<misura>."}
|
{"version": "1.25.3", "build": "2026-07-27-v1.25.3", "date": "2026-07-27", "changelog": "Gestione Rischi (ticket #500 fase 2, backend): nuovo endpoint GET /api/risks/derived che deriva l'elenco dei rischi dai requisiti del framework LEX&ISO (Determinazione ACN n. 164179/2025) con codifica RSK-<misura>Com.N (es. RSK-GV.OC-04Com.1). Additivo, read-only, non tocca la tabella rischi. Prossimo passo: la pagina rischi consumera' questo elenco e verranno rimossi i bottoni 'Nuovo Rischio' e 'AI Suggerisci'."}
|
||||||
|
|||||||
Reference in New Issue
Block a user