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