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 * @param array $options    additional API options to select host groups.
197 *
198 * @return array
199 */
200function getSubGroups(array $groupids, array &$ms_groups = null, array $options = []) {
201	$db_groups = $groupids
202		? API::HostGroup()->get([
203			'output' => ['groupid', 'name'],
204			'groupids' => $groupids,
205			'preservekeys' => true
206		] + $options)
207		: [];
208
209	if ($ms_groups !== null) {
210		$ms_groups = CArrayHelper::renameObjectsKeys($db_groups, ['groupid' => 'id']);
211	}
212
213	$db_groups_names = [];
214
215	foreach ($db_groups as $db_group) {
216		$db_groups_names[] = $db_group['name'].'/';
217	}
218
219	if ($db_groups_names) {
220		$db_groups += API::HostGroup()->get([
221			'output' => ['groupid'],
222			'search' => ['name' => $db_groups_names],
223			'searchByAny' => true,
224			'startSearch' => true,
225			'preservekeys' => true
226		] + $options);
227	}
228
229	return array_keys($db_groups);
230}
231
232/*
233 * Creates a hintbox suitable for Problem hosts widget.
234 *
235 * @param array  $hosts                                                   Array of problematic hosts.
236 * @param array  $data                                                    Array of host data, filter settings and
237 *                                                                        severity configuration.
238 * @param array  $data['config']                                          Severities configuration array.
239 * @param array  $data['filter']['severities']                            Array of severities.
240 * @param string $data['hosts_data'][<hostid>]['host']                    Host name.
241 * @param int    $data['hosts_data'][<hostid>]['severities'][<severity>]  Severity count.
242 * @param CUrl   $url                                                     URL that leads to problems view having hostid
243 *                                                                        in its filter.
244 *
245 * @return CTableInfo
246 */
247function makeProblemHostsHintBox(array $hosts, array $data, CUrl $url) {
248	// Set trigger severities as table header, ordered starting from highest severity.
249	$header = [_('Host')];
250
251	foreach (range(TRIGGER_SEVERITY_COUNT - 1, TRIGGER_SEVERITY_NOT_CLASSIFIED) as $severity) {
252		if (in_array($severity, $data['filter']['severities'])) {
253			$header[] = getSeverityName($severity, $data['config']);
254		}
255	}
256
257	$maintenanceids = [];
258	foreach ($data['hosts_data'] as $host) {
259		if ($host['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) {
260			$maintenanceids[$host['maintenanceid']] = true;
261		}
262	}
263
264	$db_maintenances = $maintenanceids
265		? API::Maintenance()->get([
266			'output' => ['name', 'description'],
267			'maintenanceids' => array_keys($maintenanceids),
268			'preservekeys' => true
269		])
270		: [];
271
272	$table_inf = (new CTableInfo())->setHeader($header);
273
274	$popup_rows = 0;
275
276	foreach ($hosts as $hostid => $host) {
277		$host_data = $data['hosts_data'][$hostid];
278		$url->setArgument('filter_hostids', [$hostid]);
279		$host_name = new CLink($host_data['host'], $url->getUrl());
280
281		if ($host_data['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) {
282			if (array_key_exists($host_data['maintenanceid'], $db_maintenances)) {
283				$maintenance = $db_maintenances[$host_data['maintenanceid']];
284				$maintenance_icon = makeMaintenanceIcon($host_data['maintenance_type'], $maintenance['name'],
285					$maintenance['description']
286				);
287			}
288			else {
289				$maintenance_icon = makeMaintenanceIcon($host_data['maintenance_type'], _('Inaccessible maintenance'),
290					''
291				);
292			}
293
294			$host_name = [$host_name, $maintenance_icon];
295		}
296
297		$row = new CRow((new CCol($host_name))->addClass(ZBX_STYLE_NOWRAP));
298
299		foreach (range(TRIGGER_SEVERITY_COUNT - 1, TRIGGER_SEVERITY_NOT_CLASSIFIED) as $severity) {
300			if (in_array($severity, $data['filter']['severities'])) {
301				$row->addItem(
302					($host_data['severities'][$severity] != 0)
303						? (new CCol($host_data['severities'][$severity]))->addClass(getSeverityStyle($severity))
304						: ''
305				);
306			}
307		}
308
309		$table_inf->addRow($row);
310
311		if (++$popup_rows == ZBX_WIDGET_ROWS) {
312			break;
313		}
314	}
315
316	return $table_inf;
317}
318
319/**
320 * Enriches host groups array by parent groups.
321 *
322 * @param array  $groups
323 * @param string $groups[<groupid>]['groupid']
324 * @param string $groups[<groupid>]['name']
325 *
326 * @return array
327 */
328function enrichParentGroups(array $groups) {
329	$parents = [];
330	foreach ($groups as $group) {
331		$parent = explode('/', $group['name']);
332		while (array_pop($parent) && $parent) {
333			$parents[implode('/', $parent)] = true;
334		}
335	}
336
337	if ($parents) {
338		foreach ($groups as $group) {
339			if (array_key_exists($group['name'], $parents)) {
340				unset($parents[$group['name']]);
341			}
342		}
343	}
344
345	if ($parents) {
346		$groups += API::HostGroup()->get([
347			'output' => ['groupid', 'name'],
348			'filter' => [
349				'name' => array_keys($parents)
350			],
351			'preservekeys' => true
352		]);
353	}
354
355	return $groups;
356}
357