<?php declare(strict_types = 0); /* ** Copyright (C) 2001-2025 Zabbix SIA ** ** This program is free software: you can redistribute it and/or modify it under the terms of ** the GNU Affero General Public License as published by the Free Software Foundation, version 3. ** ** 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 Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License along with this program. ** If not, see <https://www.gnu.org/licenses/>. **/ class CControllerAvailabilityReportList extends CController { protected function init(): void { $this->disableCsrfValidation(); } protected function checkInput(): bool { $fields = [ 'mode' => 'in '.AVAILABILITY_REPORT_BY_HOST.','.AVAILABILITY_REPORT_BY_TEMPLATE, 'filter_template_groups' => 'array_db hosts_groups.groupid', 'filter_templates' => 'array_db hosts.hostid', 'filter_triggers' => 'array_db triggers.triggerid', 'filter_host_groups' => 'array_db hosts_groups.groupid', 'filter_hosts' => 'array_db hosts.hostid', 'filter_set'=> 'in 1', 'filter_rst' => 'in 1', 'from' => 'range_time', 'to' => 'range_time', 'page' => 'ge 1' ]; $ret = $this->validateInput($fields) && $this->validateTimeSelectorPeriod(); if (!$ret) { $this->setResponse(new CControllerResponseFatal()); } return $ret; } protected function checkPermissions(): bool { return $this->checkAccess(CRoleHelper::UI_REPORTS_AVAILABILITY_REPORT); } protected function doAction(): void { $report_mode = $this->getInput('mode', CProfile::get('web.availabilityreport.filter.mode', AVAILABILITY_REPORT_BY_HOST) ); $prefix = 'web.availabilityreport.filter.'.$report_mode; CProfile::update('web.availabilityreport.filter.mode', $report_mode, PROFILE_TYPE_INT); if ($this->hasInput('filter_set')) { $this->updateProfiles($report_mode); } elseif ($this->hasInput('filter_rst')) { $this->deleteProfiles($report_mode); } $timeselector_options = [ 'profileIdx' => 'web.availabilityreport.filter', 'profileIdx2' => 0, 'from' => $this->hasInput('from') ? $this->getInput('from') : null, 'to' => $this->hasInput('to') ? $this->getInput('to') : null ]; updateTimeSelectorPeriod($timeselector_options); $data = [ 'timeline' => getTimeSelectorPeriod($timeselector_options), 'active_tab' => CProfile::get('web.availabilityreport.filter.active', 1), 'profileIdx' => 'web.availabilityreport.filter', 'mode' => $report_mode ]; $data['filter'] = ($report_mode == AVAILABILITY_REPORT_BY_TEMPLATE) ? [ 'template_groups' => CProfile::getArray($prefix.'.template_groups', $this->getInput('filter_template_groups', [])), 'templates' => CProfile::getArray($prefix.'.templates', $this->getInput('filter_templates', [])), 'triggers' => CProfile::getArray($prefix.'.triggers', $this->getInput('filter_hosts', [])), 'host_groups' => CProfile::getArray($prefix.'.host_groups', $this->getInput('filter_host_groups', [])) ] : [ 'host_groups' => CProfile::getArray($prefix.'.host_groups', $this->getInput('filter_host_groups', [])), 'hosts' => CProfile::getArray($prefix.'.hosts', $this->getInput('filter_hosts', [])) ]; $data['filter'] = $this->prepareDataForMultiselectFields($data['filter']); $limit = CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT) + 1; if ($report_mode == AVAILABILITY_REPORT_BY_TEMPLATE) { $template_groupids = $data['filter']['template_groups'] ? getTemplateSubGroups(array_keys($data['filter']['template_groups'])) : null; $triggers = API::Trigger()->get([ 'output' => ['description'], 'selectHosts' => ['name'], 'selectItems' => ['status'], 'triggerids' => $data['filter']['triggers'] ? array_keys($data['filter']['triggers']) : null, 'templateids' => $data['filter']['templates'] ? array_keys($data['filter']['templates']) : null, 'groupids' => $template_groupids, 'templated' => true, 'filter' => [ 'status' => TRIGGER_STATUS_ENABLED, 'flags' => [ZBX_FLAG_DISCOVERY_NORMAL] ], 'sortfield' => 'description', 'preservekeys' => true ]); if ($triggers) { foreach ($triggers as $id => $trigger) { foreach ($trigger['items'] as $item) { if ($item['status'] != ITEM_STATUS_ACTIVE) { unset($triggers[$id]); break; } } } if ($triggers) { $host_groupids = $data['filter']['host_groups'] ? getSubGroups(array_keys($data['filter']['host_groups'])) : null; $triggers = API::Trigger()->get([ 'output' => ['triggerid', 'description', 'expression', 'value'], 'selectHosts' => ['name'], 'expandDescription' => true, 'monitored' => true, 'groupids' => $host_groupids, 'filter' => ['templateid' => array_keys($triggers)], 'limit' => $limit ]); if (!$triggers) { $triggers = []; } } } } else { $host_groupids = $data['filter']['host_groups'] ? getSubGroups(array_keys($data['filter']['host_groups'])) : null; $triggers = API::Trigger()->get([ 'output' => ['triggerid', 'description', 'expression', 'value'], 'selectHosts' => ['name'], 'groupids' => $host_groupids, 'hostids' => $data['filter']['hosts'] ? array_keys($data['filter']['hosts']) : null, 'expandDescription' => true, 'monitored' => true, 'limit' => $limit ]); } foreach ($triggers as &$trigger) { $trigger['host_name'] = $trigger['hosts'][0]['name']; } unset($trigger); CArrayHelper::sort($triggers, ['host_name', 'description']); // pager $page = $this->getInput('page', 1); $view_url = (new CUrl('zabbix.php'))->setArgument('action', 'availabilityreport.list'); CPagerHelper::savePage('availabilityreport.list', $page); $data += [ 'paging' => CPagerHelper::paginate($page, $triggers, ZBX_SORT_UP, $view_url), 'can_monitor_problems' => CWebUser::checkAccess(CRoleHelper::UI_MONITORING_PROBLEMS), 'triggers' => $triggers ]; $response = new CControllerResponseData($data); $response->setTitle(_('Availability report')); $this->setResponse($response); } private function updateProfiles($report_mode): void { $prefix = 'web.availabilityreport.filter.'.$report_mode; if ($report_mode == AVAILABILITY_REPORT_BY_TEMPLATE) { CProfile::updateArray($prefix.'.template_groups', $this->getInput('filter_template_groups', []), PROFILE_TYPE_ID ); CProfile::updateArray($prefix.'.templates', $this->getInput('filter_templates', []), PROFILE_TYPE_ID); CProfile::updateArray($prefix.'.triggers', $this->getInput('filter_triggers', []), PROFILE_TYPE_ID); CProfile::updateArray($prefix.'.host_groups', $this->getInput('filter_host_groups', []), PROFILE_TYPE_ID); } else { CProfile::updateArray($prefix.'.host_groups', $this->getInput('filter_host_groups', []), PROFILE_TYPE_ID); CProfile::updateArray($prefix.'.hosts', $this->getInput('filter_hosts', []), PROFILE_TYPE_ID); } } private function deleteProfiles($report_mode): void { $prefix = 'web.availabilityreport.filter.'.$report_mode; if ($report_mode == AVAILABILITY_REPORT_BY_TEMPLATE) { CProfile::delete($prefix.'.template_groups'); CProfile::delete($prefix.'.templates'); CProfile::delete($prefix.'.triggers'); CProfile::delete($prefix.'.host_groups'); } else { CProfile::deleteIdx($prefix.'.host_groups'); CProfile::deleteIdx($prefix.'.hosts'); } } /** * Prepare data for multiselect fields. * * @param array $filter * * @return array */ private function prepareDataForMultiselectFields(array $filter): array { if (array_key_exists('template_groups', $filter)) { $template_groups = CArrayHelper::renameObjectsKeys(API::TemplateGroup()->get([ 'output' => ['groupid', 'name'], 'groupids' => $filter['template_groups'], 'preservekeys' => true ]), ['groupid' => 'id']); $prepared_data['template_groups'] = $template_groups ?: []; } if (array_key_exists('templates', $filter)) { $templates = CArrayHelper::renameObjectsKeys(API::Template()->get([ 'output' => ['templateid', 'name'], 'templateids' => $filter['templates'], 'preservekeys' => true ]), ['templateid' => 'id']); $prepared_data['templates'] = $templates ?: []; } if (array_key_exists('triggers', $filter)) { $triggers = API::Trigger()->get([ 'output' => ['triggerid', 'description'], 'triggerids' => $filter['triggers'], 'templated' => true, 'selectHosts' => ['name'], 'filter' => [ 'status' => TRIGGER_STATUS_ENABLED, 'flags' => [ZBX_FLAG_DISCOVERY_NORMAL] ], 'expandDescription' => true, 'preservekeys' => true ]); if ($triggers) { foreach ($triggers as $id => $trigger) { $prepared_data['triggers'][$id] = [ 'id' => $id, 'name' => $trigger['hosts'][0]['name'].NAME_DELIMITER.$trigger['description'] ]; } } else { $prepared_data['triggers'] = []; } } if (array_key_exists('host_groups', $filter)) { $host_groups = CArrayHelper::renameObjectsKeys(API::HostGroup()->get([ 'output' => ['groupid', 'name'], 'groupids' => $filter['host_groups'], 'with_monitored_hosts' => true, 'preservekeys' => true ]), ['groupid' => 'id']); CArrayHelper::sort($host_groups, ['name']); $prepared_data['host_groups'] = $host_groups ?: []; } if (array_key_exists('hosts', $filter)) { $hosts = CArrayHelper::renameObjectsKeys(API::Host()->get([ 'output' => ['hostid', 'name'], 'hostids' => $filter['hosts'], 'preservekeys' => true ]), ['hostid' => 'id']); CArrayHelper::sort($hosts, ['name']); $prepared_data['hosts'] = $hosts ?: []; } return $prepared_data; } }