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__).'/include/config.inc.php';
23require_once dirname(__FILE__).'/include/maps.inc.php';
24require_once dirname(__FILE__).'/include/forms.inc.php';
25
26$page['title'] = _('Configuration of network maps');
27$page['file'] = 'sysmaps.php';
28$page['type'] = detect_page_type(PAGE_TYPE_HTML);
29$page['scripts'] = ['multiselect.js', 'class.tab-indicators.js'];
30
31require_once dirname(__FILE__).'/include/page_header.php';
32
33// VAR	TYPE	OPTIONAL	FLAGS	VALIDATION	EXCEPTION
34$fields = [
35	'maps' =>					[T_ZBX_INT, O_OPT, P_SYS,	DB_ID,			null],
36	'sysmapid' =>				[T_ZBX_INT, O_OPT, P_SYS,	DB_ID,
37		'isset({form}) && ({form} === "update" || {form} === "full_clone")'
38	],
39	'name' =>					[T_ZBX_STR, O_OPT, null,	NOT_EMPTY, 'isset({add}) || isset({update})', _('Name')],
40	'width' =>					[T_ZBX_INT, O_OPT, null,	BETWEEN(0, 65535), 'isset({add}) || isset({update})', _('Width')],
41	'height' =>					[T_ZBX_INT, O_OPT, null,	BETWEEN(0, 65535), 'isset({add}) || isset({update})', _('Height')],
42	'backgroundid' =>			[T_ZBX_INT, O_OPT, null,	DB_ID,			'isset({add}) || isset({update})'],
43	'iconmapid' =>				[T_ZBX_INT, O_OPT, null,	DB_ID,			'isset({add}) || isset({update})'],
44	'expandproblem' =>			[T_ZBX_INT, O_OPT, null,
45		IN([SYSMAP_PROBLEMS_NUMBER, SYSMAP_SINGLE_PROBLEM, SYSMAP_PROBLEMS_NUMBER_CRITICAL]),	null
46	],
47	'markelements' =>			[T_ZBX_INT, O_OPT, null,	BETWEEN(0, 1),	null],
48	'show_unack' =>				[T_ZBX_INT, O_OPT, null,	BETWEEN(0, 2),	null],
49	'highlight' =>				[T_ZBX_INT, O_OPT, null,	BETWEEN(0, 1),	null],
50	'label_format' =>			[T_ZBX_INT, O_OPT, null,	BETWEEN(0, 1),	null],
51	'label_type_host' =>		[T_ZBX_INT, O_OPT, null,	BETWEEN(MAP_LABEL_TYPE_LABEL, MAP_LABEL_TYPE_CUSTOM), 'isset({add}) || isset({update})'],
52	'label_type_hostgroup' =>	[T_ZBX_INT, O_OPT, null,	BETWEEN(MAP_LABEL_TYPE_LABEL, MAP_LABEL_TYPE_CUSTOM), 'isset({add}) || isset({update})'],
53	'label_type_trigger' =>		[T_ZBX_INT, O_OPT, null,	BETWEEN(MAP_LABEL_TYPE_LABEL, MAP_LABEL_TYPE_CUSTOM), 'isset({add}) || isset({update})'],
54	'label_type_map' =>			[T_ZBX_INT, O_OPT, null,	BETWEEN(MAP_LABEL_TYPE_LABEL, MAP_LABEL_TYPE_CUSTOM), 'isset({add}) || isset({update})'],
55	'label_type_image' =>		[T_ZBX_INT, O_OPT, null,	BETWEEN(MAP_LABEL_TYPE_LABEL, MAP_LABEL_TYPE_CUSTOM), 'isset({add}) || isset({update})'],
56	'label_string_host' =>		[T_ZBX_STR, O_OPT, null,	null,			'isset({add}) || isset({update})'],
57	'label_string_hostgroup' =>	[T_ZBX_STR, O_OPT, null,	null,			'isset({add}) || isset({update})'],
58	'label_string_trigger' =>	[T_ZBX_STR, O_OPT, null,	null,			'isset({add}) || isset({update})'],
59	'label_string_map' =>		[T_ZBX_STR, O_OPT, null,	null,			'isset({add}) || isset({update})'],
60	'label_string_image' =>		[T_ZBX_STR, O_OPT, null,	null,			'isset({add}) || isset({update})'],
61	'label_type' =>				[T_ZBX_INT, O_OPT, null,	BETWEEN(MAP_LABEL_TYPE_LABEL,MAP_LABEL_TYPE_CUSTOM), 'isset({add}) || isset({update})'],
62	'label_location' =>			[T_ZBX_INT, O_OPT, null,	BETWEEN(0, 3),	'isset({add}) || isset({update})'],
63	'urls' =>					[T_ZBX_STR, O_OPT, null,	null,			null],
64	'severity_min' =>			[T_ZBX_INT, O_OPT, null,	IN('0,1,2,3,4,5'), null],
65	'show_suppressed' =>		[T_ZBX_INT, O_OPT, null,	BETWEEN(0, 1),	null],
66	'userid' =>					[T_ZBX_INT, O_OPT, P_SYS,	DB_ID,			null],
67	'private' =>				[T_ZBX_INT, O_OPT, null,	BETWEEN(0, 1),	null],
68	'users' =>					[T_ZBX_INT, O_OPT, null,	null,			null],
69	'userGroups' =>				[T_ZBX_INT, O_OPT, null,	null,			null],
70	// actions
71	'action' =>					[T_ZBX_STR, O_OPT, P_SYS|P_ACT, IN('"map.export","map.massdelete"'),		null],
72	'add' =>					[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,		null],
73	'update' =>					[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,		null],
74	'delete' =>					[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,		null],
75	'cancel' =>					[T_ZBX_STR, O_OPT, P_SYS,	null,			null],
76	// form
77	'form' =>					[T_ZBX_STR, O_OPT, P_SYS,	null,			null],
78	'form_refresh' =>			[T_ZBX_INT, O_OPT, null,	null,			null],
79	// filter
80	'filter_set' =>				[T_ZBX_STR, O_OPT, P_SYS,	null,			null],
81	'filter_rst' =>				[T_ZBX_STR, O_OPT, P_SYS,	null,			null],
82	'filter_name' =>			[T_ZBX_STR, O_OPT, null,	null,			null],
83	// sort and sortorder
84	'sort' =>					[T_ZBX_STR, O_OPT, P_SYS, IN('"height","name","width"'),				null],
85	'sortorder' =>				[T_ZBX_STR, O_OPT, P_SYS, IN('"'.ZBX_SORT_DOWN.'","'.ZBX_SORT_UP.'"'),	null]
86];
87check_fields($fields);
88
89/*
90 * Permissions
91 */
92if (hasRequest('sysmapid')) {
93	$sysmap = API::Map()->get([
94		'sysmapids' => getRequest('sysmapid'),
95		'editable' => true,
96		'output' => API_OUTPUT_EXTEND,
97		'selectUrls' => API_OUTPUT_EXTEND,
98		'selectUsers' => ['userid', 'permission'],
99		'selectUserGroups' => ['usrgrpid', 'permission']
100	]);
101	if (empty($sysmap)) {
102		access_deny();
103	}
104	else {
105		$sysmap = reset($sysmap);
106	}
107}
108else {
109	$sysmap = [];
110}
111
112$allowed_edit = CWebUser::checkAccess(CRoleHelper::ACTIONS_EDIT_MAPS);
113
114/*
115 * Actions
116 */
117if (hasRequest('add') || hasRequest('update')) {
118	if (!$allowed_edit) {
119		access_deny(ACCESS_DENY_PAGE);
120	}
121
122	$map = [
123		'name' => getRequest('name'),
124		'width' => getRequest('width'),
125		'height' => getRequest('height'),
126		'backgroundid' => getRequest('backgroundid'),
127		'iconmapid' => getRequest('iconmapid'),
128		'highlight' => getRequest('highlight', 0),
129		'markelements' => getRequest('markelements', 0),
130		'expandproblem' => getRequest('expandproblem', DB::getDefault('sysmaps', 'expandproblem')),
131		'label_format' => getRequest('label_format', 0),
132		'label_type_host' => getRequest('label_type_host', 2),
133		'label_type_hostgroup' => getRequest('label_type_hostgroup', 2),
134		'label_type_trigger' => getRequest('label_type_trigger', 2),
135		'label_type_map' => getRequest('label_type_map', 2),
136		'label_type_image' => getRequest('label_type_image', 2),
137		'label_string_host' => getRequest('label_string_host', ''),
138		'label_string_hostgroup' => getRequest('label_string_hostgroup', ''),
139		'label_string_trigger' => getRequest('label_string_trigger', ''),
140		'label_string_map' => getRequest('label_string_map', ''),
141		'label_string_image' => getRequest('label_string_image', ''),
142		'label_type' => getRequest('label_type'),
143		'label_location' => getRequest('label_location'),
144		'show_unack' => getRequest('show_unack', 0),
145		'severity_min' => getRequest('severity_min', TRIGGER_SEVERITY_NOT_CLASSIFIED),
146		'show_suppressed' => getRequest('show_suppressed', 0),
147		'urls' => getRequest('urls', []),
148		'userid' => getRequest('userid', ''),
149		'private' => getRequest('private', PRIVATE_SHARING),
150		'users' => getRequest('users', []),
151		'userGroups' => getRequest('userGroups', [])
152	];
153
154	foreach ($map['urls'] as $unum => $url) {
155		if (zbx_empty($url['name']) && zbx_empty($url['url'])) {
156			unset($map['urls'][$unum]);
157		}
158	}
159
160	DBstart();
161
162	if (hasRequest('update')) {
163		// TODO check permission by new value.
164		$map['sysmapid'] = getRequest('sysmapid');
165
166		// Only administrators can set map owner.
167		if (CWebUser::getType() == USER_TYPE_ZABBIX_USER) {
168			unset($map['userid']);
169		}
170		// Map update with inaccessible user.
171		elseif (CWebUser::getType() == USER_TYPE_ZABBIX_ADMIN && $map['userid'] === '') {
172			$user_exist = API::User()->get([
173				'output' => ['userid'],
174				'userids' => [$sysmap['userid']]
175			]);
176
177			if (!$user_exist) {
178				unset($map['userid']);
179			}
180		}
181
182		$result = API::Map()->update($map);
183
184		$messageSuccess = _('Network map updated');
185		$messageFailed = _('Cannot update network map');
186		$auditAction = AUDIT_ACTION_UPDATE;
187	}
188	else {
189		if (getRequest('form') === 'full_clone') {
190			$maps = API::Map()->get([
191				'output' => [],
192				'selectSelements' => ['selementid', 'elements', 'elementtype', 'iconid_off', 'iconid_on', 'label',
193					'label_location', 'x', 'y', 'iconid_disabled', 'iconid_maintenance', 'elementsubtype', 'areatype',
194					'width', 'height', 'viewtype', 'use_iconmap', 'urls', 'tags', 'evaltype'
195				],
196				'selectShapes' => ['type', 'x', 'y', 'width', 'height', 'text', 'font', 'font_size', 'font_color',
197					'text_halign', 'text_valign', 'border_type', 'border_width', 'border_color', 'background_color',
198					'zindex'
199				],
200				'selectLines' => ['x1', 'y1', 'x2', 'y2', 'line_type', 'line_width', 'line_color', 'zindex'],
201				'selectLinks' => ['selementid1', 'selementid2', 'drawtype', 'color', 'label', 'linktriggers'],
202				'sysmapids' => $sysmap['sysmapid']
203			]);
204
205			if ($maps) {
206				$map['selements'] = $maps[0]['selements'];
207				$map['shapes'] = $maps[0]['shapes'];
208				$map['lines'] = $maps[0]['lines'];
209				$map['links'] = $maps[0]['links'];
210			}
211		}
212
213		$result = API::Map()->create($map);
214
215		$messageSuccess = _('Network map added');
216		$messageFailed = _('Cannot add network map');
217		$auditAction = AUDIT_ACTION_ADD;
218	}
219
220	if ($result) {
221		add_audit($auditAction, AUDIT_RESOURCE_MAP, 'Name ['.$map['name'].']');
222		unset($_REQUEST['form']);
223	}
224
225	$result = DBend($result);
226
227	if ($result) {
228		uncheckTableRows();
229	}
230	show_messages($result, $messageSuccess, $messageFailed);
231}
232elseif ((hasRequest('delete') && hasRequest('sysmapid'))
233		|| (hasRequest('action') && getRequest('action') == 'map.massdelete')) {
234	if (!$allowed_edit) {
235		access_deny(ACCESS_DENY_PAGE);
236	}
237
238	$sysmapIds = getRequest('maps', []);
239
240	if (hasRequest('sysmapid')) {
241		$sysmapIds[] = getRequest('sysmapid');
242	}
243
244	DBstart();
245
246	$maps = API::Map()->get([
247		'sysmapids' => $sysmapIds,
248		'output' => ['sysmapid', 'name'],
249		'editable' => true
250	]);
251	$result = API::Map()->delete($sysmapIds);
252
253	if ($result) {
254		unset($_REQUEST['form']);
255
256		foreach ($maps as $map) {
257			add_audit_ext(AUDIT_ACTION_DELETE, AUDIT_RESOURCE_MAP, $map['sysmapid'], $map['name'], null, null, null);
258		}
259	}
260
261	$result = DBend($result);
262
263	if ($result) {
264		uncheckTableRows();
265	}
266	else {
267		uncheckTableRows(null, zbx_objectValues($maps, 'sysmapid'));
268	}
269	show_messages($result, _('Network map deleted'), _('Cannot delete network map'));
270}
271
272/*
273 * Display
274 */
275if (hasRequest('form')) {
276	if (!$allowed_edit) {
277		access_deny(ACCESS_DENY_PAGE);
278	}
279
280	$current_userid = CWebUser::$data['userid'];
281	$userids[$current_userid] = $current_userid;
282	$user_groupids = [];
283
284	if (!hasRequest('sysmapid') || hasRequest('form_refresh')) {
285		// Map owner
286		$map_owner = getRequest('userid', $current_userid);
287		$userids[$map_owner] = $map_owner;
288
289		foreach (getRequest('users', []) as $user) {
290			$userids[$user['userid']] = $user['userid'];
291		}
292
293		foreach (getRequest('userGroups', []) as $user_group) {
294			$user_groupids[$user_group['usrgrpid']] = $user_group['usrgrpid'];
295		}
296	}
297	else {
298		// Map owner.
299		$userids[$sysmap['userid']] = $sysmap['userid'];
300
301		foreach ($sysmap['users'] as $user) {
302			$userids[$user['userid']] = $user['userid'];
303		}
304
305		foreach ($sysmap['userGroups'] as $user_group) {
306			$user_groupids[$user_group['usrgrpid']] = $user_group['usrgrpid'];
307		}
308	}
309
310	$data['users'] = API::User()->get([
311		'output' => ['userid', 'username', 'name', 'surname'],
312		'userids' => $userids,
313		'preservekeys' => true
314	]);
315
316	$data['user_groups'] = API::UserGroup()->get([
317		'output' => ['usrgrpid', 'name'],
318		'usrgrpids' => $user_groupids,
319		'preservekeys' => true
320	]);
321
322	if (!hasRequest('sysmapid') || hasRequest('form_refresh')) {
323		$data['sysmap'] = [
324			'sysmapid' => getRequest('sysmapid'),
325			'name' => getRequest('name', ''),
326			'width' => getRequest('width', 800),
327			'height' => getRequest('height', 600),
328			'backgroundid' => getRequest('backgroundid', 0),
329			'iconmapid' => getRequest('iconmapid', 0),
330			'label_format' => getRequest('label_format', 0),
331			'label_type_host' => getRequest('label_type_host', 2),
332			'label_type_hostgroup' => getRequest('label_type_hostgroup', 2),
333			'label_type_trigger' => getRequest('label_type_trigger', 2),
334			'label_type_map' => getRequest('label_type_map', 2),
335			'label_type_image' => getRequest('label_type_image', 2),
336			'label_string_host' => getRequest('label_string_host', ''),
337			'label_string_hostgroup' => getRequest('label_string_hostgroup', ''),
338			'label_string_trigger' => getRequest('label_string_trigger', ''),
339			'label_string_map' => getRequest('label_string_map', ''),
340			'label_string_image' => getRequest('label_string_image', ''),
341			'label_type' => getRequest('label_type', 0),
342			'label_location' => getRequest('label_location', 0),
343			'highlight' => getRequest('highlight', 0),
344			'markelements' => getRequest('markelements', 0),
345			'expandproblem' => getRequest('expandproblem', DB::getDefault('sysmaps', 'expandproblem')),
346			'show_unack' => getRequest('show_unack', 0),
347			'severity_min' => getRequest('severity_min', TRIGGER_SEVERITY_NOT_CLASSIFIED),
348			'show_suppressed' => getRequest('show_suppressed', 0),
349			'urls' => getRequest('urls', []),
350			'userid' => getRequest('userid', hasRequest('form_refresh') ? '' : $current_userid),
351			'private' => getRequest('private', PRIVATE_SHARING),
352			'users' => getRequest('users', []),
353			'userGroups' => getRequest('userGroups', [])
354		];
355	}
356	else {
357		$data['sysmap'] = $sysmap;
358	}
359
360	$data['current_user_userid'] = $current_userid;
361	$data['form_refresh'] = getRequest('form_refresh');
362
363	// advanced labels
364	$data['labelTypes'] = sysmapElementLabel();
365	$data['labelTypesLimited'] = $data['labelTypes'];
366	unset($data['labelTypesLimited'][MAP_LABEL_TYPE_IP]);
367	$data['labelTypesImage'] = $data['labelTypesLimited'];
368	unset($data['labelTypesImage'][MAP_LABEL_TYPE_STATUS]);
369
370	// images
371	$data['images'] = API::Image()->get([
372		'output' => ['imageid', 'name'],
373		'filter' => ['imagetype' => IMAGE_TYPE_BACKGROUND]
374	]);
375	order_result($data['images'], 'name');
376
377	// icon maps
378	$data['iconMaps'] = API::IconMap()->get([
379		'output' => ['iconmapid', 'name'],
380		'preservekeys' => true
381	]);
382	order_result($data['iconMaps'], 'name');
383
384	// render view
385	echo (new CView('monitoring.sysmap.edit', $data))->getOutput();
386}
387else {
388	CProfile::delete('web.maps.sysmapid');
389
390	$sortField = getRequest('sort', CProfile::get('web.'.$page['file'].'.sort', 'name'));
391	$sortOrder = getRequest('sortorder', CProfile::get('web.'.$page['file'].'.sortorder', ZBX_SORT_UP));
392
393	CProfile::update('web.'.$page['file'].'.sort', $sortField, PROFILE_TYPE_STR);
394	CProfile::update('web.'.$page['file'].'.sortorder', $sortOrder, PROFILE_TYPE_STR);
395
396	if (hasRequest('filter_set')) {
397		CProfile::update('web.sysmapconf.filter_name', getRequest('filter_name', ''), PROFILE_TYPE_STR);
398	}
399	elseif (hasRequest('filter_rst')) {
400		DBStart();
401		CProfile::delete('web.sysmapconf.filter_name');
402		DBend();
403	}
404
405	$data = [
406		'filter' => [
407			'name' => CProfile::get('web.sysmapconf.filter_name', '')
408		],
409		'sort' => $sortField,
410		'sortorder' => $sortOrder,
411		'profileIdx' => 'web.sysmapconf.filter',
412		'active_tab' => CProfile::get('web.sysmapconf.filter.active', 1),
413		'allowed_edit' => $allowed_edit
414	];
415
416	// get maps
417	$limit = CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT) + 1;
418	$data['maps'] = API::Map()->get([
419		'output' => ['sysmapid', 'name', 'width', 'height'],
420		'sortfield' => $sortField,
421		'limit' => $limit,
422		'search' => [
423			'name' => ($data['filter']['name'] === '') ? null : $data['filter']['name']
424		],
425		'preservekeys' => true
426	]);
427
428	order_result($data['maps'], $sortField, $sortOrder);
429
430	// pager
431	if (hasRequest('page')) {
432		$data['page'] = getRequest('page');
433	}
434	elseif (isRequestMethod('get') && !hasRequest('cancel')) {
435		$data['page'] = 1;
436	}
437	else {
438		$data['page'] = CPagerHelper::loadPage($page['file']);
439	}
440
441	CPagerHelper::savePage($page['file'], $data['page']);
442
443	$data['paging'] = CPagerHelper::paginate($data['page'], $data['maps'], $sortOrder, new CUrl('sysmaps.php'));
444
445	if (CWebUser::getType() != USER_TYPE_SUPER_ADMIN) {
446		$editable_maps = API::Map()->get([
447			'output' => [],
448			'sysmapids' => array_keys($data['maps']),
449			'editable' => true,
450			'preservekeys' => true
451		]);
452
453		foreach ($data['maps'] as &$map) {
454			$map['editable'] = array_key_exists($map['sysmapid'], $editable_maps);
455		}
456		unset($map);
457	}
458
459	// render view
460	echo (new CView('monitoring.sysmap.list', $data))->getOutput();
461}
462
463require_once dirname(__FILE__).'/include/page_footer.php';
464