diff options
Diffstat (limited to 'ui/widgets/geomap/actions/WidgetView.php')
-rw-r--r-- | ui/widgets/geomap/actions/WidgetView.php | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/ui/widgets/geomap/actions/WidgetView.php b/ui/widgets/geomap/actions/WidgetView.php new file mode 100644 index 00000000000..895bd55d149 --- /dev/null +++ b/ui/widgets/geomap/actions/WidgetView.php @@ -0,0 +1,296 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Geomap\Actions; + +use API, + CControllerDashboardWidgetView, + CControllerResponseData, + CGeomapCoordinatesParser, + CParser, + CProfile, + CSettingsHelper, + CSeverityHelper; + +class WidgetView extends CControllerDashboardWidgetView { + + private const NO_PROBLEMS_MARKER_COLOR = '#009900'; + + protected string $widgetid; + + /** + * Global geomap configuration. + * + * @param array + */ + protected array $geomap_config; + + protected function init(): void { + parent::init(); + + $this->addValidationRules([ + 'initial_load' => 'in 0,1', + 'widgetid' => 'db widget.widgetid', + 'unique_id' => 'required|string' + ]); + } + + protected function doAction(): void { + $this->widgetid = $this->getInput('widgetid', 0); + + $data = [ + 'name' => $this->getInput('name', $this->widget->getDefaultName()), + 'hosts' => self::convertToRFC7946($this->getHosts()), + 'user' => [ + 'debug_mode' => $this->getDebugMode() + ], + 'unique_id' => $this->getInput('unique_id') + ]; + + if ($this->getInput('initial_load', 0)) { + $this->geomap_config = self::getMapConfig(); + + $data['config'] = $this->geomap_config + $this->getMapCenter() + [ + 'filter' => $this->getUserProfileFilter(), + 'colors' => self::getSeveritySettings() + ]; + } + + $this->setResponse(new CControllerResponseData($data)); + } + + /** + * Get hosts and their properties to show on the map as markers. + */ + private function getHosts(): array { + $filter_groupids = $this->fields_values['groupids'] ? getSubGroups($this->fields_values['groupids']) : null; + + $hosts = API::Host()->get([ + 'output' => ['hostid', 'name'], + 'selectInventory' => ['location_lat', 'location_lon'], + 'groupids' => $filter_groupids, + 'hostids' => $this->fields_values['hostids'] ?: null, + 'evaltype' => $this->fields_values['evaltype'], + 'tags' => $this->fields_values['tags'], + 'filter' => [ + 'inventory_mode' => [HOST_INVENTORY_MANUAL, HOST_INVENTORY_AUTOMATIC] + ], + 'monitored_hosts' => true, + 'preservekeys' => true + ]); + + $hosts = array_filter($hosts, static function ($host) { + $lat = $host['inventory']['location_lat']; + $lng = $host['inventory']['location_lon']; + + return (is_numeric($lat) && $lat >= GEOMAP_LAT_MIN && $lat <= GEOMAP_LAT_MAX + && is_numeric($lng) && $lng >= GEOMAP_LNG_MIN && $lng <= GEOMAP_LNG_MAX); + }); + + // Get triggers. + $triggers = API::Trigger()->get([ + 'output' => [], + 'selectHosts' => ['hostid'], + 'hostids' => array_keys($hosts), + 'filter' => [ + 'value' => TRIGGER_VALUE_TRUE + ], + 'monitored' => true, + 'preservekeys' => true + ]); + + // Get problems. + $problems = API::Problem()->get([ + 'output' => ['objectid', 'severity'], + 'selectHosts' => ['hostid'], + 'objectids' => array_keys($triggers) + ]); + + // Group problems by hosts. + $problems_by_host = []; + foreach ($problems as $problem) { + foreach ($triggers[$problem['objectid']]['hosts'] as $trigger_host) { + if (!array_key_exists($trigger_host['hostid'], $problems_by_host)) { + $problems_by_host[$trigger_host['hostid']] = [ + TRIGGER_SEVERITY_DISASTER => 0, + TRIGGER_SEVERITY_HIGH => 0, + TRIGGER_SEVERITY_AVERAGE => 0, + TRIGGER_SEVERITY_WARNING => 0, + TRIGGER_SEVERITY_INFORMATION => 0, + TRIGGER_SEVERITY_NOT_CLASSIFIED => 0 + ]; + } + + $problems_by_host[$trigger_host['hostid']][$problem['severity']]++; + } + } + + // Filter hosts by severity filter. + $severity_filter = CProfile::get('web.dashboard.widget.geomap.severity_filter', '', $this->widgetid); + $severity_filter = ($severity_filter !== '') ? array_flip(explode(',', $severity_filter)) : []; + + if ($severity_filter && count($severity_filter) != 7) { + $hosts = array_filter($hosts, static function ($host) use ($severity_filter, $problems_by_host) { + return array_key_exists($host['hostid'], $problems_by_host) + ? (bool) array_intersect_key(array_filter($problems_by_host[$host['hostid']]), $severity_filter) + : array_key_exists(-1, $severity_filter); + }); + } + + $result_hosts = []; + foreach ($hosts as $host) { + $problems = array_key_exists($host['hostid'], $problems_by_host) + ? $problems_by_host[$host['hostid']] + : [ + TRIGGER_SEVERITY_DISASTER => 0, + TRIGGER_SEVERITY_HIGH => 0, + TRIGGER_SEVERITY_AVERAGE => 0, + TRIGGER_SEVERITY_WARNING => 0, + TRIGGER_SEVERITY_INFORMATION => 0, + TRIGGER_SEVERITY_NOT_CLASSIFIED => 0 + ]; + + $result_hosts[] = $host + ['problems' => $problems]; + } + + return $result_hosts; + } + + /** + * Get initial map center point, zoom level and coordinates to center when clicking on navigate home button. + */ + private function getMapCenter(): array { + $geoloc_parser = new CGeomapCoordinatesParser(); + $home_coords = []; + $center = []; + + $user_default_view = CProfile::get('web.dashboard.widget.geomap.default_view', '', $this->widgetid); + if ($user_default_view !== '' && $geoloc_parser->parse($user_default_view) == CParser::PARSE_SUCCESS) { + $home_coords['default'] = true; + $center = $geoloc_parser->result; + $center['zoom'] = min($this->geomap_config['max_zoom'], $center['zoom']); + } + + if (array_key_exists('default_view', $this->fields_values) + && $this->fields_values['default_view'] !== '' + && $geoloc_parser->parse($this->fields_values['default_view']) == CParser::PARSE_SUCCESS) { + $initial_view = $geoloc_parser->result; + + if (array_key_exists('zoom', $initial_view)) { + $initial_view['zoom'] = min($this->geomap_config['max_zoom'], $initial_view['zoom']); + } + else { + $initial_view['zoom'] = ceil($this->geomap_config['max_zoom'] / 2); + } + + $home_coords['initial'] = $initial_view; + if (!$center) { + $center = $home_coords['initial']; + } + } + + $defaults = [ + 'latitude' => 0, + 'longitude' => 0, + 'zoom' => 1 + ]; + + return [ + 'center' => $center ?: $defaults, + 'home_coords' => $home_coords + ]; + } + + private function getUserProfileFilter(): array { + return [ + 'severity' => CProfile::get('web.dashboard.widget.geomap.severity_filter', [], $this->widgetid) + ]; + } + + /** + * Get global map configuration. + */ + private static function getMapConfig(): array { + if (CSettingsHelper::get(CSettingsHelper::GEOMAPS_TILE_PROVIDER) === '') { + return [ + 'tile_url' => CSettingsHelper::get(CSettingsHelper::GEOMAPS_TILE_URL), + 'max_zoom' => CSettingsHelper::get(CSettingsHelper::GEOMAPS_MAX_ZOOM), + 'attribution' => CSettingsHelper::get(CSettingsHelper::GEOMAPS_ATTRIBUTION) + ]; + } + + $tile_provider = getTileProviders()[CSettingsHelper::get(CSettingsHelper::GEOMAPS_TILE_PROVIDER)]; + + return [ + 'tile_url' => $tile_provider['geomaps_tile_url'], + 'max_zoom' => $tile_provider['geomaps_max_zoom'], + 'attribution' => $tile_provider['geomaps_attribution'] + ]; + } + + /** + * Create an array of problem severity colors. + */ + private static function getSeveritySettings(): array { + $severity_config = [ + -1 => self::NO_PROBLEMS_MARKER_COLOR + ]; + + for ($severity = TRIGGER_SEVERITY_NOT_CLASSIFIED; $severity < TRIGGER_SEVERITY_COUNT; $severity++) { + $severity_config[$severity] = '#'.CSeverityHelper::getColor($severity); + } + + return $severity_config; + } + + /** + * Convert array of hosts to valid GeoJSON (RFC7946) object. + */ + private static function convertToRFC7946(array $hosts) : array { + $geo_json = []; + + foreach ($hosts as $host) { + $problems = array_filter($host['problems']); + $severities = array_keys($problems); + $top_severity = reset($severities); + + $geo_json[] = [ + 'type' => 'Feature', + 'geometry' => [ + 'type' => 'Point', + 'coordinates' => [ + $host['inventory']['location_lon'], + $host['inventory']['location_lat'], + 0 + ] + ], + 'properties' => [ + 'hostid' => $host['hostid'], + 'name' => $host['name'], + 'severity' => ($top_severity === false) ? -1 : $top_severity, + 'problems' => $problems + ] + ]; + } + + return $geo_json; + } +} |