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/hosts.inc.php';
24require_once dirname(__FILE__).'/include/maintenances.inc.php';
25require_once dirname(__FILE__).'/include/forms.inc.php';
26
27$page['title'] = _('Configuration of maintenance periods');
28$page['file'] = 'maintenance.php';
29$page['scripts'] = ['class.cviewswitcher.js', 'class.calendar.js', 'multiselect.js'];
30
31require_once dirname(__FILE__).'/include/page_header.php';
32
33// VAR	TYPE	OPTIONAL	FLAGS	VALIDATION	EXCEPTION
34$fields = [
35	'hostids' =>							[T_ZBX_INT, O_OPT, P_SYS,	DB_ID,		null],
36	'groupids' =>							[T_ZBX_INT, O_OPT, P_SYS,	DB_ID,		null],
37	// maintenance
38	'maintenanceid' =>						[T_ZBX_INT, O_OPT, P_SYS,	DB_ID,		'isset({form}) && {form} == "update"'],
39	'maintenanceids' =>						[T_ZBX_INT, O_OPT, P_SYS,	DB_ID, 		null],
40	'mname' =>								[T_ZBX_STR, O_OPT, null,	NOT_EMPTY,	'isset({add}) || isset({update})', _('Name')],
41	'maintenance_type' =>					[T_ZBX_INT, O_OPT, null,	null,		'isset({add}) || isset({update})'],
42	'description' =>						[T_ZBX_STR, O_OPT, null,	null,		'isset({add}) || isset({update})'],
43	'active_since' =>						[T_ZBX_ABS_TIME, O_OPT, null, NOT_EMPTY,
44												'isset({add}) || isset({update})', _('Active since')
45											],
46	'active_till' =>						[T_ZBX_ABS_TIME, O_OPT, null, NOT_EMPTY,
47												'isset({add}) || isset({update})', _('Active till')
48											],
49	'timeperiods' =>						[T_ZBX_STR, O_OPT, null,	null,		null],
50	'tags_evaltype' =>						[T_ZBX_INT, O_OPT, null,	null,		null],
51	'tags' =>								[T_ZBX_STR, O_OPT, null,	null,		null],
52	// actions
53	'action' =>								[T_ZBX_STR, O_OPT, P_SYS|P_ACT, IN('"maintenance.massdelete"'), null],
54	'add' =>								[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
55	'update' =>								[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
56	'clone' =>								[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
57	'delete' =>								[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
58	'cancel' =>								[T_ZBX_STR, O_OPT, P_SYS,		 null,	null],
59	// form
60	'form' =>								[T_ZBX_STR, O_OPT, P_SYS,	null,		null],
61	'form_refresh' =>						[T_ZBX_INT, O_OPT, null,	null,		null],
62	// filter
63	'filter_set' =>							[T_ZBX_STR, O_OPT, P_SYS,	null,		null],
64	'filter_rst' =>							[T_ZBX_STR, O_OPT, P_SYS,	null,		null],
65	'filter_name' =>						[T_ZBX_STR, O_OPT, null,	null,		null],
66	'filter_status' =>						[T_ZBX_INT, O_OPT, null,	IN([-1, MAINTENANCE_STATUS_ACTIVE, MAINTENANCE_STATUS_APPROACH, MAINTENANCE_STATUS_EXPIRED]), null],
67	'filter_groups' =>						[T_ZBX_INT, O_OPT, null,	DB_ID,		null],
68	// sort and sortorder
69	'sort' =>								[T_ZBX_STR, O_OPT, P_SYS,
70												IN('"active_since","active_till","maintenance_type","name"'),
71												null
72											],
73	'sortorder' =>							[T_ZBX_STR, O_OPT, P_SYS, IN('"'.ZBX_SORT_DOWN.'","'.ZBX_SORT_UP.'"'),
74												null
75											]
76];
77
78check_fields($fields);
79
80/*
81 * Permissions
82 */
83if (isset($_REQUEST['maintenanceid'])) {
84	$dbMaintenance = API::Maintenance()->get([
85		'output' => API_OUTPUT_EXTEND,
86		'selectTimeperiods' => API_OUTPUT_EXTEND,
87		'selectTags' => API_OUTPUT_EXTEND,
88		'editable' => true,
89		'maintenanceids' => getRequest('maintenanceid')
90	]);
91	if (empty($dbMaintenance)) {
92		access_deny();
93	}
94}
95if (hasRequest('action') && (!hasRequest('maintenanceids') || !is_array(getRequest('maintenanceids')))) {
96	access_deny();
97}
98
99/*
100 * Actions
101 */
102if (isset($_REQUEST['clone']) && isset($_REQUEST['maintenanceid'])) {
103	unset($_REQUEST['maintenanceid']);
104	$_REQUEST['form'] = 'clone';
105}
106elseif (hasRequest('add') || hasRequest('update')) {
107	if (hasRequest('update')) {
108		$messageSuccess = _('Maintenance updated');
109		$messageFailed = _('Cannot update maintenance');
110	}
111	else {
112		$messageSuccess = _('Maintenance added');
113		$messageFailed = _('Cannot add maintenance');
114	}
115
116	$result = true;
117	$absolute_time_parser = new CAbsoluteTimeParser();
118
119	$absolute_time_parser->parse(getRequest('active_since'));
120	$active_since_date = $absolute_time_parser->getDateTime(true);
121
122	$absolute_time_parser->parse(getRequest('active_till'));
123	$active_till_date = $absolute_time_parser->getDateTime(true);
124
125	if (!validateDateInterval($active_since_date->format('Y'), $active_since_date->format('m'),
126			$active_since_date->format('d'))) {
127		info(_s('"%1$s" must be between 1970.01.01 and 2038.01.18.', _('Active since')));
128		$result = false;
129	}
130
131	if (!validateDateInterval($active_till_date->format('Y'), $active_till_date->format('m'),
132			$active_till_date->format('d'))) {
133		info(_s('"%1$s" must be between 1970.01.01 and 2038.01.18.', _('Active till')));
134		$result = false;
135	}
136
137	if ($result) {
138		$timeperiods = getRequest('timeperiods', []);
139
140		foreach ($timeperiods as &$timeperiod) {
141			if ($timeperiod['timeperiod_type'] == TIMEPERIOD_TYPE_ONETIME) {
142				$absolute_time_parser->parse($timeperiod['start_date']);
143				$timeperiod['start_date'] = $absolute_time_parser
144					->getDateTime(true)
145					->getTimestamp();
146			}
147		}
148		unset($timeperiod);
149
150		$maintenance = [
151			'name' => $_REQUEST['mname'],
152			'maintenance_type' => getRequest('maintenance_type'),
153			'description' => getRequest('description'),
154			'active_since' => $active_since_date->getTimestamp(),
155			'active_till' => $active_till_date->getTimestamp(),
156			'timeperiods' => $timeperiods,
157			'hostids' => getRequest('hostids', []),
158			'groupids' => getRequest('groupids', [])
159		];
160
161		if ($maintenance['maintenance_type'] != MAINTENANCE_TYPE_NODATA) {
162			$maintenance += [
163				'tags_evaltype' => getRequest('tags_evaltype', MAINTENANCE_TAG_EVAL_TYPE_AND_OR),
164				'tags' => getRequest('tags', [])
165			];
166
167			foreach ($maintenance['tags'] as $tnum => $tag) {
168				if ($tag['tag'] === '' && $tag['value'] === '') {
169					unset($maintenance['tags'][$tnum]);
170				}
171			}
172		}
173
174		if (isset($_REQUEST['maintenanceid'])) {
175			$maintenance['maintenanceid'] = $_REQUEST['maintenanceid'];
176			$result = API::Maintenance()->update($maintenance);
177		}
178		else {
179			$result = API::Maintenance()->create($maintenance);
180		}
181	}
182
183	if ($result) {
184		unset($_REQUEST['form']);
185		uncheckTableRows();
186	}
187
188	show_messages($result, $messageSuccess, $messageFailed);
189}
190elseif (hasRequest('delete') || getRequest('action', '') == 'maintenance.massdelete') {
191	$maintenanceids = getRequest('maintenanceid', []);
192	if (hasRequest('maintenanceids')) {
193		$maintenanceids = getRequest('maintenanceids');
194	}
195
196	zbx_value2array($maintenanceids);
197
198	$result = API::Maintenance()->delete($maintenanceids);
199	if ($result) {
200		unset($_REQUEST['form'], $_REQUEST['maintenanceid']);
201		uncheckTableRows();
202	}
203	else {
204		$maintenances = API::Maintenance()->get([
205			'maintenanceids' => getRequest('maintenanceids'),
206			'output' => [],
207			'editable' => true
208		]);
209		uncheckTableRows(null, zbx_objectValues($maintenances, 'maintenanceid'));
210	}
211
212	show_messages($result, _('Maintenance deleted'), _('Cannot delete maintenance'));
213}
214
215/*
216 * Display
217 */
218$data = [
219	'form' => getRequest('form')
220];
221
222if (!empty($data['form'])) {
223	$data['maintenanceid'] = getRequest('maintenanceid');
224	$data['form_refresh'] = getRequest('form_refresh', 0);
225
226	if (isset($data['maintenanceid']) && !hasRequest('form_refresh')) {
227		$dbMaintenance = reset($dbMaintenance);
228		$data['mname'] = $dbMaintenance['name'];
229		$data['maintenance_type'] = $dbMaintenance['maintenance_type'];
230		$data['active_since'] = date(ZBX_DATE_TIME, $dbMaintenance['active_since']);
231		$data['active_till'] = date(ZBX_DATE_TIME, $dbMaintenance['active_till']);
232		$data['description'] = $dbMaintenance['description'];
233
234		// time periods
235		$data['timeperiods'] = $dbMaintenance['timeperiods'];
236		CArrayHelper::sort($data['timeperiods'], ['timeperiod_type', 'start_date']);
237
238		foreach ($data['timeperiods'] as &$timeperiod) {
239			$timeperiod['start_date'] = date(ZBX_DATE_TIME, $timeperiod['start_date']);
240		}
241		unset($timeperiod);
242
243		// get hosts
244		$db_hosts = API::Host()->get([
245			'output' => ['hostid', 'name'],
246			'maintenanceids' => $data['maintenanceid'],
247			'editable' => true
248		]);
249
250		// get groups
251		$db_groups = API::HostGroup()->get([
252			'output' => ['groupid', 'name'],
253			'maintenanceids' => $data['maintenanceid'],
254			'editable' => true
255		]);
256
257		// tags
258		$data['tags_evaltype'] = $dbMaintenance['tags_evaltype'];
259		$data['tags'] = $dbMaintenance['tags'];
260		CArrayHelper::sort($data['tags'], ['tag', 'value']);
261	}
262	else {
263		$data += [
264			'mname' => getRequest('mname', ''),
265			'maintenance_type' => getRequest('maintenance_type', 0),
266			'active_since' => getRequest('active_since', date(ZBX_DATE_TIME, strtotime('today'))),
267			'active_till' => getRequest('active_till', date(ZBX_DATE_TIME, strtotime('tomorrow'))),
268			'description' => getRequest('description', ''),
269			'timeperiods' => getRequest('timeperiods', []),
270			'tags_evaltype' => getRequest('tags_evaltype', MAINTENANCE_TAG_EVAL_TYPE_AND_OR),
271			'tags' => getRequest('tags', [])
272		];
273
274		$hostids = getRequest('hostids', []);
275		$groupids = getRequest('groupids', []);
276
277		$db_hosts = $hostids
278			? API::Host()->get([
279				'output' => ['hostid', 'name'],
280				'hostids' => $hostids,
281				'editable' => true
282			])
283			: [];
284
285		$db_groups = $groupids
286			? API::HostGroup()->get([
287				'output' => ['groupid', 'name'],
288				'groupids' => $groupids,
289				'editable' => true
290			])
291			: [];
292	}
293
294	$data['hosts_ms'] = CArrayHelper::renameObjectsKeys($db_hosts, ['hostid' => 'id']);
295	CArrayHelper::sort($data['hosts_ms'], ['name']);
296
297	$data['groups_ms'] = CArrayHelper::renameObjectsKeys($db_groups, ['groupid' => 'id']);
298	CArrayHelper::sort($data['groups_ms'], ['name']);
299
300	// render view
301	echo (new CView('configuration.maintenance.edit', $data))->getOutput();
302}
303else {
304	// get maintenances
305	$sortField = getRequest('sort', CProfile::get('web.'.$page['file'].'.sort', 'name'));
306	$sortOrder = getRequest('sortorder', CProfile::get('web.'.$page['file'].'.sortorder', ZBX_SORT_UP));
307
308	CProfile::update('web.'.$page['file'].'.sort', $sortField, PROFILE_TYPE_STR);
309	CProfile::update('web.'.$page['file'].'.sortorder', $sortOrder, PROFILE_TYPE_STR);
310
311	// filter
312	if (hasRequest('filter_set')) {
313		CProfile::update('web.maintenance.filter_name', getRequest('filter_name', ''), PROFILE_TYPE_STR);
314		CProfile::update('web.maintenance.filter_status', getRequest('filter_status', -1), PROFILE_TYPE_INT);
315		CProfile::updateArray('web.maintenance.filter_groups', getRequest('filter_groups', []), PROFILE_TYPE_ID);
316	}
317	elseif (hasRequest('filter_rst')) {
318		CProfile::delete('web.maintenance.filter_name');
319		CProfile::delete('web.maintenance.filter_status');
320		CProfile::deleteIdx('web.maintenance.filter_groups');
321	}
322
323	$filter = [
324		'name' => CProfile::get('web.maintenance.filter_name', ''),
325		'status' => CProfile::get('web.maintenance.filter_status', -1),
326		'groups' => CProfile::getArray('web.maintenance.filter_groups', [])
327	];
328
329	// Get host groups.
330	$filter['groups'] = $filter['groups']
331		? CArrayHelper::renameObjectsKeys(API::HostGroup()->get([
332			'output' => ['groupid', 'name'],
333			'groupids' => $filter['groups'],
334			'editable' => true,
335			'preservekeys' => true
336		]), ['groupid' => 'id'])
337		: [];
338
339	$filter_groupids = $filter['groups'] ? array_keys($filter['groups']) : null;
340	if ($filter_groupids) {
341		$filter_groupids = getSubGroups($filter_groupids);
342	}
343
344	$config = select_config();
345
346	$data = [
347		'sort' => $sortField,
348		'sortorder' => $sortOrder,
349		'filter' => $filter,
350		'profileIdx' => 'web.maintenance.filter',
351		'active_tab' => CProfile::get('web.maintenance.filter.active', 1)
352	];
353
354	// Get list of maintenances.
355	$options = [
356		'output' => ['maintenanceid', 'name', 'maintenance_type', 'active_since', 'active_till', 'description'],
357		'search' => [
358			'name' => ($filter['name'] === '') ? null : $filter['name']
359		],
360		'groupids' => $filter_groupids,
361		'editable' => true,
362		'sortfield' => $sortField,
363		'sortorder' => $sortOrder,
364		'limit' => $config['search_limit'] + 1
365	];
366
367	$data['maintenances'] = API::Maintenance()->get($options);
368
369	foreach ($data['maintenances'] as $key => $maintenance) {
370		if ($maintenance['active_till'] < time()) {
371			$data['maintenances'][$key]['status'] = MAINTENANCE_STATUS_EXPIRED;
372		}
373		elseif ($maintenance['active_since'] > time()) {
374			$data['maintenances'][$key]['status'] = MAINTENANCE_STATUS_APPROACH;
375		}
376		else {
377			$data['maintenances'][$key]['status'] = MAINTENANCE_STATUS_ACTIVE;
378		}
379	}
380
381	// filter by status
382	if ($filter['status'] != -1) {
383		foreach ($data['maintenances'] as $key => $maintenance) {
384			if ($data['maintenances'][$key]['status'] != $filter['status']) {
385				unset($data['maintenances'][$key]);
386			}
387		}
388	}
389
390	order_result($data['maintenances'], $sortField, $sortOrder);
391
392	// pager
393	if (hasRequest('page')) {
394		$page_num = getRequest('page');
395	}
396	elseif (isRequestMethod('get') && !hasRequest('cancel')) {
397		$page_num = 1;
398	}
399	else {
400		$page_num = CPagerHelper::loadPage($page['file']);
401	}
402
403	CPagerHelper::savePage($page['file'], $page_num);
404
405	$data['paging'] = CPagerHelper::paginate($page_num, $data['maintenances'], $sortOrder, new CUrl('maintenance.php'));
406
407	// render view
408	echo (new CView('configuration.maintenance.list', $data))->getOutput();
409}
410
411require_once dirname(__FILE__).'/include/page_footer.php';
412