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', 'class.tab-indicators.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$allowed_edit = CWebUser::checkAccess(CRoleHelper::ACTIONS_EDIT_MAINTENANCE);
100
101if (!$allowed_edit && hasRequest('form') && getRequest('form') !== 'update') {
102	access_deny(ACCESS_DENY_PAGE);
103}
104
105/*
106 * Actions
107 */
108if (isset($_REQUEST['clone']) && isset($_REQUEST['maintenanceid'])) {
109	unset($_REQUEST['maintenanceid']);
110	$_REQUEST['form'] = 'clone';
111}
112elseif (hasRequest('add') || hasRequest('update')) {
113	if (!$allowed_edit) {
114		access_deny(ACCESS_DENY_PAGE);
115	}
116
117	if (hasRequest('update')) {
118		$messageSuccess = _('Maintenance updated');
119		$messageFailed = _('Cannot update maintenance');
120	}
121	else {
122		$messageSuccess = _('Maintenance added');
123		$messageFailed = _('Cannot add maintenance');
124	}
125
126	$result = true;
127	$absolute_time_parser = new CAbsoluteTimeParser();
128
129	$absolute_time_parser->parse(getRequest('active_since'));
130	$active_since_date = $absolute_time_parser->getDateTime(true);
131
132	$absolute_time_parser->parse(getRequest('active_till'));
133	$active_till_date = $absolute_time_parser->getDateTime(true);
134
135	if (!validateDateInterval($active_since_date->format('Y'), $active_since_date->format('m'),
136			$active_since_date->format('d'))) {
137		info(_s('"%1$s" must be between 1970.01.01 and 2038.01.18.', _('Active since')));
138		$result = false;
139	}
140
141	if (!validateDateInterval($active_till_date->format('Y'), $active_till_date->format('m'),
142			$active_till_date->format('d'))) {
143		info(_s('"%1$s" must be between 1970.01.01 and 2038.01.18.', _('Active till')));
144		$result = false;
145	}
146
147	if ($result) {
148		$timeperiods = getRequest('timeperiods', []);
149
150		foreach ($timeperiods as &$timeperiod) {
151			if ($timeperiod['timeperiod_type'] == TIMEPERIOD_TYPE_ONETIME) {
152				$absolute_time_parser->parse($timeperiod['start_date']);
153				$timeperiod['start_date'] = $absolute_time_parser
154					->getDateTime(true)
155					->getTimestamp();
156			}
157		}
158		unset($timeperiod);
159
160		$maintenance = [
161			'name' => $_REQUEST['mname'],
162			'maintenance_type' => getRequest('maintenance_type'),
163			'description' => getRequest('description'),
164			'active_since' => $active_since_date->getTimestamp(),
165			'active_till' => $active_till_date->getTimestamp(),
166			'timeperiods' => $timeperiods,
167			'hostids' => getRequest('hostids', []),
168			'groupids' => getRequest('groupids', [])
169		];
170
171		if ($maintenance['maintenance_type'] != MAINTENANCE_TYPE_NODATA) {
172			$maintenance += [
173				'tags_evaltype' => getRequest('tags_evaltype', MAINTENANCE_TAG_EVAL_TYPE_AND_OR),
174				'tags' => getRequest('tags', [])
175			];
176
177			foreach ($maintenance['tags'] as $tnum => $tag) {
178				if ($tag['tag'] === '' && $tag['value'] === '') {
179					unset($maintenance['tags'][$tnum]);
180				}
181			}
182		}
183
184		if (isset($_REQUEST['maintenanceid'])) {
185			$maintenance['maintenanceid'] = $_REQUEST['maintenanceid'];
186			$result = API::Maintenance()->update($maintenance);
187		}
188		else {
189			$result = API::Maintenance()->create($maintenance);
190		}
191	}
192
193	if ($result) {
194		unset($_REQUEST['form']);
195		uncheckTableRows();
196	}
197
198	show_messages($result, $messageSuccess, $messageFailed);
199}
200elseif (hasRequest('delete') || getRequest('action', '') == 'maintenance.massdelete') {
201	if (!$allowed_edit) {
202		access_deny(ACCESS_DENY_PAGE);
203	}
204
205	$maintenanceids = getRequest('maintenanceid', []);
206	if (hasRequest('maintenanceids')) {
207		$maintenanceids = getRequest('maintenanceids');
208	}
209
210	zbx_value2array($maintenanceids);
211
212	$result = API::Maintenance()->delete($maintenanceids);
213	if ($result) {
214		unset($_REQUEST['form'], $_REQUEST['maintenanceid']);
215		uncheckTableRows();
216	}
217	else {
218		$maintenances = API::Maintenance()->get([
219			'maintenanceids' => getRequest('maintenanceids'),
220			'output' => [],
221			'editable' => true
222		]);
223		uncheckTableRows(null, zbx_objectValues($maintenances, 'maintenanceid'));
224	}
225
226	show_messages($result, _('Maintenance deleted'), _('Cannot delete maintenance'));
227}
228
229/*
230 * Display
231 */
232$data = [
233	'form' => getRequest('form'),
234	'allowed_edit' => $allowed_edit
235];
236
237if (!empty($data['form'])) {
238	$data['maintenanceid'] = getRequest('maintenanceid');
239	$data['form_refresh'] = getRequest('form_refresh', 0);
240
241	if (isset($data['maintenanceid']) && !hasRequest('form_refresh')) {
242		$dbMaintenance = reset($dbMaintenance);
243		$data['mname'] = $dbMaintenance['name'];
244		$data['maintenance_type'] = $dbMaintenance['maintenance_type'];
245		$data['active_since'] = date(ZBX_DATE_TIME, $dbMaintenance['active_since']);
246		$data['active_till'] = date(ZBX_DATE_TIME, $dbMaintenance['active_till']);
247		$data['description'] = $dbMaintenance['description'];
248
249		// time periods
250		$data['timeperiods'] = $dbMaintenance['timeperiods'];
251		CArrayHelper::sort($data['timeperiods'], ['timeperiod_type', 'start_date']);
252
253		foreach ($data['timeperiods'] as &$timeperiod) {
254			$timeperiod['start_date'] = date(ZBX_DATE_TIME, $timeperiod['start_date']);
255		}
256		unset($timeperiod);
257
258		// get hosts
259		$db_hosts = API::Host()->get([
260			'output' => ['hostid', 'name'],
261			'maintenanceids' => $data['maintenanceid'],
262			'editable' => true
263		]);
264
265		// get groups
266		$db_groups = API::HostGroup()->get([
267			'output' => ['groupid', 'name'],
268			'maintenanceids' => $data['maintenanceid'],
269			'editable' => true
270		]);
271
272		// tags
273		$data['tags_evaltype'] = $dbMaintenance['tags_evaltype'];
274		$data['tags'] = $dbMaintenance['tags'];
275		CArrayHelper::sort($data['tags'], ['tag', 'value']);
276	}
277	else {
278		$data += [
279			'mname' => getRequest('mname', ''),
280			'maintenance_type' => getRequest('maintenance_type', 0),
281			'active_since' => getRequest('active_since', date(ZBX_DATE_TIME, strtotime('today'))),
282			'active_till' => getRequest('active_till', date(ZBX_DATE_TIME, strtotime('tomorrow'))),
283			'description' => getRequest('description', ''),
284			'timeperiods' => getRequest('timeperiods', []),
285			'tags_evaltype' => getRequest('tags_evaltype', MAINTENANCE_TAG_EVAL_TYPE_AND_OR),
286			'tags' => getRequest('tags', [])
287		];
288
289		$hostids = getRequest('hostids', []);
290		$groupids = getRequest('groupids', []);
291
292		$db_hosts = $hostids
293			? API::Host()->get([
294				'output' => ['hostid', 'name'],
295				'hostids' => $hostids,
296				'editable' => true
297			])
298			: [];
299
300		$db_groups = $groupids
301			? API::HostGroup()->get([
302				'output' => ['groupid', 'name'],
303				'groupids' => $groupids,
304				'editable' => true
305			])
306			: [];
307	}
308
309	$data['hosts_ms'] = CArrayHelper::renameObjectsKeys($db_hosts, ['hostid' => 'id']);
310	CArrayHelper::sort($data['hosts_ms'], ['name']);
311
312	$data['groups_ms'] = CArrayHelper::renameObjectsKeys($db_groups, ['groupid' => 'id']);
313	CArrayHelper::sort($data['groups_ms'], ['name']);
314
315	// render view
316	echo (new CView('configuration.maintenance.edit', $data))->getOutput();
317}
318else {
319	// get maintenances
320	$sortField = getRequest('sort', CProfile::get('web.'.$page['file'].'.sort', 'name'));
321	$sortOrder = getRequest('sortorder', CProfile::get('web.'.$page['file'].'.sortorder', ZBX_SORT_UP));
322
323	CProfile::update('web.'.$page['file'].'.sort', $sortField, PROFILE_TYPE_STR);
324	CProfile::update('web.'.$page['file'].'.sortorder', $sortOrder, PROFILE_TYPE_STR);
325
326	// filter
327	if (hasRequest('filter_set')) {
328		CProfile::update('web.maintenance.filter_name', getRequest('filter_name', ''), PROFILE_TYPE_STR);
329		CProfile::update('web.maintenance.filter_status', getRequest('filter_status', -1), PROFILE_TYPE_INT);
330		CProfile::updateArray('web.maintenance.filter_groups', getRequest('filter_groups', []), PROFILE_TYPE_ID);
331	}
332	elseif (hasRequest('filter_rst')) {
333		CProfile::delete('web.maintenance.filter_name');
334		CProfile::delete('web.maintenance.filter_status');
335		CProfile::deleteIdx('web.maintenance.filter_groups');
336	}
337
338	$filter = [
339		'name' => CProfile::get('web.maintenance.filter_name', ''),
340		'status' => CProfile::get('web.maintenance.filter_status', -1),
341		'groups' => CProfile::getArray('web.maintenance.filter_groups', [])
342	];
343
344	// Get host groups.
345	$filter['groups'] = $filter['groups']
346		? CArrayHelper::renameObjectsKeys(API::HostGroup()->get([
347			'output' => ['groupid', 'name'],
348			'groupids' => $filter['groups'],
349			'editable' => true,
350			'preservekeys' => true
351		]), ['groupid' => 'id'])
352		: [];
353
354	$filter_groupids = $filter['groups'] ? array_keys($filter['groups']) : null;
355	if ($filter_groupids) {
356		$filter_groupids = getSubGroups($filter_groupids);
357	}
358
359	$data = [
360		'sort' => $sortField,
361		'sortorder' => $sortOrder,
362		'filter' => $filter,
363		'profileIdx' => 'web.maintenance.filter',
364		'active_tab' => CProfile::get('web.maintenance.filter.active', 1),
365		'allowed_edit' => $allowed_edit
366	];
367
368	// Get list of maintenances.
369	$options = [
370		'output' => ['maintenanceid', 'name', 'maintenance_type', 'active_since', 'active_till', 'description'],
371		'search' => [
372			'name' => ($filter['name'] === '') ? null : $filter['name']
373		],
374		'groupids' => $filter_groupids,
375		'editable' => true,
376		'sortfield' => $sortField,
377		'sortorder' => $sortOrder,
378		'limit' => CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT) + 1
379	];
380
381	$data['maintenances'] = API::Maintenance()->get($options);
382
383	foreach ($data['maintenances'] as $key => $maintenance) {
384		if ($maintenance['active_till'] < time()) {
385			$data['maintenances'][$key]['status'] = MAINTENANCE_STATUS_EXPIRED;
386		}
387		elseif ($maintenance['active_since'] > time()) {
388			$data['maintenances'][$key]['status'] = MAINTENANCE_STATUS_APPROACH;
389		}
390		else {
391			$data['maintenances'][$key]['status'] = MAINTENANCE_STATUS_ACTIVE;
392		}
393	}
394
395	// filter by status
396	if ($filter['status'] != -1) {
397		foreach ($data['maintenances'] as $key => $maintenance) {
398			if ($data['maintenances'][$key]['status'] != $filter['status']) {
399				unset($data['maintenances'][$key]);
400			}
401		}
402	}
403
404	order_result($data['maintenances'], $sortField, $sortOrder);
405
406	// pager
407	if (hasRequest('page')) {
408		$page_num = getRequest('page');
409	}
410	elseif (isRequestMethod('get') && !hasRequest('cancel')) {
411		$page_num = 1;
412	}
413	else {
414		$page_num = CPagerHelper::loadPage($page['file']);
415	}
416
417	CPagerHelper::savePage($page['file'], $page_num);
418
419	$data['paging'] = CPagerHelper::paginate($page_num, $data['maintenances'], $sortOrder, new CUrl('maintenance.php'));
420
421	// render view
422	echo (new CView('configuration.maintenance.list', $data))->getOutput();
423}
424
425require_once dirname(__FILE__).'/include/page_footer.php';
426