* (scripts/ NON e bind-mountato nel container: copiare in public/ per l'esecuzione, * oppure eseguire via CLI host con il giusto include path). * * Sorgente domande: docs/supplier-portal/template-nis2-base.questions.json (26 domande, * mappate alle misure ACN GV.SC, Allegato 2 Det. 164179/2025). * * Idempotente: se esiste gia un template is_default con name "NIS2 base" per l'org, * non duplica (verifica per nome) e salta le domande gia presenti (per question_code). */ $ROOT = '/var/www/nis2-agile'; require $ROOT . '/application/config/env.php'; require $ROOT . '/application/config/config.php'; require $ROOT . '/application/config/database.php'; $orgId = (int) ($argv[1] ?? 0); if ($orgId <= 0) { fwrite(STDERR, "ERRORE: org_id mancante. Uso: php seed_supplier_template.php \n"); exit(1); } $org = Database::fetchOne('SELECT id, name FROM organizations WHERE id = ?', [$orgId]); if (!$org) { fwrite(STDERR, "ERRORE: organizzazione {$orgId} non trovata.\n"); exit(1); } $jsonPath = $ROOT . '/docs/supplier-portal/template-nis2-base.questions.json'; if (!is_file($jsonPath)) { fwrite(STDERR, "ERRORE: file domande non trovato: {$jsonPath}\n"); exit(1); } $data = json_decode((string) file_get_contents($jsonPath), true); $questions = $data['questions'] ?? []; if (empty($questions)) { fwrite(STDERR, "ERRORE: nessuna domanda nel JSON.\n"); exit(1); } // 1. Template (idempotente per nome) $tplName = 'NIS2 base - Sicurezza catena di fornitura'; $tpl = Database::fetchOne( 'SELECT id FROM questionnaire_templates WHERE organization_id = ? AND name = ?', [$orgId, $tplName] ); if ($tpl) { $tplId = (int) $tpl['id']; echo "Template gia presente (id={$tplId}) per org {$orgId} ({$org['name']}).\n"; } else { $tplId = Database::insert('questionnaire_templates', [ 'organization_id' => $orgId, 'category_id' => null, 'name' => $tplName, 'description' => 'Template predefinito mappato alle misure ACN GV.SC (Allegato 2, Det. 164179/2025) e Art. 21.2(d)/21.3 Dir. (UE) 2022/2555. 26 domande, scoring per-vulnerabilita.', 'current_version' => '1.0', 'status' => 'active', 'pass_threshold' => 70, 'is_default' => 1, 'created_by' => null, ]); echo "Template creato (id={$tplId}) per org {$orgId} ({$org['name']}).\n"; } // 2. Domande (idempotente per question_code) $inserted = 0; $skipped = 0; foreach ($questions as $q) { $code = $q['code'] ?? null; if ($code === null) { continue; } $exists = Database::fetchOne( 'SELECT id FROM questionnaire_questions WHERE template_id = ? AND question_code = ?', [$tplId, $code] ); if ($exists) { $skipped++; continue; } Database::insert('questionnaire_questions', [ 'template_id' => $tplId, 'organization_id' => $orgId, 'question_code' => $code, 'question_text' => $q['text'] ?? '', 'question_type' => $q['type'] ?? 'yes_no_partial', 'options' => isset($q['options']) && $q['options'] !== null ? json_encode($q['options'], JSON_UNESCAPED_UNICODE) : null, 'weight' => (float) ($q['weight'] ?? 1), 'is_required' => !empty($q['required']) ? 1 : 0, 'order_index' => (int) ($q['order_index'] ?? 0), 'nis2_ref' => $q['nis2_ref'] ?? null, 'vuln_flag' => $q['vuln_flag'] ?? null, 'high_criticality_only' => !empty($q['high_criticality_only']) ? 1 : 0, ]); $inserted++; } $total = Database::fetchOne('SELECT COUNT(*) AS n FROM questionnaire_questions WHERE template_id = ?', [$tplId]); echo "Domande: inserite={$inserted}, gia presenti={$skipped}, totale nel template={$total['n']}.\n"; echo "OK.\n";