diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index 1c61743..360c0a3 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -2,9 +2,9 @@ namespace Icinga\Module\Businessprocess\Controllers; +use Icinga\Date\DateFormatter; use Icinga\Module\Businessprocess\BpConfig; -use Icinga\Module\Businessprocess\State\MonitoringState; -use Icinga\Module\Businessprocess\Storage\ConfigDiff; +use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\Html\Element; use Icinga\Module\Businessprocess\Html\HtmlString; use Icinga\Module\Businessprocess\Html\HtmlTag; @@ -16,14 +16,18 @@ use Icinga\Module\Businessprocess\Renderer\Renderer; use Icinga\Module\Businessprocess\Renderer\TileRenderer; use Icinga\Module\Businessprocess\Renderer\TreeRenderer; use Icinga\Module\Businessprocess\Simulation; +use Icinga\Module\Businessprocess\State\MonitoringState; +use Icinga\Module\Businessprocess\Storage\ConfigDiff; use Icinga\Module\Businessprocess\Storage\LegacyConfigRenderer; use Icinga\Module\Businessprocess\Web\Component\ActionBar; use Icinga\Module\Businessprocess\Web\Component\RenderedProcessActionBar; use Icinga\Module\Businessprocess\Web\Component\Tabs; use Icinga\Module\Businessprocess\Web\Controller; use Icinga\Module\Businessprocess\Web\Url; +use Icinga\Util\Json; use Icinga\Web\Notification; use Icinga\Web\Widget\Tabextension\DashboardAction; +use Icinga\Web\Widget\Tabextension\OutputFormat; class ProcessController extends Controller { @@ -95,7 +99,12 @@ class ProcessController extends Controller $this->redirectNow($this->url()->with('unlocked', true)); } + $this->handleFormatRequest($bp, $node); + $this->prepareControls($bp, $renderer); + + $this->tabs()->extend(new OutputFormat()); + $missing = $bp->getMissingChildren(); if (! empty($missing)) { if (($count = count($missing)) > 10) { @@ -527,4 +536,65 @@ class ProcessController extends Controller return $tabs; } + + protected function handleFormatRequest(BpConfig $bp, BpNode $node = null) + { + $desiredContentType = $this->getRequest()->getHeader('Accept'); + if ($desiredContentType === 'application/json') { + $desiredFormat = 'json'; + } elseif ($desiredContentType === 'text/csv') { + $desiredFormat = 'csv'; + } else { + $desiredFormat = strtolower($this->params->get('format', 'html')); + } + + switch ($desiredFormat) { + case 'json': + $response = $this->getResponse(); + $response + ->setHeader('Content-Type', 'application/json') + ->setHeader('Cache-Control', 'no-store') + ->setHeader( + 'Content-Disposition', + 'inline; filename=' . $this->getRequest()->getActionName() . '.json' + ) + ->appendBody(Json::sanitize($node !== null ? $node->toArray() : $bp->toArray())) + ->sendResponse(); + exit; + case 'csv': + $csv = fopen('php://temp', 'w'); + + fputcsv($csv, ['Path', 'Name', 'State', 'Since']); + + foreach ($node !== null ? $node->toArray(null, true) : $bp->toArray(true) as $node) { + $data = [$node['path'], $node['name']]; + + if (isset($node['state'])) { + $data[] = $node['state']; + } + + if (isset($node['since'])) { + $data[] = DateFormatter::formatDateTime($node['since']); + } + + fputcsv($csv, $data); + } + + $response = $this->getResponse(); + $response + ->setHeader('Content-Type', 'text/csv') + ->setHeader('Cache-Control', 'no-store') + ->setHeader( + 'Content-Disposition', + 'attachment; filename=' . $this->getRequest()->getActionName() . '.csv' + ) + ->sendHeaders(); + + rewind($csv); + + fpassthru($csv); + + exit; + } + } } diff --git a/library/Businessprocess/BpConfig.php b/library/Businessprocess/BpConfig.php index aedcc5c..4f1bc73 100644 --- a/library/Businessprocess/BpConfig.php +++ b/library/Businessprocess/BpConfig.php @@ -837,4 +837,41 @@ class BpConfig return count($this->listBpNodes()) === 0; } + + /** + * Export the config to array + * + * @param bool $flat If false, children will be added to the array key children, else the array will be flat + * + * @return array + */ + public function toArray($flat = false) + { + $data = [ + 'name' => $this->getTitle(), + 'path' => $this->getTitle() + ]; + + $children = []; + + foreach ($this->getChildren() as $node) { + if ($flat) { + $children = array_merge($children, $node->toArray($data, $flat)); + } else { + $children[] = $node->toArray($data, $flat); + } + } + + if ($flat) { + $data = [$data]; + + if (! empty($children)) { + $data = array_merge($data, $children); + } + } else { + $data['children'] = $children; + } + + return $data; + } } diff --git a/library/Businessprocess/Node.php b/library/Businessprocess/Node.php index 7396eb9..4fc35cf 100644 --- a/library/Businessprocess/Node.php +++ b/library/Businessprocess/Node.php @@ -395,4 +395,49 @@ abstract class Node { unset($this->parents); } + + /** + * Export the node to array + * + * @param array $parent The node's parent. Used to construct the path to the node + * @param bool $flat If false, children will be added to the array key children, else the array will be flat + * + * @return array + */ + public function toArray(array $parent = null, $flat = false) + { + $data = [ + 'name' => $this->getAlias(), + 'state' => $this->getStateName(), + 'since' => $this->getLastStateChange() + ]; + + if ($parent !== null) { + $data['path'] = $parent['path'] . '!' . $this->getAlias(); + } else { + $data['path'] = $this->getAlias(); + } + + $children = []; + + foreach ($this->getChildren() as $node) { + if ($flat) { + $children = array_merge($children, $node->toArray($data, $flat)); + } else { + $children[] = $node->toArray($data, $flat); + } + } + + if ($flat) { + $data = [$data]; + + if (! empty($children)) { + $data = array_merge($data, $children); + } + } else { + $data['children'] = $children; + } + + return $data; + } }