__('Read'), UPDATE => __('Update'), CREATE => __('Create'), PURGE => __('Delete permanently'), ]; } public static function canView(): bool { return Session::haveRight(self::$rightname, READ); } public static function canCreate(): bool { return Session::haveRight(self::$rightname, CREATE); } public static function canUpdate(): bool { return Session::haveRight(self::$rightname, UPDATE); } public static function canPurge(): bool { return Session::haveRight(self::$rightname, PURGE); } public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0): string { if ($item->getType() === 'NetworkEquipment' && self::canView()) { return __('Config History', 'netconfig') . ' (' . countElementsInTable(self::getTable(), ['networkdevices_id' => $item->getID()]) . ')'; } return ''; } public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0): bool { if ($item->getType() !== 'NetworkEquipment') return true; $configs = (new self())->find( ['networkdevices_id' => $item->getID()], 'created_at DESC' ); $twig = new TemplateRenderer(); echo $twig->render('@netconfig/config_tab.html.twig', [ 'configs' => $configs, 'can_export' => self::canView(), 'can_create' => self::canCreate() ]); return true; } public static function getLastConfigByDevice(int $networkdevices_id): ?array { $db = DBConnection::getReadConnection(); $stmt = $db->prepare("SELECT * FROM " . self::getTable() . " WHERE networkdevices_id = ? ORDER BY created_at DESC LIMIT 1"); $stmt->bind_param('i', $networkdevices_id); $stmt->execute(); return $stmt->get_result()->fetch_assoc() ?: null; } public static function saveConfig(array $data): bool { $config = new self(); $hash = hash('sha256', $data['content']); $last = self::getLastConfigByDevice($data['networkdevices_id']); if ($last && $last['config_hash'] === $hash) { return true; // Nessuna modifica rilevata } $input = [ 'networkdevices_id' => $data['networkdevices_id'], 'config_content' => Encryption::encrypt($data['content']), 'config_hash' => $hash, 'users_id' => $data['users_id'] ?? Session::getLoginUserID() ?: 0, 'is_encrypted' => 1, ]; return $config->add($input) !== false; } public function getDecryptedContent(): string { return $this->fields['is_encrypted'] ? Encryption::decrypt($this->fields['config_content']) : $this->fields['config_content']; } public function getDiffFromPrevious(): string { $last = self::getLastConfigByDevice($this->fields['networkdevices_id']); if (!$last || $last['id'] === $this->fields['id']) return ''; $prev = new self(); $prev->getFromDB($last['id']); $differ = new Differ(new HtmlOutput()); return $differ->diff($prev->getDecryptedContent(), $this->getDecryptedContent()); } // MASSIVE ACTIONS public function getSpecificMassiveActions($checkitem = null): array { $actions = parent::getSpecificMassiveActions($checkitem); if (self::canCreate()) { $actions[self::class . ':BackupNow'] = __('Force backup now', 'netconfig'); } if (self::canView()) { $actions[self::class . ':ExportSelected'] = __('Export selected', 'netconfig'); } return $actions; } public static function processMassiveActionsForOneItemtype(MassiveAction $ma, CommonDBTM $item, array $ids): void { switch ($ma->getAction()) { case self::class . ':BackupNow': foreach ($ids as $id) { // Qui puoi integrare coda RabbitMQ, webhook o chiamata diretta all'agent $ma->itemDone($item::getType(), $id, MassiveAction::ACTION_OK); } break; case self::class . ':ExportSelected': foreach ($ids as $id) { // Redirect to export script $ma->itemDone($item::getType(), $id, MassiveAction::ACTION_OK); } break; } } }