requireOrgAccess(); $where = 'organization_id = ?'; $params = [$this->getCurrentOrgId()]; if ($this->hasParam('status')) { $where .= ' AND status = ?'; $params[] = $this->getParam('status'); } if ($this->hasParam('category')) { $where .= ' AND category = ?'; $params[] = $this->getParam('category'); } $policies = Database::fetchAll( "SELECT p.*, u.full_name as approved_by_name FROM policies p LEFT JOIN users u ON u.id = p.approved_by WHERE p.{$where} ORDER BY p.category, p.title", $params ); $this->jsonSuccess($policies); } public function create(): void { $this->requireOrgRole(['org_admin', 'compliance_manager']); $this->validateRequired(['title', 'category']); $policyId = Database::insert('policies', [ 'organization_id' => $this->getCurrentOrgId(), 'title' => trim($this->getParam('title')), 'category' => $this->getParam('category'), 'nis2_article' => $this->getParam('nis2_article'), 'content' => $this->getParam('content'), 'next_review_date' => $this->getParam('next_review_date'), 'ai_generated' => $this->getParam('ai_generated', 0), ]); $this->logAudit('policy_created', 'policy', $policyId); $this->jsonSuccess(['id' => $policyId], 'Policy creata', 201); } public function get(int $id): void { $this->requireOrgAccess(); $policy = Database::fetchOne( 'SELECT p.*, u.full_name as approved_by_name FROM policies p LEFT JOIN users u ON u.id = p.approved_by WHERE p.id = ? AND p.organization_id = ?', [$id, $this->getCurrentOrgId()] ); if (!$policy) { $this->jsonError('Policy non trovata', 404, 'POLICY_NOT_FOUND'); } $this->jsonSuccess($policy); } public function update(int $id): void { $this->requireOrgRole(['org_admin', 'compliance_manager']); $updates = []; foreach (['title', 'content', 'category', 'nis2_article', 'status', 'version', 'next_review_date'] as $field) { if ($this->hasParam($field)) { $updates[$field] = $this->getParam($field); } } if (!empty($updates)) { Database::update('policies', $updates, 'id = ? AND organization_id = ?', [$id, $this->getCurrentOrgId()]); $this->logAudit('policy_updated', 'policy', $id, $updates); } $this->jsonSuccess($updates, 'Policy aggiornata'); } public function delete(int $id): void { $this->requireOrgRole(['org_admin']); $deleted = Database::delete('policies', 'id = ? AND organization_id = ?', [$id, $this->getCurrentOrgId()]); if ($deleted === 0) { $this->jsonError('Policy non trovata', 404, 'POLICY_NOT_FOUND'); } $this->logAudit('policy_deleted', 'policy', $id); $this->jsonSuccess(null, 'Policy eliminata'); } public function approve(int $id): void { $this->requireOrgRole(['org_admin']); Database::update('policies', [ 'status' => 'approved', 'approved_by' => $this->getCurrentUserId(), 'approved_at' => date('Y-m-d H:i:s'), ], 'id = ? AND organization_id = ?', [$id, $this->getCurrentOrgId()]); $this->logAudit('policy_approved', 'policy', $id); $this->jsonSuccess(null, 'Policy approvata'); } public function aiGeneratePolicy(): void { $this->requireOrgRole(['org_admin', 'compliance_manager']); $this->validateRequired(['category']); $category = $this->getParam('category'); $org = Database::fetchOne('SELECT * FROM organizations WHERE id = ?', [$this->getCurrentOrgId()]); try { $aiService = new AIService(); $generated = $aiService->generatePolicy($category, $org); $aiService->logInteraction( $this->getCurrentOrgId(), $this->getCurrentUserId(), 'policy_draft', "Generate {$category} policy", substr($generated['title'] ?? '', 0, 500) ); $this->jsonSuccess($generated, 'Policy generata dall\'AI'); } catch (Throwable $e) { $this->jsonError('Errore AI: ' . $e->getMessage(), 500, 'AI_ERROR'); } } public function getTemplates(): void { $this->requireOrgAccess(); $templates = [ ['category' => 'information_security', 'title' => 'Politica di Sicurezza delle Informazioni', 'nis2_article' => '21.2.a'], ['category' => 'access_control', 'title' => 'Politica di Controllo degli Accessi', 'nis2_article' => '21.2.i'], ['category' => 'incident_response', 'title' => 'Piano di Risposta agli Incidenti', 'nis2_article' => '21.2.b'], ['category' => 'business_continuity', 'title' => 'Piano di Continuità Operativa', 'nis2_article' => '21.2.c'], ['category' => 'supply_chain', 'title' => 'Politica di Sicurezza della Supply Chain', 'nis2_article' => '21.2.d'], ['category' => 'encryption', 'title' => 'Politica sulla Crittografia', 'nis2_article' => '21.2.h'], ['category' => 'hr_security', 'title' => 'Politica di Sicurezza delle Risorse Umane', 'nis2_article' => '21.2.i'], ['category' => 'asset_management', 'title' => 'Politica di Gestione degli Asset', 'nis2_article' => '21.2.i'], ['category' => 'network_security', 'title' => 'Politica di Sicurezza della Rete', 'nis2_article' => '21.2.e'], ['category' => 'vulnerability_management', 'title' => 'Politica di Gestione delle Vulnerabilità', 'nis2_article' => '21.2.e'], ]; $this->jsonSuccess($templates); } }