1<?php
2/*
3** Zabbix
4** Copyright (C) 2001-2021 Zabbix SIA
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19**/
20
21
22require_once dirname(__FILE__).'/../../blocks.inc.php';
23
24class CScreenHostTriggers extends CScreenBase {
25
26	/**
27	 * Process screen.
28	 *
29	 * @return CDiv (screen inside container)
30	 */
31	public function get() {
32		$params = [
33			'groupids' => null,
34			'hostids' => null,
35			'maintenance' => null,
36			'trigger_name' => '',
37			'severity' => null,
38			'limit' => $this->screenitem['elements']
39		];
40
41		// by default triggers are sorted by date desc, do we need to override this?
42		switch ($this->screenitem['sort_triggers']) {
43			case SCREEN_SORT_TRIGGERS_DATE_DESC:
44				$params['sortfield'] = 'lastchange';
45				$params['sortorder'] = ZBX_SORT_DOWN;
46				break;
47			case SCREEN_SORT_TRIGGERS_SEVERITY_DESC:
48				$params['sortfield'] = 'severity';
49				$params['sortorder'] = ZBX_SORT_DOWN;
50				break;
51			case SCREEN_SORT_TRIGGERS_HOST_NAME_ASC:
52				// a little black magic here - there is no such field 'hostname' in 'triggers',
53				// but API has a special case for sorting by hostname
54				$params['sortfield'] = 'hostname';
55				$params['sortorder'] = ZBX_SORT_UP;
56				break;
57		}
58
59		if ($this->screenitem['resourceid'] != 0) {
60			$hosts = API::Host()->get([
61				'output' => ['name'],
62				'hostids' => [$this->screenitem['resourceid']]
63			]);
64
65			$header = (new CDiv([
66				new CTag('h4', true, _('Host issues')),
67				(new CList())->addItem([_('Host'), ':', SPACE, $hosts[0]['name']])
68			]))->addClass(ZBX_STYLE_DASHBRD_WIDGET_HEAD);
69
70			$params['hostids'] = $this->screenitem['resourceid'];
71		}
72		else {
73			$groupid = getRequest('tr_groupid', CProfile::get('web.screens.tr_groupid', 0));
74			$hostid = getRequest('tr_hostid', CProfile::get('web.screens.tr_hostid', 0));
75
76			CProfile::update('web.screens.tr_groupid', $groupid, PROFILE_TYPE_ID);
77			CProfile::update('web.screens.tr_hostid', $hostid, PROFILE_TYPE_ID);
78
79			// get groups
80			$groups = API::HostGroup()->get([
81				'output' => ['name'],
82				'monitored_hosts' => true,
83				'preservekeys' => true
84			]);
85			order_result($groups, 'name');
86
87			foreach ($groups as &$group) {
88				$group = $group['name'];
89			}
90			unset($group);
91
92			// get hsots
93			$options = [
94				'output' => ['name'],
95				'monitored_hosts' => true,
96				'preservekeys' => true
97			];
98			if ($groupid != 0) {
99				$options['groupids'] = [$groupid];
100			}
101			$hosts = API::Host()->get($options);
102			order_result($hosts, 'name');
103
104			foreach ($hosts as &$host) {
105				$host = $host['name'];
106			}
107			unset($host);
108
109			$groups = [0 => _('all')] + $groups;
110			$hosts = [0 => _('all')] + $hosts;
111
112			if (!array_key_exists($hostid, $hosts)) {
113				$hostid = 0;
114			}
115
116			if ($groupid != 0) {
117				$params['groupids'] = $groupid;
118			}
119			if ($hostid != 0) {
120				$params['hostids'] = $hostid;
121			}
122
123			$groups_cb = (new CComboBox('tr_groupid', $groupid, 'submit()', $groups))
124				->setEnabled($this->mode != SCREEN_MODE_EDIT);
125			$hosts_cb = (new CComboBox('tr_hostid', $hostid, 'submit()', $hosts))
126				->setEnabled($this->mode != SCREEN_MODE_EDIT);
127
128			$header = (new CDiv([
129				new CTag('h4', true, _('Host issues')),
130				(new CForm('get', $this->pageFile))
131					->addItem(
132						(new CList())
133							->addItem([_('Group'), '&nbsp;', $groups_cb])
134							->addItem('&nbsp;')
135							->addItem([_('Host'), '&nbsp;', $hosts_cb])
136					)
137			]))->addClass(ZBX_STYLE_DASHBRD_WIDGET_HEAD);
138		}
139
140		list($table, $info) = $this->getProblemsListTable($params,
141			(new CUrl($this->pageFile))
142				->setArgument('screenid', $this->screenid)
143				->getUrl()
144		);
145
146		$footer = (new CList())
147			->addItem($info)
148			->addItem(_s('Updated: %s', zbx_date2str(TIME_FORMAT_SECONDS)))
149			->addClass(ZBX_STYLE_DASHBRD_WIDGET_FOOT);
150
151		return $this->getOutput(new CUiWidget('hat_trstatus', [$header, $table, $footer]));
152	}
153
154	/**
155	 * Render table with host or host group problems.
156	 *
157	 * @param array   $filter                  Array of filter options.
158	 * @param int     $filter['limit']         Table rows count.
159	 * @param array   $filter['groupids']      Host group ids.
160	 * @param array   $filter['hostids']       Host ids.
161	 * @param string  $filter['sortfield']     Sort field name.
162	 * @param string  $filter['sortorder']     Sort order.
163	 * @param string  $back_url                URL used by acknowledgment page.
164	 */
165	protected function getProblemsListTable($filter, $back_url) {
166		$config = select_config();
167
168		$filter = $filter + [
169			'show' => TRIGGERS_OPTION_IN_PROBLEM,
170			'show_timeline' => 0,
171			'details' => 1,
172			'show_latest_values' => 0,
173			'sort_field' => '',
174			'sort_order' => ZBX_SORT_DOWN
175		];
176
177		$data = CScreenProblem::getData($filter, $config);
178
179		$header = [
180			'hostname' => _('Host'),
181			'severity' => _('Issue'),
182			'lastchange' => _('Last change')
183		];
184
185		if (array_key_exists('sortfield', $filter)) {
186			$sort_field = $filter['sortfield'];
187			$sort_order = ($sort_field !== 'lastchange') ? $filter['sortorder'] : ZBX_SORT_DOWN;
188
189			$header[$sort_field] = [
190				$header[$sort_field],
191				(new CDiv())->addClass(($sort_order === ZBX_SORT_DOWN) ? ZBX_STYLE_ARROW_DOWN : ZBX_STYLE_ARROW_UP)
192			];
193
194			$data = CScreenProblem::sortData($data, $config, $sort_field === 'hostname' ? 'host' : $sort_field,
195				$sort_order
196			);
197		}
198
199		$info = _n('%1$d of %3$d%2$s problem is shown', '%1$d of %3$d%2$s problems are shown',
200			min($filter['limit'], count($data['problems'])),
201			(count($data['problems']) > $config['search_limit']) ? '+' : '',
202			min($config['search_limit'], count($data['problems']))
203		);
204		$data['problems'] = array_slice($data['problems'], 0, $filter['limit'], true);
205		$data = CScreenProblem::makeData($data, $filter);
206
207		$hostids = [];
208		foreach ($data['triggers'] as $trigger) {
209			$hostids += $trigger['hosts'] ? array_fill_keys(zbx_objectValues($trigger['hosts'], 'hostid'), '') : [];
210		}
211
212		$hosts = API::Host()->get([
213			'output' => ['hostid', 'name', 'status'],
214			'hostids' => array_keys($hostids),
215			'preservekeys' => true
216		]);
217
218		$table = (new CTableInfo())->setHeader($header + [_('Age'), _('Info'), _('Ack'), _('Actions')]);
219
220		foreach ($data['problems'] as $problem) {
221			$trigger = $data['triggers'][$problem['objectid']];
222
223			// Host name with hint box.
224			$host = reset($trigger['hosts']);
225			$host = $hosts[$host['hostid']];
226			$host_name = (new CLinkAction($host['name']))->setMenuPopup(CMenuPopupHelper::getHost($host['hostid']));
227
228			// Info.
229			$info_icons = [];
230			if ($problem['r_eventid'] != 0) {
231				if ($problem['correlationid'] != 0) {
232					$info_icons[] = makeInformationIcon(
233						array_key_exists($problem['correlationid'], $data['correlations'])
234							? _s('Resolved by correlation rule "%1$s".',
235								$data['correlations'][$problem['correlationid']]['name']
236							)
237							: _('Resolved by correlation rule.')
238					);
239				}
240				elseif ($problem['userid'] != 0) {
241					$info_icons[] = makeInformationIcon(
242						array_key_exists($problem['userid'], $data['users'])
243							? _s('Resolved by user "%1$s".', getUserFullname($data['users'][$problem['userid']]))
244							: _('Resolved by inaccessible user.')
245					);
246				}
247			}
248
249			// Clock.
250			$clock = new CLink(zbx_date2str(DATE_TIME_FORMAT_SECONDS, $problem['clock']),
251				(new CUrl('zabbix.php'))
252					->setArgument('action', 'problem.view')
253					->setArgument('filter_triggerids[]', $trigger['triggerid'])
254					->setArgument('filter_set', '1')
255			);
256
257			$table->addRow([
258				$host_name,
259				(new CCol([
260					(new CLinkAction($problem['name']))
261						->setAjaxHint(
262							CHintBoxHelper::getEventList($trigger['triggerid'], $problem['eventid'], $back_url)
263						)
264				]))->addClass(getSeverityStyle($problem['severity'])),
265				$clock,
266				zbx_date2age($problem['clock']),
267				makeInformationList($info_icons),
268				(new CLink($problem['acknowledged'] ? _('Yes') : _('No'),
269					(new CUrl('zabbix.php'))
270						->setArgument('action', 'acknowledge.edit')
271						->setArgument('eventids', [$problem['eventid']])
272						->setArgument('backurl', $back_url)
273						->getUrl())
274					)
275					->addClass($problem['acknowledged'] ? ZBX_STYLE_GREEN : ZBX_STYLE_RED)
276					->addClass(ZBX_STYLE_LINK_ALT),
277				makeEventActionsIcons($problem['eventid'], $data['actions'], $data['mediatypes'], $data['users'],
278					$config
279				)
280			]);
281		}
282
283		return [$table, $info];
284	}
285}
286