[FIX] ServicesController: allineamento colonne DB reali (risk_level, contained_at, owner_name, company_name, category compliance_controls)

This commit is contained in:
DevEnv nis2-agile 2026-03-09 10:20:43 +01:00
parent 27ec63c28d
commit 159d783ed7

View File

@ -855,13 +855,13 @@ class ServicesController extends BaseController
} }
} }
// Risk summary // Risk summary (risk_level calcolato da inherent_risk_score: >=16 critical, >=9 high)
$riskStats = Database::fetchOne( $riskStats = Database::fetchOne(
'SELECT 'SELECT
COUNT(*) as total, COUNT(*) as total,
SUM(CASE WHEN status = "open" THEN 1 ELSE 0 END) as open_count, SUM(CASE WHEN status NOT IN ("closed") THEN 1 ELSE 0 END) as open_count,
SUM(CASE WHEN risk_level IN ("high","critical") AND status = "open" THEN 1 ELSE 0 END) as high_critical, SUM(CASE WHEN inherent_risk_score >= 9 AND status NOT IN ("closed") THEN 1 ELSE 0 END) as high_critical,
SUM(CASE WHEN status = "mitigated" THEN 1 ELSE 0 END) as mitigated SUM(CASE WHEN status = "monitored" THEN 1 ELSE 0 END) as mitigated
FROM risks WHERE organization_id = ?', FROM risks WHERE organization_id = ?',
[$orgId] [$orgId]
); );
@ -870,9 +870,9 @@ class ServicesController extends BaseController
$incidentStats = Database::fetchOne( $incidentStats = Database::fetchOne(
'SELECT 'SELECT
COUNT(*) as total, COUNT(*) as total,
SUM(CASE WHEN status = "open" OR status = "investigating" THEN 1 ELSE 0 END) as open_count, SUM(CASE WHEN status NOT IN ("closed","post_mortem") THEN 1 ELSE 0 END) as open_count,
SUM(CASE WHEN is_significant = 1 THEN 1 ELSE 0 END) as significant, SUM(CASE WHEN is_significant = 1 THEN 1 ELSE 0 END) as significant,
SUM(CASE WHEN early_warning_sent = 1 THEN 1 ELSE 0 END) as notified_acn SUM(CASE WHEN early_warning_sent_at IS NOT NULL THEN 1 ELSE 0 END) as notified_acn
FROM incidents WHERE organization_id = ?', FROM incidents WHERE organization_id = ?',
[$orgId] [$orgId]
); );
@ -944,10 +944,18 @@ class ServicesController extends BaseController
$params = [$orgId]; $params = [$orgId];
if (!empty($_GET['level'])) { if (!empty($_GET['level'])) {
// risk_level è calcolato da inherent_risk_score
$levelMap = ['critical' => 16, 'high' => 9, 'medium' => 4, 'low' => 0];
$levels = array_filter(explode(',', $_GET['level'])); $levels = array_filter(explode(',', $_GET['level']));
$placeholders = implode(',', array_fill(0, count($levels), '?')); $conditions = [];
$where .= " AND r.risk_level IN ({$placeholders})"; foreach ($levels as $lv) {
$params = array_merge($params, $levels); $lv = strtolower(trim($lv));
if ($lv === 'critical') { $conditions[] = 'r.inherent_risk_score >= 16'; }
elseif ($lv === 'high') { $conditions[] = '(r.inherent_risk_score >= 9 AND r.inherent_risk_score < 16)'; }
elseif ($lv === 'medium') { $conditions[] = '(r.inherent_risk_score >= 4 AND r.inherent_risk_score < 9)'; }
elseif ($lv === 'low') { $conditions[] = 'r.inherent_risk_score < 4'; }
}
if ($conditions) $where .= ' AND ('.implode(' OR ', $conditions).')';
} }
if (!empty($_GET['area'])) { if (!empty($_GET['area'])) {
@ -969,8 +977,12 @@ class ServicesController extends BaseController
$risks = Database::fetchAll( $risks = Database::fetchAll(
"SELECT r.id, r.title, r.description, r.category, r.likelihood, "SELECT r.id, r.title, r.description, r.category, r.likelihood,
r.impact, r.inherent_risk_score, r.risk_level, r.status, r.impact, r.inherent_risk_score,
r.treatment_plan, r.owner_name, r.residual_risk_score, CASE WHEN r.inherent_risk_score >= 16 THEN 'critical'
WHEN r.inherent_risk_score >= 9 THEN 'high'
WHEN r.inherent_risk_score >= 4 THEN 'medium'
ELSE 'low' END as risk_level,
r.status, r.treatment, r.residual_risk_score,
r.created_at, r.updated_at r.created_at, r.updated_at
FROM risks r FROM risks r
WHERE {$where} WHERE {$where}
@ -1035,12 +1047,10 @@ class ServicesController extends BaseController
$incidents = Database::fetchAll( $incidents = Database::fetchAll(
"SELECT id, title, classification, severity, status, is_significant, "SELECT id, title, classification, severity, status, is_significant,
detected_at, contained_at, resolved_at, detected_at, closed_at,
early_warning_sent, early_warning_sent_at, early_warning_sent_at, notification_sent_at, final_report_sent_at,
notification_sent, notification_sent_at, early_warning_due, notification_due, final_report_due,
final_report_sent, final_report_sent_at, affected_services, root_cause,
notification_deadline, final_report_deadline,
affected_systems, impact_description,
created_at, updated_at created_at, updated_at
FROM incidents FROM incidents
WHERE {$where} WHERE {$where}
@ -1057,20 +1067,20 @@ class ServicesController extends BaseController
'early_warning_24h' => [ 'early_warning_24h' => [
'required' => (bool)$inc['is_significant'], 'required' => (bool)$inc['is_significant'],
'deadline' => date('c', $detectedTs + 86400), 'deadline' => date('c', $detectedTs + 86400),
'sent' => (bool)$inc['early_warning_sent'], 'sent' => $inc['early_warning_sent_at'] !== null,
'overdue' => !$inc['early_warning_sent'] && $now > $detectedTs + 86400, 'overdue' => !$inc['early_warning_sent_at'] && $now > $detectedTs + 86400,
], ],
'notification_72h' => [ 'notification_72h' => [
'required' => (bool)$inc['is_significant'], 'required' => (bool)$inc['is_significant'],
'deadline' => date('c', $detectedTs + 259200), 'deadline' => date('c', $detectedTs + 259200),
'sent' => (bool)$inc['notification_sent'], 'sent' => $inc['notification_sent_at'] !== null,
'overdue' => !$inc['notification_sent'] && $now > $detectedTs + 259200, 'overdue' => !$inc['notification_sent_at'] && $now > $detectedTs + 259200,
], ],
'final_report_30d' => [ 'final_report_30d' => [
'required' => (bool)$inc['is_significant'], 'required' => (bool)$inc['is_significant'],
'deadline' => date('c', $detectedTs + 2592000), 'deadline' => date('c', $detectedTs + 2592000),
'sent' => (bool)$inc['final_report_sent'], 'sent' => $inc['final_report_sent_at'] !== null,
'overdue' => !$inc['final_report_sent'] && $now > $detectedTs + 2592000, 'overdue' => !$inc['final_report_sent_at'] && $now > $detectedTs + 2592000,
], ],
]; ];
} }
@ -1099,28 +1109,28 @@ class ServicesController extends BaseController
$orgId = $this->currentOrgId; $orgId = $this->currentOrgId;
$controls = Database::fetchAll( $controls = Database::fetchAll(
'SELECT id, control_code, title, category, status, 'SELECT id, control_code, title, framework, status,
implementation_notes, due_date, updated_at implementation_percentage, evidence_description, next_review_date, updated_at
FROM compliance_controls FROM compliance_controls
WHERE organization_id = ? WHERE organization_id = ?
ORDER BY category, control_code', ORDER BY framework, control_code',
[$orgId] [$orgId]
); );
// Raggruppa per categoria // Raggruppa per framework
$byCategory = []; $byCategory = [];
foreach ($controls as $ctrl) { foreach ($controls as $ctrl) {
$cat = $ctrl['category'] ?? 'uncategorized'; $cat = $ctrl['framework'] ?? 'nis2';
if (!isset($byCategory[$cat])) { if (!isset($byCategory[$cat])) {
$byCategory[$cat] = [ $byCategory[$cat] = [
'category' => $cat, 'category' => $cat,
'controls' => [], 'controls' => [],
'stats' => ['total' => 0, 'implemented' => 0, 'partial' => 0, 'planned' => 0, 'not_applicable' => 0], 'stats' => ['total' => 0, 'implemented' => 0, 'in_progress' => 0, 'not_started' => 0, 'verified' => 0],
]; ];
} }
$byCategory[$cat]['controls'][] = $ctrl; $byCategory[$cat]['controls'][] = $ctrl;
$byCategory[$cat]['stats']['total']++; $byCategory[$cat]['stats']['total']++;
$s = $ctrl['status'] ?? 'not_applicable'; $s = $ctrl['status'] ?? 'not_started';
if (isset($byCategory[$cat]['stats'][$s])) { if (isset($byCategory[$cat]['stats'][$s])) {
$byCategory[$cat]['stats'][$s]++; $byCategory[$cat]['stats'][$s]++;
} }
@ -1129,8 +1139,8 @@ class ServicesController extends BaseController
// Score per categoria // Score per categoria
foreach ($byCategory as &$cat) { foreach ($byCategory as &$cat) {
$t = $cat['stats']['total']; $t = $cat['stats']['total'];
$i = $cat['stats']['implemented']; $i = $cat['stats']['implemented'] + ($cat['stats']['verified'] ?? 0);
$p = $cat['stats']['partial']; $p = $cat['stats']['in_progress'] ?? 0;
$cat['score'] = $t > 0 ? round((($i + $p * 0.5) / $t) * 100) : 0; $cat['score'] = $t > 0 ? round((($i + $p * 0.5) / $t) * 100) : 0;
} }
unset($cat); unset($cat);
@ -1138,16 +1148,17 @@ class ServicesController extends BaseController
$totals = [ $totals = [
'total' => count($controls), 'total' => count($controls),
'implemented' => 0, 'implemented' => 0,
'partial' => 0, 'verified' => 0,
'planned' => 0, 'in_progress' => 0,
'not_applicable' => 0, 'not_started' => 0,
]; ];
foreach ($controls as $ctrl) { foreach ($controls as $ctrl) {
$s = $ctrl['status'] ?? 'not_applicable'; $s = $ctrl['status'] ?? 'not_started';
if (isset($totals[$s])) $totals[$s]++; if (isset($totals[$s])) $totals[$s]++;
} }
$done = $totals['implemented'] + $totals['verified'];
$totals['overall_score'] = $totals['total'] > 0 $totals['overall_score'] = $totals['total'] > 0
? round((($totals['implemented'] + $totals['partial'] * 0.5) / $totals['total']) * 100) ? round((($done + $totals['in_progress'] * 0.5) / $totals['total']) * 100)
: 0; : 0;
$this->jsonSuccess([ $this->jsonSuccess([
@ -1191,7 +1202,7 @@ class ServicesController extends BaseController
$assets = Database::fetchAll( $assets = Database::fetchAll(
"SELECT id, name, asset_type, criticality, status, "SELECT id, name, asset_type, criticality, status,
owner_name, location, ip_address, description, owner_user_id, location, ip_address, description,
dependencies, created_at dependencies, created_at
FROM assets FROM assets
WHERE {$where} WHERE {$where}
@ -1222,10 +1233,17 @@ class ServicesController extends BaseController
$params = [$orgId]; $params = [$orgId];
if (!empty($_GET['risk_level'])) { if (!empty($_GET['risk_level'])) {
// risk_score: 0-100, mappa high=>=60, critical=>=80
$levels = array_filter(explode(',', $_GET['risk_level'])); $levels = array_filter(explode(',', $_GET['risk_level']));
$ph = implode(',', array_fill(0, count($levels), '?')); $conditions = [];
$where .= " AND s.risk_level IN ({$ph})"; foreach ($levels as $lv) {
$params = array_merge($params, $levels); $lv = strtolower(trim($lv));
if ($lv === 'critical') { $conditions[] = 's.risk_score >= 80'; }
elseif ($lv === 'high') { $conditions[] = '(s.risk_score >= 60 AND s.risk_score < 80)'; }
elseif ($lv === 'medium') { $conditions[] = '(s.risk_score >= 30 AND s.risk_score < 60)'; }
elseif ($lv === 'low') { $conditions[] = 's.risk_score < 30'; }
}
if ($conditions) $where .= ' AND ('.implode(' OR ', $conditions).')';
} }
if (!empty($_GET['status'])) { if (!empty($_GET['status'])) {
@ -1234,21 +1252,20 @@ class ServicesController extends BaseController
} }
$suppliers = Database::fetchAll( $suppliers = Database::fetchAll(
"SELECT s.id, s.company_name, s.category, s.risk_level, s.status, "SELECT s.id, s.name, s.service_type, s.criticality, s.risk_score, s.status,
s.last_assessment_date, s.assessment_score, s.contact_email, s.last_assessment_date, s.contact_email,
s.services_provided, s.critical_dependency,
s.created_at, s.updated_at s.created_at, s.updated_at
FROM suppliers s FROM suppliers s
WHERE {$where} WHERE {$where}
ORDER BY FIELD(s.risk_level,'critical','high','medium','low'), s.company_name", ORDER BY FIELD(s.criticality,'critical','high','medium','low'), s.risk_score DESC, s.name",
$params $params
); );
$stats = Database::fetchOne( $stats = Database::fetchOne(
"SELECT "SELECT
COUNT(*) as total, COUNT(*) as total,
SUM(CASE WHEN risk_level IN ('high','critical') AND deleted_at IS NULL THEN 1 ELSE 0 END) as high_risk, SUM(CASE WHEN risk_score >= 60 AND deleted_at IS NULL THEN 1 ELSE 0 END) as high_risk,
SUM(CASE WHEN critical_dependency = 1 AND deleted_at IS NULL THEN 1 ELSE 0 END) as critical_deps, SUM(CASE WHEN criticality IN ('critical','high') AND deleted_at IS NULL THEN 1 ELSE 0 END) as critical_deps,
SUM(CASE WHEN last_assessment_date IS NULL AND deleted_at IS NULL THEN 1 ELSE 0 END) as unassessed SUM(CASE WHEN last_assessment_date IS NULL AND deleted_at IS NULL THEN 1 ELSE 0 END) as unassessed
FROM suppliers WHERE organization_id = ?", FROM suppliers WHERE organization_id = ?",
[$orgId] [$orgId]