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
22/**
23 * Check if user has read permissions for host groups.
24 *
25 * @param array $groupids
26 *
27 * @return bool
28 */
29function isReadableHostGroups(array $groupids) {
30	return count($groupids) == API::HostGroup()->get([
31		'countOutput' => true,
32		'groupids' => $groupids
33	]);
34}
35
36/**
37 * Check if user has write permissions for host groups.
38 *
39 * @param array $groupids
40 *
41 * @return bool
42 */
43function isWritableHostGroups(array $groupids) {
44	return count($groupids) == API::HostGroup()->get([
45		'countOutput' => true,
46		'groupids' => $groupids,
47		'editable' => true
48	]);
49}
50
51/**
52 * Returns list of child groups for host group with given name.
53 *
54 * @param string $name     Host group name.
55 */
56function getChildGroupIds($name) {
57	$parent = $name.'/';
58	$len = strlen($parent);
59
60	$groups = API::HostGroup()->get([
61		'output' => ['groupid', 'name'],
62		'search' => ['name' => $parent],
63		'startSearch' => true
64	]);
65
66	$child_groupids = [];
67	foreach ($groups as $group) {
68		if (substr($group['name'], 0, $len) === $parent) {
69			$child_groupids[] = $group['groupid'];
70		}
71	}
72
73	return $child_groupids;
74}
75
76/**
77 * Apply host group rights to all subgroups.
78 *
79 * @param string $groupid  Host group ID.
80 * @param string $name     Host group name.
81 */
82function inheritPermissions($groupid, $name) {
83	$child_groupids = getChildGroupIds($name);
84
85	if (!$child_groupids) {
86		return;
87	}
88
89	$usrgrps = API::UserGroup()->get([
90		'output' => ['usrgrpid'],
91		'selectRights' => ['id', 'permission']
92	]);
93
94	$upd_usrgrps = [];
95
96	foreach ($usrgrps as $usrgrp) {
97		$rights = zbx_toHash($usrgrp['rights'], 'id');
98
99		if (array_key_exists($groupid, $rights)) {
100			foreach ($child_groupids as $child_groupid) {
101				$rights[$child_groupid] = [
102					'id' => $child_groupid,
103					'permission' => $rights[$groupid]['permission']
104				];
105			}
106		}
107		else {
108			foreach ($child_groupids as $child_groupid) {
109				unset($rights[$child_groupid]);
110			}
111		}
112
113		$rights = array_values($rights);
114
115		if ($usrgrp['rights'] !== $rights) {
116			$upd_usrgrps[] = [
117				'usrgrpid' => $usrgrp['usrgrpid'],
118				'rights' => $rights
119			];
120		}
121	}
122
123	if ($upd_usrgrps) {
124		API::UserGroup()->update($upd_usrgrps);
125	}
126}
127
128/**
129 * Add subgroups with tag filters inherited from main host group ($groupid) to all user groups in which tag filters for
130 * particular group are created.
131 *
132 * @param string $groupid  Host group ID.
133 * @param string $name     Host group name.
134 */
135function inheritTagFilters($groupid, $name) {
136	$child_groupids = getChildGroupIds($name);
137
138	if (!$child_groupids) {
139		return;
140	}
141
142	$usrgrps = API::UserGroup()->get([
143		'output' => ['usrgrpid'],
144		'selectTagFilters' => ['groupid', 'tag', 'value']
145	]);
146
147	$upd_usrgrps = [];
148
149	foreach ($usrgrps as $usrgrp) {
150		$tag_filters = [];
151
152		foreach ($usrgrp['tag_filters'] as $tag_filter) {
153			$tag_filters[$tag_filter['groupid']][] = [
154				'tag' => $tag_filter['tag'],
155				'value' => $tag_filter['value']
156			];
157		}
158
159		if (array_key_exists($groupid, $tag_filters)) {
160			foreach ($child_groupids as $child_groupid) {
161				$tag_filters[$child_groupid] = $tag_filters[$groupid];
162			}
163		}
164		else {
165			foreach ($child_groupids as $child_groupid) {
166				unset($tag_filters[$child_groupid]);
167			}
168		}
169
170		$upd_tag_filters = [];
171
172		foreach ($tag_filters as $tag_filter_groupid => $tags) {
173			foreach ($tags as $tag) {
174				$upd_tag_filters[] = ['groupid' => (string) $tag_filter_groupid] + $tag;
175			}
176		}
177
178		if ($usrgrp['tag_filters'] !== $upd_tag_filters) {
179			$upd_usrgrps[] = [
180				'usrgrpid' => $usrgrp['usrgrpid'],
181				'tag_filters' => $upd_tag_filters
182			];
183		}
184	}
185
186	if ($upd_usrgrps) {
187		API::UserGroup()->update($upd_usrgrps);
188	}
189}
190
191/**
192 * Get sub-groups of selected host groups.
193 *
194 * @param array $groupids
195 * @param array $ms_groups  [OUT] the list of groups for multiselect
196 *
197 * @return array
198 */
199function getSubGroups(array $groupids, array &$ms_groups = null) {
200	$db_groups = $groupids
201		? API::HostGroup()->get([
202			'output' => ['groupid', 'name'],
203			'groupids' => $groupids,
204			'preservekeys' => true
205		])
206		: [];
207
208	if ($ms_groups !== null) {
209		$ms_groups = CArrayHelper::renameObjectsKeys($db_groups, ['groupid' => 'id']);
210	}
211
212	$db_groups_names = [];
213
214	foreach ($db_groups as $db_group) {
215		$db_groups_names[] = $db_group['name'].'/';
216	}
217
218	if ($db_groups_names) {
219		$child_groups = API::HostGroup()->get([
220			'output' => ['groupid'],
221			'search' => ['name' => $db_groups_names],
222			'searchByAny' => true,
223			'startSearch' => true
224		]);
225
226		foreach ($child_groups as $child_group) {
227			$groupids[] = $child_group['groupid'];
228		}
229	}
230
231	return $groupids;
232}
233
234/*
235 * Creates a hintbox suitable for Problem hosts widget.
236 *
237 * @param array  $hosts                                                   Array of problematic hosts.
238 * @param array  $data                                                    Array of host data, filter settings and
239 *                                                                        severity configuration.
240 * @param array  $data['config']                                          Severities configuration array.
241 * @param array  $data['filter']['severities']                            Array of severities.
242 * @param string $data['hosts_data'][<hostid>]['host']                    Host name.
243 * @param int    $data['hosts_data'][<hostid>]['severities'][<severity>]  Severity count.
244 * @param CUrl   $url                                                     URL that leads to problems view having hostid
245 *                                                                        in its filter.
246 *
247 * @return CTableInfo
248 */
249function makeProblemHostsHintBox(array $hosts, array $data, CUrl $url) {
250	// Set trigger severities as table header, ordered starting from highest severity.
251	$header = [_('Host')];
252
253	foreach (range(TRIGGER_SEVERITY_COUNT - 1, TRIGGER_SEVERITY_NOT_CLASSIFIED) as $severity) {
254		if (in_array($severity, $data['filter']['severities'])) {
255			$header[] = getSeverityName($severity, $data['config']);
256		}
257	}
258
259	$maintenanceids = [];
260	foreach ($data['hosts_data'] as $host) {
261		if ($host['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) {
262			$maintenanceids[$host['maintenanceid']] = true;
263		}
264	}
265
266	$db_maintenances = $maintenanceids
267		? API::Maintenance()->get([
268			'output' => ['name', 'description'],
269			'maintenanceids' => array_keys($maintenanceids),
270			'preservekeys' => true
271		])
272		: [];
273
274	$table_inf = (new CTableInfo())->setHeader($header);
275
276	$popup_rows = 0;
277
278	foreach ($hosts as $hostid => $host) {
279		$host_data = $data['hosts_data'][$hostid];
280		$url->setArgument('filter_hostids', [$hostid]);
281		$host_name = new CLink($host_data['host'], $url->getUrl());
282
283		if ($host_data['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) {
284			if (array_key_exists($host_data['maintenanceid'], $db_maintenances)) {
285				$maintenance = $db_maintenances[$host_data['maintenanceid']];
286				$maintenance_icon = makeMaintenanceIcon($host_data['maintenance_type'], $maintenance['name'],
287					$maintenance['description']
288				);
289			}
290			else {
291				$maintenance_icon = makeMaintenanceIcon($host_data['maintenance_type'], _('Inaccessible maintenance'),
292					''
293				);
294			}
295
296			$host_name = [$host_name, $maintenance_icon];
297		}
298
299		$row = new CRow((new CCol($host_name))->addClass(ZBX_STYLE_NOWRAP));
300
301		foreach (range(TRIGGER_SEVERITY_COUNT - 1, TRIGGER_SEVERITY_NOT_CLASSIFIED) as $severity) {
302			if (in_array($severity, $data['filter']['severities'])) {
303				$row->addItem(
304					($host_data['severities'][$severity] != 0)
305						? (new CCol($host_data['severities'][$severity]))->addClass(getSeverityStyle($severity))
306						: ''
307				);
308			}
309		}
310
311		$table_inf->addRow($row);
312
313		if (++$popup_rows == ZBX_WIDGET_ROWS) {
314			break;
315		}
316	}
317
318	return $table_inf;
319}
320
321/**
322 * Enriches host groups array by parent groups.
323 *
324 * @param array  $groups
325 * @param string $groups[<groupid>]['groupid']
326 * @param string $groups[<groupid>]['name']
327 * @param array  $options                        HostGroup API call parameters.
328 *
329 * @return array
330 */
331function enrichParentGroups(array $groups, array $options = []) {
332	$parents = [];
333	foreach ($groups as $group) {
334		$parent = explode('/', $group['name']);
335		while (array_pop($parent) && $parent) {
336			$parents[implode('/', $parent)] = true;
337		}
338	}
339
340	if ($parents) {
341		foreach ($groups as $group) {
342			if (array_key_exists($group['name'], $parents)) {
343				unset($parents[$group['name']]);
344			}
345		}
346	}
347
348	if ($parents) {
349		if (!array_key_exists('output', $options)) {
350			$options['output'] = ['groupid', 'name'];
351		}
352
353		if (!array_key_exists('filter', $options)) {
354			$options['filter'] = [];
355		}
356
357		$options['filter']['name'] = array_keys($parents);
358
359		$options['preservekeys'] = true;
360		$groups += API::HostGroup()->get($options);
361	}
362
363	return $groups;
364}
365