[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(
'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]