From d61b7618d9c04ff90fdf8d3b584ad5976faedad9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 14 Apr 2024 15:16:36 +0200 Subject: Adding upstream version 1.3.2. Signed-off-by: Daniel Baumann --- library/Cube/Web/ActionLink.php | 103 +++++++++++++ library/Cube/Web/ActionLinks.php | 115 ++++++++++++++ library/Cube/Web/Controller.php | 297 +++++++++++++++++++++++++++++++++++++ library/Cube/Web/IdoController.php | 198 +++++++++++++++++++++++++ 4 files changed, 713 insertions(+) create mode 100644 library/Cube/Web/ActionLink.php create mode 100644 library/Cube/Web/ActionLinks.php create mode 100644 library/Cube/Web/Controller.php create mode 100644 library/Cube/Web/IdoController.php (limited to 'library/Cube/Web') diff --git a/library/Cube/Web/ActionLink.php b/library/Cube/Web/ActionLink.php new file mode 100644 index 0000000..c9ad87b --- /dev/null +++ b/library/Cube/Web/ActionLink.php @@ -0,0 +1,103 @@ +url = $url; + $this->title = $title; + $this->description = $description; + $this->icon = $icon; + } + + /** + * @return Url + */ + public function getUrl() + { + return $this->url; + } + + /** + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * @return string + */ + public function getIcon() + { + return $this->icon; + } + + /** + * Render our icon + * + * @param View $view + * @return string + */ + protected function renderIcon(View $view) + { + return $view->icon($this->getIcon()); + } + + /** + * @param View $view + * @return string + */ + public function render(View $view) + { + return sprintf( + '%s%s

%s

', + $this->getUrl(), + $this->renderIcon($view), + $view->escape($this->getTitle()), + $view->escape($this->getDescription()) + ); + } +} diff --git a/library/Cube/Web/ActionLinks.php b/library/Cube/Web/ActionLinks.php new file mode 100644 index 0000000..4b84fac --- /dev/null +++ b/library/Cube/Web/ActionLinks.php @@ -0,0 +1,115 @@ +prepareActionLinks($cube, $view); + } catch (Exception $e) { + $html[] = self::renderErrorItem($e, $view); + } + + foreach ($hook->getActionLinks()->getLinks() as $link) { + $html[] = '
  • ' . $link->render($view) . '
  • '; + } + } + + if (empty($html)) { + $html[] = self::renderErrorItem( + $view->translate('No action links have been provided for this cube'), + $view + ); + } + + return implode("\n", $html) . "\n"; + } + + /** + * @param Exception|string $error + * @param View $view + * @return string + */ + private static function renderErrorItem($error, View $view) + { + if ($error instanceof Exception) { + $error = $error->getMessage(); + } + return '
  • ' . $view->escape($error) . '
  • '; + } + + /** + * Add an ActionLink to this set of actions + * + * @param ActionLink $link + * @return $this + */ + public function add(ActionLink $link) + { + $this->links[] = $link; + return $this; + } + + /** + * @return ActionLink[] + */ + public function getLinks() + { + return $this->links; + } + + /** + * @param View $view + * + * @return string + */ + public function render(View $view) + { + $links = $this->getLinks(); + if (empty($links)) { + return ''; + } + + $html = ''; + + return $html; + } +} diff --git a/library/Cube/Web/Controller.php b/library/Cube/Web/Controller.php new file mode 100644 index 0000000..028a744 --- /dev/null +++ b/library/Cube/Web/Controller.php @@ -0,0 +1,297 @@ +filter === null) { + $this->filter = QueryString::parse((string) $this->params); + } + + return $this->filter; + } + + public function detailsAction(): void + { + $cube = $this->prepareCube(); + $this->getTabs()->add('details', [ + 'label' => $this->translate('Cube details'), + 'url' => $this->getRequest()->getUrl() + ])->activate('details'); + + $cube->setBaseFilter($this->getFilter()); + + $this->setTitle($cube->getSlicesLabel()); + $this->view->links = IcingaDbActionsHook::renderAll($cube); + + $this->addContent( + HtmlString::create($this->view->render('/cube-details.phtml')) + ); + } + + protected function renderCube(): void + { + $cube = $this->prepareCube(); + $this->setTitle(sprintf( + $this->translate('Cube: %s'), + $cube->getPathLabel() + )); + + $this->params->shift('format'); + $showSettings = $this->params->shift('showSettings'); + + $query = $cube->innerQuery(); + $problemsOnly = (bool) $this->params->shift('problems', false); + $problemToggle = (new ProblemToggle($problemsOnly ?: null)) + ->setIdProtector([$this->getRequest(), 'protectId']) + ->on(ProblemToggle::ON_SUCCESS, function (ProblemToggle $form) { + /** @var CheckboxElement $problems */ + $problems = $form->getElement('problems'); + if (! $problems->isChecked()) { + $this->redirectNow(Url::fromRequest()->remove('problems')); + } else { + $this->redirectNow(Url::fromRequest()->setParam('problems')); + } + })->handleRequest($this->getServerRequest()); + + $this->addControl($problemToggle); + + $sortControl = SortControl::create([ + IcingaDbCube::DIMENSION_VALUE_SORT_PARAM => t('Value'), + IcingaDbCube::DIMENSION_SEVERITY_SORT_PARAM . ' desc' => t('Severity'), + ]); + + $this->params->shift($sortControl->getSortParam()); + $cube->sortBy($sortControl->getSort()); + $this->addControl($sortControl); + + $searchBar = $this->createSearchBar( + $query, + $this->preserveParams + ); + + if ($searchBar->hasBeenSent() && ! $searchBar->isValid()) { + if ($searchBar->hasBeenSubmitted()) { + $filter = $this->getFilter(); + } else { + $this->addControl($searchBar); + $this->sendMultipartUpdate(); + return; + } + } else { + $filter = $searchBar->getFilter(); + } + + if ($problemsOnly) { + $filter = Filter::all($filter, Filter::equal('state.is_problem', true)); + } + + $cube->setBaseFilter($filter); + $cube->problemsOnly($problemsOnly); + + $this->addControl($searchBar); + + if (count($cube->listDimensions()) > 0) { + $this->view->cube = $cube; + } else { + $showSettings = true; + } + + $this->view->url = Url::fromRequest() + ->onlyWith($this->preserveParams) + ->setFilter($searchBar->getFilter()); + + if ($showSettings) { + $form = (new DimensionsForm()) + ->setUrl($this->view->url) + ->setCube($cube) + ->on(DimensionsForm::ON_SUCCESS, function ($form) { + $this->redirectNow($form->getRedirectUrl()); + }) + ->handleRequest($this->getServerRequest()); + + $this->view->form = $form; + } else { + $this->setAutorefreshInterval(15); + } + + $this->addContent( + HtmlString::create($this->view->render('/cube-index.phtml')) + ); + + if (! $searchBar->hasBeenSubmitted() && $searchBar->hasBeenSent()) { + $this->sendMultipartUpdate(); + } + } + + private function prepareCube(): IcingaDbCube + { + $cube = $this->getCube(); + $cube->chooseFacts(array_keys($cube->getAvailableFactColumns())); + + $dimensions = DimensionParams::fromString( + $this->params->shift('dimensions', '') + )->getDimensions(); + + if ($this->hasLegacyDimensionParams($dimensions)) { + $this->transformLegacyDimensionParamsAndRedirect($dimensions); + } + + $wantNull = $this->params->shift('wantNull'); + foreach ($dimensions as $dimension) { + $cube->addDimensionByName($dimension); + if ($wantNull) { + $cube->getDimension($dimension)->wantNull(); + } + + $sliceParamWithPrefix = rawurlencode($cube::SLICE_PREFIX . $dimension); + + if ($this->params->has($sliceParamWithPrefix)) { + $this->preserveParams[] = $sliceParamWithPrefix; + $cube->slice($dimension, $this->params->shift($sliceParamWithPrefix)); + } + } + + return $cube; + } + + /** + * Get whether the given dimension param is legacy dimension param + * + * @param string $dimensionParam + * + * @return bool + */ + private function isLegacyDimensionParam(string $dimensionParam): bool + { + return ! Str::startsWith($dimensionParam, CustomVariableDimension::HOST_PREFIX) + && ! Str::startsWith($dimensionParam, CustomVariableDimension::SERVICE_PREFIX); + } + + /** + * Get whether the dimensions contain legacy dimension + * + * @param array $dimensions + * + * @return bool + */ + private function hasLegacyDimensionParams(array $dimensions): bool + { + foreach ($dimensions as $dimension) { + if ($this->isLegacyDimensionParam($dimension)) { + return true; + } + } + + return false; + } + + /** + * Transform legacy dimension and slice params and redirect + * + * This adds the new prefix to params and then redirects so that the new URL contains the prefixed params + * Slices are prefixed to differ filter and slice params + * + * @param array $legacyDimensions + */ + private function transformLegacyDimensionParamsAndRedirect(array $legacyDimensions): void + { + $dimensions = []; + $slices = []; + + $dimensionPrefix = CustomVariableDimension::HOST_PREFIX; + if ($this->getRequest()->getControllerName() === 'services') { + $dimensionPrefix = CustomVariableDimension::SERVICE_PREFIX; + } + + foreach ($legacyDimensions as $param) { + $newParam = $param; + if ($this->isLegacyDimensionParam($param)) { + $newParam = $dimensionPrefix . $param; + } + + $slice = $this->params->shift($param); + if ($slice) { + $slices[IcingaDbCube::SLICE_PREFIX . $newParam] = $slice; + } + + $dimensions[] = $newParam; + } + + $this->redirectNow( + Url::fromRequest() + ->setParam('dimensions', DimensionParams::fromArray($dimensions)->getParams()) + ->addParams($slices) + ->without($legacyDimensions) + ); + } + + public function createTabs(): Tabs + { + $params = Url::fromRequest() + ->onlyWith($this->preserveParams) + ->getParams() + ->toString(); + + return $this->getTabs() + ->add('cube/hosts', [ + 'label' => $this->translate('Hosts'), + 'url' => 'cube/hosts' . ($params === '' ? '' : '?' . $params) + ]) + ->add('cube/services', [ + 'label' => $this->translate('Services'), + 'url' => 'cube/services' . ($params === '' ? '' : '?' . $params) + ]); + } +} diff --git a/library/Cube/Web/IdoController.php b/library/Cube/Web/IdoController.php new file mode 100644 index 0000000..a9feec9 --- /dev/null +++ b/library/Cube/Web/IdoController.php @@ -0,0 +1,198 @@ +prepareCube(); + + $this->getTabs()->add('details', [ + 'label' => $this->translate('Cube details'), + 'url' => $this->getRequest()->getUrl() + ])->activate('details'); + + $this->view->title = $cube->getSlicesLabel(); + + $this->view->links = ActionLinks::renderAll($cube, $this->view); + + $this->render('cube-details', null, true); + } + + protected function renderCube(): void + { + $this->params->shift('format'); + $showSettings = $this->params->shift('showSettings'); + + $cube = $this->prepareCube(); + + $this->view->title = sprintf( + $this->translate('Cube: %s'), + $cube->getPathLabel() + ); + + if (count($cube->listDimensions()) > 0) { + $this->view->cube = $cube; + } else { + $showSettings = true; + } + + $this->view->url = Url::fromRequest(); + if ($showSettings) { + $form = (new DimensionsForm()) + ->setUrl($this->view->url) + ->setCube($cube) + ->setUrl(Url::fromRequest()) + ->on(DimensionsForm::ON_SUCCESS, function ($form) { + $this->redirectNow($form->getRedirectUrl()); + }) + ->handleRequest($this->getServerRequest()); + + $this->view->form = $form; + } else { + $this->setAutorefreshInterval(15); + } + + $this->render('cube-index', null, true); + } + + private function prepareCube(): IdoCube + { + $cube = $this->getCube(); + $cube->chooseFacts(array_keys($cube->getAvailableFactColumns())); + + $vars = DimensionParams::fromString($this->params->shift('dimensions', ''))->getDimensions(); + + $resolved = $this->params->shift('resolved', false); + + if ( + ! $resolved + && Module::exists('icingadb') + && $this->hasIcingadbDimensionParams($vars) + ) { + $this->transformIcingadbDimensionParamsAndRedirect($vars); + } elseif ($resolved) { + $this->redirectNow(Url::fromRequest()->without('resolved')); + } + + $wantNull = $this->params->shift('wantNull'); + + foreach ($vars as $var) { + $cube->addDimensionByName($var); + if ($wantNull) { + $cube->getDimension($var)->wantNull(); + } + } + + foreach ($this->params->toArray() as $param) { + $cube->slice(rawurldecode($param[0]), rawurldecode($param[1])); + } + + return $cube; + } + + /** + * Get whether the dimensions contain icingadb dimension + * + * @param array $dimensions + * + * @return bool + */ + private function hasIcingadbDimensionParams(array $dimensions): bool + { + foreach ($dimensions as $dimension) { + if ( + Str::startsWith($dimension, CustomVariableDimension::HOST_PREFIX) + || Str::startsWith($dimension, CustomVariableDimension::SERVICE_PREFIX) + ) { + return true; + } + } + + return false; + } + + /** + * Transform icingadb dimension and slice params and redirect + * + * This remove the new icingadb prefix from params and remove sort, problems-only, filter params + * + * @param array $icingadbDimensions + */ + private function transformIcingadbDimensionParamsAndRedirect(array $icingadbDimensions): void + { + $dimensions = []; + $slices = []; + $toRemoveSlices = []; + + $prefix = CustomVariableDimension::HOST_PREFIX; + if ($this->getRequest()->getControllerName() === 'ido-services') { + $prefix = CustomVariableDimension::SERVICE_PREFIX; + } + + foreach ($icingadbDimensions as $param) { + $newParam = $param; + if (strpos($param, $prefix) !== false) { + $newParam = substr($param, strlen($prefix)); + } + + $slice = $this->params->shift(IcingaDbCube::SLICE_PREFIX . $param); + if ($slice) { + $slices[$newParam] = $slice; + $toRemoveSlices[] = IcingaDbCube::SLICE_PREFIX . $param; + } + + $dimensions[] = $newParam; + } + + $icingadbParams = array_merge( + $icingadbDimensions, + $toRemoveSlices, + array_keys($this->params->toArray(false)) + ); + + $this->redirectNow( + Url::fromRequest() + ->setParam('dimensions', DimensionParams::fromArray($dimensions)->getParams()) + ->addParams($slices) + ->addParams(['resolved' => true]) + ->without($icingadbParams) + ); + } + + public function createTabs(): Tabs + { + $params = Url::fromRequest()->getParams()->toString(); + + return $this->getTabs() + ->add('cube/hosts', [ + 'label' => $this->translate('Hosts'), + 'url' => 'cube/hosts' . ($params === '' ? '' : '?' . $params) + ]) + ->add('cube/services', [ + 'label' => $this->translate('Services'), + 'url' => 'cube/services' . ($params === '' ? '' : '?' . $params) + ]); + } +} -- cgit v1.2.3