From 159d783ed7eecce3fc28fcd79effe66500672d43 Mon Sep 17 00:00:00 2001 From: DevEnv nis2-agile Date: Mon, 9 Mar 2026 10:20:43 +0100 Subject: [PATCH] [FIX] ServicesController: allineamento colonne DB reali (risk_level, contained_at, owner_name, company_name, category compliance_controls) --- .../controllers/ServicesController.php | 115 ++++++++++-------- 1 file changed, 66 insertions(+), 49 deletions(-) diff --git a/application/controllers/ServicesController.php b/application/controllers/ServicesController.php index 727ef2b..20c8326 100644 --- a/application/controllers/ServicesController.php +++ b/application/controllers/ServicesController.php @@ -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( 'SELECT COUNT(*) as total, - SUM(CASE WHEN status = "open" 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 status = "mitigated" THEN 1 ELSE 0 END) as mitigated + SUM(CASE WHEN status NOT IN ("closed") THEN 1 ELSE 0 END) as open_count, + SUM(CASE WHEN inherent_risk_score >= 9 AND status NOT IN ("closed") THEN 1 ELSE 0 END) as high_critical, + SUM(CASE WHEN status = "monitored" THEN 1 ELSE 0 END) as mitigated FROM risks WHERE organization_id = ?', [$orgId] ); @@ -870,9 +870,9 @@ class ServicesController extends BaseController $incidentStats = Database::fetchOne( 'SELECT 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 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 = ?', [$orgId] ); @@ -944,10 +944,18 @@ class ServicesController extends BaseController $params = [$orgId]; 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'])); - $placeholders = implode(',', array_fill(0, count($levels), '?')); - $where .= " AND r.risk_level IN ({$placeholders})"; - $params = array_merge($params, $levels); + $conditions = []; + foreach ($levels as $lv) { + $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'])) { @@ -969,8 +977,12 @@ class ServicesController extends BaseController $risks = Database::fetchAll( "SELECT r.id, r.title, r.description, r.category, r.likelihood, - r.impact, r.inherent_risk_score, r.risk_level, r.status, - r.treatment_plan, r.owner_name, r.residual_risk_score, + r.impact, r.inherent_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 FROM risks r WHERE {$where} @@ -1035,12 +1047,10 @@ class ServicesController extends BaseController $incidents = Database::fetchAll( "SELECT id, title, classification, severity, status, is_significant, - detected_at, contained_at, resolved_at, - early_warning_sent, early_warning_sent_at, - notification_sent, notification_sent_at, - final_report_sent, final_report_sent_at, - notification_deadline, final_report_deadline, - affected_systems, impact_description, + detected_at, closed_at, + early_warning_sent_at, notification_sent_at, final_report_sent_at, + early_warning_due, notification_due, final_report_due, + affected_services, root_cause, created_at, updated_at FROM incidents WHERE {$where} @@ -1057,20 +1067,20 @@ class ServicesController extends BaseController 'early_warning_24h' => [ 'required' => (bool)$inc['is_significant'], 'deadline' => date('c', $detectedTs + 86400), - 'sent' => (bool)$inc['early_warning_sent'], - 'overdue' => !$inc['early_warning_sent'] && $now > $detectedTs + 86400, + 'sent' => $inc['early_warning_sent_at'] !== null, + 'overdue' => !$inc['early_warning_sent_at'] && $now > $detectedTs + 86400, ], 'notification_72h' => [ 'required' => (bool)$inc['is_significant'], 'deadline' => date('c', $detectedTs + 259200), - 'sent' => (bool)$inc['notification_sent'], - 'overdue' => !$inc['notification_sent'] && $now > $detectedTs + 259200, + 'sent' => $inc['notification_sent_at'] !== null, + 'overdue' => !$inc['notification_sent_at'] && $now > $detectedTs + 259200, ], 'final_report_30d' => [ 'required' => (bool)$inc['is_significant'], 'deadline' => date('c', $detectedTs + 2592000), - 'sent' => (bool)$inc['final_report_sent'], - 'overdue' => !$inc['final_report_sent'] && $now > $detectedTs + 2592000, + 'sent' => $inc['final_report_sent_at'] !== null, + 'overdue' => !$inc['final_report_sent_at'] && $now > $detectedTs + 2592000, ], ]; } @@ -1099,28 +1109,28 @@ class ServicesController extends BaseController $orgId = $this->currentOrgId; $controls = Database::fetchAll( - 'SELECT id, control_code, title, category, status, - implementation_notes, due_date, updated_at + 'SELECT id, control_code, title, framework, status, + implementation_percentage, evidence_description, next_review_date, updated_at FROM compliance_controls WHERE organization_id = ? - ORDER BY category, control_code', + ORDER BY framework, control_code', [$orgId] ); - // Raggruppa per categoria + // Raggruppa per framework $byCategory = []; foreach ($controls as $ctrl) { - $cat = $ctrl['category'] ?? 'uncategorized'; + $cat = $ctrl['framework'] ?? 'nis2'; if (!isset($byCategory[$cat])) { $byCategory[$cat] = [ 'category' => $cat, '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]['stats']['total']++; - $s = $ctrl['status'] ?? 'not_applicable'; + $s = $ctrl['status'] ?? 'not_started'; if (isset($byCategory[$cat]['stats'][$s])) { $byCategory[$cat]['stats'][$s]++; } @@ -1129,25 +1139,26 @@ class ServicesController extends BaseController // Score per categoria foreach ($byCategory as &$cat) { $t = $cat['stats']['total']; - $i = $cat['stats']['implemented']; - $p = $cat['stats']['partial']; + $i = $cat['stats']['implemented'] + ($cat['stats']['verified'] ?? 0); + $p = $cat['stats']['in_progress'] ?? 0; $cat['score'] = $t > 0 ? round((($i + $p * 0.5) / $t) * 100) : 0; } unset($cat); $totals = [ - 'total' => count($controls), - 'implemented' => 0, - 'partial' => 0, - 'planned' => 0, - 'not_applicable' => 0, + 'total' => count($controls), + 'implemented' => 0, + 'verified' => 0, + 'in_progress' => 0, + 'not_started' => 0, ]; foreach ($controls as $ctrl) { - $s = $ctrl['status'] ?? 'not_applicable'; + $s = $ctrl['status'] ?? 'not_started'; if (isset($totals[$s])) $totals[$s]++; } + $done = $totals['implemented'] + $totals['verified']; $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; $this->jsonSuccess([ @@ -1191,7 +1202,7 @@ class ServicesController extends BaseController $assets = Database::fetchAll( "SELECT id, name, asset_type, criticality, status, - owner_name, location, ip_address, description, + owner_user_id, location, ip_address, description, dependencies, created_at FROM assets WHERE {$where} @@ -1222,10 +1233,17 @@ class ServicesController extends BaseController $params = [$orgId]; if (!empty($_GET['risk_level'])) { + // risk_score: 0-100, mappa high=>=60, critical=>=80 $levels = array_filter(explode(',', $_GET['risk_level'])); - $ph = implode(',', array_fill(0, count($levels), '?')); - $where .= " AND s.risk_level IN ({$ph})"; - $params = array_merge($params, $levels); + $conditions = []; + foreach ($levels as $lv) { + $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'])) { @@ -1234,21 +1252,20 @@ class ServicesController extends BaseController } $suppliers = Database::fetchAll( - "SELECT s.id, s.company_name, s.category, s.risk_level, s.status, - s.last_assessment_date, s.assessment_score, s.contact_email, - s.services_provided, s.critical_dependency, + "SELECT s.id, s.name, s.service_type, s.criticality, s.risk_score, s.status, + s.last_assessment_date, s.contact_email, s.created_at, s.updated_at FROM suppliers s 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 ); $stats = Database::fetchOne( "SELECT 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 critical_dependency = 1 AND deleted_at IS NULL THEN 1 ELSE 0 END) as critical_deps, + SUM(CASE WHEN risk_score >= 60 AND deleted_at IS NULL THEN 1 ELSE 0 END) as high_risk, + 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 FROM suppliers WHERE organization_id = ?", [$orgId]