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/forms.inc.php';
24require_once dirname(__FILE__).'/include/actions.inc.php';
25require_once dirname(__FILE__).'/include/triggers.inc.php';
26
27$page['title'] = _('Configuration of actions');
28$page['file'] = 'actionconf.php';
29$page['scripts'] = ['multiselect.js'];
30
31require_once dirname(__FILE__).'/include/page_header.php';
32// VAR							TYPE	OPTIONAL	FLAGS	VALIDATION	EXCEPTION
33$fields = [
34	'actionid' =>						[T_ZBX_INT, O_OPT, P_SYS,	DB_ID,		'isset({form}) && {form} == "update"'],
35	'name' =>							[T_ZBX_STR, O_OPT, null,	NOT_EMPTY,	'isset({add}) || isset({update})',
36											_('Name')
37										],
38	'eventsource' =>					[T_ZBX_INT, O_OPT, null,
39											IN([EVENT_SOURCE_TRIGGERS, EVENT_SOURCE_DISCOVERY,
40												EVENT_SOURCE_AUTO_REGISTRATION, EVENT_SOURCE_INTERNAL
41											]),
42											null
43										],
44	'evaltype' =>						[T_ZBX_INT, O_OPT, null,
45											IN([CONDITION_EVAL_TYPE_AND_OR, CONDITION_EVAL_TYPE_AND,
46												CONDITION_EVAL_TYPE_OR, CONDITION_EVAL_TYPE_EXPRESSION
47											]),
48											'isset({add}) || isset({update})'
49										],
50	'formula' =>						[T_ZBX_STR, O_OPT, null,	null,	'isset({add}) || isset({update})'],
51	'esc_period' =>						[T_ZBX_STR, O_OPT, null,	null,	null, _('Default operation step duration')],
52	'status' =>							[T_ZBX_INT, O_OPT, null,	IN([ACTION_STATUS_ENABLED, ACTION_STATUS_DISABLED]),
53											null
54										],
55	'def_shortdata' =>					[T_ZBX_STR, O_OPT, null,	null,		'isset({add}) || isset({update})'],
56	'def_longdata' =>					[T_ZBX_STR, O_OPT, null,	null,		'isset({add}) || isset({update})'],
57	'r_shortdata' =>					[T_ZBX_STR, O_OPT, null,	null,		null],
58	'r_longdata' =>						[T_ZBX_STR, O_OPT, null,	null,		null],
59	'ack_shortdata' =>					[T_ZBX_STR, O_OPT, null,	null,		null],
60	'ack_longdata' =>					[T_ZBX_STR, O_OPT, null,	null,		null],
61	'g_actionid' =>						[T_ZBX_INT, O_OPT, null,	DB_ID,		null],
62	'conditions' =>						[null,		O_OPT,	null,	null,		null],
63	'new_condition' =>					[null,		O_OPT,	null,	null,		'isset({add_condition})'],
64	'operations' =>						[null,		O_OPT,	null,	null,		null],
65	'edit_operationid' =>				[T_ZBX_STR, O_OPT,	P_ACT,	null,		null],
66	'new_operation' =>					[null,		O_OPT,	null,	null,		null],
67	'recovery_operations' =>			[null,		O_OPT,	null,	null,		null],
68	'edit_recovery_operationid' =>		[T_ZBX_STR, O_OPT,	P_ACT,	null,		null],
69	'new_recovery_operation' =>			[null,		O_OPT,	null,	null,		null],
70	'ack_operations' =>					[null,		O_OPT,	null,	null,		null],
71	'edit_ack_operationid' =>			[T_ZBX_STR, O_OPT,	P_ACT,	null,		null],
72	'new_ack_operation' =>				[null,		O_OPT,	null,	null,		null],
73	'opconditions' =>					[null,		O_OPT,	null,	null,		null],
74	'new_opcondition' =>				[null,		O_OPT,	null,	null,		'isset({add_opcondition})'],
75	// actions
76	'action' =>							[T_ZBX_STR, O_OPT, P_SYS|P_ACT,
77											IN('"action.massdelete","action.massdisable","action.massenable"'),
78											null
79										],
80	'add_condition' =>					[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
81	'cancel_new_condition' =>			[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
82	'add_operation' =>					[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
83	'cancel_new_operation' =>			[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
84	'add_recovery_operation' =>			[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
85	'cancel_new_recovery_operation' =>	[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
86	'add_ack_operation' =>				[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
87	'cancel_new_ack_operation' =>		[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
88	'add_opcondition' =>				[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
89	'cancel_new_opcondition' =>			[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
90	'pause_suppressed' =>				[T_ZBX_STR, O_OPT, null,
91											IN([ACTION_PAUSE_SUPPRESSED_FALSE, ACTION_PAUSE_SUPPRESSED_TRUE]),
92											null,
93											_('Pause operations for suppressed problems')
94										],
95	'add' =>							[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
96	'update' =>							[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
97	'delete' =>							[T_ZBX_STR, O_OPT, P_SYS|P_ACT, null,	null],
98	'cancel' =>							[T_ZBX_STR, O_OPT, P_SYS,		null,	null],
99	'form' =>							[T_ZBX_STR, O_OPT, P_SYS,		null,	null],
100	'form_refresh' =>					[T_ZBX_INT, O_OPT, null,		null,	null],
101	// filter
102	'filter_set' =>				[T_ZBX_STR, O_OPT, P_SYS,	null,		null],
103	'filter_rst' =>				[T_ZBX_STR, O_OPT, P_SYS,	null,		null],
104	'filter_name' =>			[T_ZBX_STR, O_OPT, null,	null,		null],
105	'filter_status' =>			[T_ZBX_INT, O_OPT, null,	IN([-1, ACTION_STATUS_ENABLED, ACTION_STATUS_DISABLED]),		null],
106	// sort and sortorder
107	'sort' =>							[T_ZBX_STR, O_OPT, P_SYS, IN('"name","status"'),						null],
108	'sortorder' =>						[T_ZBX_STR, O_OPT, P_SYS, IN('"'.ZBX_SORT_DOWN.'","'.ZBX_SORT_UP.'"'),	null]
109];
110
111$dataValid = check_fields($fields);
112$edit_ack_operationid = null;
113$new_ack_operation = getRequest('new_ack_operation', []);
114$ack_operations = getRequest('ack_operations', []);
115
116if ($dataValid && hasRequest('eventsource') && !hasRequest('form')) {
117	CProfile::update('web.actionconf.eventsource', getRequest('eventsource'), PROFILE_TYPE_INT);
118}
119
120if (isset($_REQUEST['actionid'])) {
121	$actionPermissions = API::Action()->get([
122		'output' => ['actionid'],
123		'actionids' => $_REQUEST['actionid'],
124		'editable' => true
125	]);
126	if (empty($actionPermissions)) {
127		access_deny();
128	}
129}
130
131/*
132 * Actions
133 */
134if (hasRequest('cancel_new_operation')) {
135	unset($_REQUEST['new_operation']);
136}
137elseif (hasRequest('cancel_new_opcondition')) {
138	unset($_REQUEST['new_opcondition']);
139}
140elseif (hasRequest('cancel_new_recovery_operation')) {
141	unset($_REQUEST['new_recovery_operation']);
142}
143elseif (hasRequest('cancel_new_ack_operation')) {
144	$new_ack_operation = [];
145}
146elseif (hasRequest('add') || hasRequest('update')) {
147	$action = [
148		'name' => getRequest('name'),
149		'status' => getRequest('status', ACTION_STATUS_DISABLED),
150		'esc_period' => getRequest('esc_period', DB::getDefault('actions', 'esc_period')),
151		'def_shortdata' => getRequest('def_shortdata', ''),
152		'def_longdata' => getRequest('def_longdata', ''),
153		'r_shortdata' => getRequest('r_shortdata', ''),
154		'r_longdata' => getRequest('r_longdata', ''),
155		'ack_shortdata' => getRequest('ack_shortdata', ''),
156		'ack_longdata' => getRequest('ack_longdata', ''),
157		'operations' => getRequest('operations', []),
158		'recovery_operations' => getRequest('recovery_operations', []),
159		'acknowledge_operations' => getRequest('ack_operations', [])
160	];
161
162	foreach (['operations', 'recovery_operations', 'acknowledge_operations'] as $operation_key) {
163		foreach ($action[$operation_key] as &$operation) {
164			if (array_key_exists('opmessage', $operation)
165					&& !array_key_exists('default_msg', $operation['opmessage'])) {
166				$operation['opmessage']['default_msg'] = 0;
167			}
168		}
169		unset($operation);
170	}
171
172	foreach ($action['operations'] as &$operation) {
173		if ($operation['operationtype'] == OPERATION_TYPE_GROUP_ADD
174				|| $operation['operationtype'] == OPERATION_TYPE_GROUP_REMOVE) {
175			$operation['opgroup'] = [];
176
177			foreach ($operation['groupids'] as $groupid) {
178				$operation['opgroup'][] = ['groupid' => $groupid];
179			}
180			unset($operation['groupids']);
181		}
182		elseif ($operation['operationtype'] == OPERATION_TYPE_TEMPLATE_ADD
183				|| $operation['operationtype'] == OPERATION_TYPE_TEMPLATE_REMOVE) {
184			$operation['optemplate'] = [];
185
186			foreach ($operation['templateids'] as $templateid) {
187				$operation['optemplate'][] = ['templateid' => $templateid];
188			}
189			unset($operation['templateids']);
190		}
191	}
192	unset($operation);
193
194	$filter = [
195		'conditions' => getRequest('conditions', []),
196		'evaltype' => getRequest('evaltype')
197	];
198
199	if ($filter['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) {
200		if (count($filter['conditions']) > 1) {
201			$filter['formula'] = getRequest('formula');
202		}
203		else {
204			// if only one or no conditions are left, reset the evaltype to "and/or" and clear the formula
205			$filter['formula'] = '';
206			$filter['evaltype'] = CONDITION_EVAL_TYPE_AND_OR;
207		}
208	}
209	$action['filter'] = $filter;
210
211	$eventsource = getRequest('eventsource', CProfile::get('web.actionconf.eventsource', EVENT_SOURCE_TRIGGERS));
212
213	if ($eventsource == EVENT_SOURCE_TRIGGERS) {
214		$action['pause_suppressed'] = getRequest('pause_suppressed', ACTION_PAUSE_SUPPRESSED_FALSE);
215	}
216
217	DBstart();
218
219	if (hasRequest('update')) {
220		$action['actionid'] = getRequest('actionid');
221
222		$result = API::Action()->update($action);
223
224		$messageSuccess = _('Action updated');
225		$messageFailed = _('Cannot update action');
226	}
227	else {
228		$action['eventsource'] = $eventsource;
229
230		$result = API::Action()->create($action);
231
232		$messageSuccess = _('Action added');
233		$messageFailed = _('Cannot add action');
234	}
235
236	if ($result) {
237		unset($_REQUEST['form']);
238	}
239
240	$result = DBend($result);
241
242	if ($result) {
243		uncheckTableRows();
244	}
245	show_messages($result, $messageSuccess, $messageFailed);
246}
247elseif (hasRequest('delete') && hasRequest('actionid')) {
248	$result = API::Action()->delete([getRequest('actionid')]);
249
250	if ($result) {
251		unset($_REQUEST['form'], $_REQUEST['actionid']);
252		uncheckTableRows();
253	}
254	show_messages($result, _('Action deleted'), _('Cannot delete action'));
255}
256elseif (hasRequest('add_condition') && hasRequest('new_condition')) {
257	$newCondition = getRequest('new_condition');
258
259	if ($newCondition) {
260		$conditions = getRequest('conditions', []);
261
262		// When adding new condition, in order to check for an existing condition, it must have a not null value.
263		if ($newCondition['conditiontype'] == CONDITION_TYPE_SUPPRESSED) {
264			$newCondition['value'] = '';
265		}
266
267		// check existing conditions and remove duplicate condition values
268		foreach ($conditions as $condition) {
269			if ($newCondition['conditiontype'] == $condition['conditiontype']) {
270				if (is_array($newCondition['value'])) {
271					foreach ($newCondition['value'] as $key => $newValue) {
272						if ($condition['value'] == $newValue) {
273							unset($newCondition['value'][$key]);
274						}
275					}
276				}
277				else {
278					if ($newCondition['value'] == $condition['value'] && (!array_key_exists('value2', $newCondition)
279							|| $newCondition['value2'] === $condition['value2'])) {
280						$newCondition['value'] = null;
281					}
282				}
283			}
284		}
285
286		$usedFormulaIds = zbx_objectValues($conditions, 'formulaid');
287
288		$validateConditions = $conditions;
289
290		if (isset($newCondition['value'])) {
291			$newConditionValues = zbx_toArray($newCondition['value']);
292			foreach ($newConditionValues as $newValue) {
293				$condition = $newCondition;
294				$condition['value'] = $newValue;
295				$condition['formulaid'] = CConditionHelper::getNextFormulaId($usedFormulaIds);
296				$usedFormulaIds[] = $condition['formulaid'];
297				$validateConditions[] = $condition;
298			}
299		}
300
301		$conditionsValid = true;
302		if ($validateConditions) {
303			$filterConditionValidator = new CActionCondValidator();
304			foreach ($validateConditions as $condition) {
305				if (!$filterConditionValidator->validate($condition)) {
306					$conditionsValid = false;
307					break;
308				}
309			}
310		}
311
312		if ($conditionsValid) {
313			$_REQUEST['conditions'] = $validateConditions;
314		}
315		else {
316			error($filterConditionValidator->getError());
317			show_error_message(_('Cannot add action condition'));
318		}
319	}
320}
321elseif (hasRequest('add_opcondition') && hasRequest('new_opcondition')) {
322	$new_opcondition = getRequest('new_opcondition');
323
324	try {
325		CAction::validateOperationConditions($new_opcondition);
326		$new_operation = getRequest('new_operation', []);
327
328		if (!isset($new_operation['opconditions'])) {
329			$new_operation['opconditions'] = [];
330		}
331		if (!str_in_array($new_opcondition, $new_operation['opconditions'])) {
332			array_push($new_operation['opconditions'], $new_opcondition);
333		}
334
335		$_REQUEST['new_operation'] = $new_operation;
336
337		unset($_REQUEST['new_opcondition']);
338	}
339	catch (APIException $e) {
340		error($e->getMessage());
341	}
342}
343elseif (hasRequest('add_operation') && hasRequest('new_operation')) {
344	$new_operation = $_REQUEST['new_operation'];
345	$result = true;
346
347	switch ($new_operation['operationtype']) {
348		case OPERATION_TYPE_GROUP_ADD:
349		case OPERATION_TYPE_GROUP_REMOVE:
350			$new_operation['opgroup'] = [];
351
352			if (array_key_exists('groupids', $new_operation)) {
353				foreach ($new_operation['groupids'] as $groupid) {
354					$new_operation['opgroup'][] = ['groupid' => $groupid];
355				}
356				unset($new_operation['groupids']);
357			}
358			break;
359
360		case OPERATION_TYPE_TEMPLATE_ADD:
361		case OPERATION_TYPE_TEMPLATE_REMOVE:
362			$new_operation['optemplate'] = [];
363
364			if (array_key_exists('templateids', $new_operation)) {
365				foreach ($new_operation['templateids'] as $templateid) {
366					$new_operation['optemplate'][] = ['templateid' => $templateid];
367				}
368				unset($new_operation['templateids']);
369			}
370			break;
371	}
372
373	$eventsource = getRequest('eventsource', CProfile::get('web.actionconf.eventsource', EVENT_SOURCE_TRIGGERS));
374
375	$new_operation['recovery'] = ACTION_OPERATION;
376	$new_operation['eventsource'] = $eventsource;
377
378	if (API::Action()->validateOperationsIntegrity($new_operation)) {
379		$_REQUEST['operations'] = getRequest('operations', []);
380
381		$uniqOperations = [
382			OPERATION_TYPE_HOST_ADD => 0,
383			OPERATION_TYPE_HOST_REMOVE => 0,
384			OPERATION_TYPE_HOST_ENABLE => 0,
385			OPERATION_TYPE_HOST_DISABLE => 0,
386			OPERATION_TYPE_HOST_INVENTORY => 0
387		];
388
389		if (array_key_exists($new_operation['operationtype'], $uniqOperations)) {
390			$uniqOperations[$new_operation['operationtype']]++;
391
392			foreach ($_REQUEST['operations'] as $operationId => $operation) {
393				if (array_key_exists($operation['operationtype'], $uniqOperations)
394					&& (!array_key_exists('id', $new_operation)
395						|| bccomp($new_operation['id'], $operationId) != 0)) {
396					$uniqOperations[$operation['operationtype']]++;
397				}
398			}
399
400			if ($uniqOperations[$new_operation['operationtype']] > 1) {
401				$result = false;
402				error(_s('Operation "%s" already exists.', operation_type2str($new_operation['operationtype'])));
403				show_messages();
404			}
405		}
406
407		if ($result) {
408			if (isset($_REQUEST['new_operation']['id'])) {
409				$_REQUEST['operations'][$_REQUEST['new_operation']['id']] = $_REQUEST['new_operation'];
410			}
411			else {
412				$_REQUEST['operations'][] = $_REQUEST['new_operation'];
413			}
414
415			sortOperations($eventsource, $_REQUEST['operations']);
416		}
417
418		unset($_REQUEST['new_operation']);
419	}
420}
421elseif (hasRequest('add_recovery_operation') && hasRequest('new_recovery_operation')) {
422	$new_recovery_operation = getRequest('new_recovery_operation');
423
424	$eventsource = getRequest('eventsource', CProfile::get('web.actionconf.eventsource', EVENT_SOURCE_TRIGGERS));
425
426	$new_recovery_operation['recovery'] = ACTION_RECOVERY_OPERATION;
427	$new_recovery_operation['eventsource'] = $eventsource;
428
429	if (API::Action()->validateOperationsIntegrity($new_recovery_operation)) {
430		$_REQUEST['recovery_operations'] = getRequest('recovery_operations', []);
431
432		if (isset($_REQUEST['new_recovery_operation']['id'])) {
433			$_REQUEST['recovery_operations'][$_REQUEST['new_recovery_operation']['id']] = $_REQUEST['new_recovery_operation'];
434		}
435		else {
436			$_REQUEST['recovery_operations'][] = $_REQUEST['new_recovery_operation'];
437		}
438
439		unset($_REQUEST['new_recovery_operation']);
440	}
441}
442elseif (hasRequest('add_ack_operation') && $new_ack_operation) {
443	$new_ack_operation['recovery'] = ACTION_ACKNOWLEDGE_OPERATION;
444	$new_ack_operation['eventsource'] = EVENT_SOURCE_TRIGGERS;
445
446	if (API::Action()->validateOperationsIntegrity($new_ack_operation)) {
447		if (array_key_exists('id', $new_ack_operation)) {
448			$ack_operations[$new_ack_operation['id']] = $new_ack_operation;
449		}
450		else {
451			$ack_operations[] = $new_ack_operation;
452		}
453		$new_ack_operation = [];
454	}
455}
456elseif (hasRequest('edit_operationid')) {
457	$_REQUEST['edit_operationid'] = array_keys($_REQUEST['edit_operationid']);
458	$edit_operationid = $_REQUEST['edit_operationid'] = array_pop($_REQUEST['edit_operationid']);
459	$_REQUEST['operations'] = getRequest('operations', []);
460
461	if (isset($_REQUEST['operations'][$edit_operationid])) {
462		$_REQUEST['new_operation'] = $_REQUEST['operations'][$edit_operationid];
463		$_REQUEST['new_operation']['id'] = $edit_operationid;
464	}
465}
466elseif (hasRequest('edit_recovery_operationid')) {
467	$_REQUEST['edit_recovery_operationid'] = array_keys($_REQUEST['edit_recovery_operationid']);
468	$edit_recovery_operationid = array_pop($_REQUEST['edit_recovery_operationid']);
469	$_REQUEST['edit_recovery_operationid'] = $edit_recovery_operationid;
470	$_REQUEST['recovery_operations'] = getRequest('recovery_operations', []);
471
472	if (array_key_exists($edit_recovery_operationid, $_REQUEST['recovery_operations'])) {
473		$_REQUEST['new_recovery_operation'] = $_REQUEST['recovery_operations'][$edit_recovery_operationid];
474		$_REQUEST['new_recovery_operation']['id'] = $edit_recovery_operationid;
475	}
476}
477elseif (hasRequest('edit_ack_operationid')) {
478	$edit_ack_operationid = key(getRequest('edit_ack_operationid'));
479
480	if (array_key_exists($edit_ack_operationid, $ack_operations)) {
481		$new_ack_operation = $ack_operations[$edit_ack_operationid];
482		$new_ack_operation['id'] = $edit_ack_operationid;
483	}
484}
485elseif (hasRequest('action') && str_in_array(getRequest('action'), ['action.massenable', 'action.massdisable']) && hasRequest('g_actionid')) {
486	$status = (getRequest('action') == 'action.massenable') ? ACTION_STATUS_ENABLED : ACTION_STATUS_DISABLED;
487	$actionids = (array) getRequest('g_actionid', []);
488	$actions_count = count($actionids);
489	$actions = [];
490
491	foreach ($actionids as $actionid) {
492		$actions[] = ['actionid' => $actionid, 'status' => $status];
493	}
494
495	$result = API::Action()->update($actions);
496
497	if ($result && array_key_exists('actionids', $result)) {
498		$message = $status == ACTION_STATUS_ENABLED
499			? _n('Action enabled', 'Actions enabled', $actions_count)
500			: _n('Action disabled', 'Actions disabled', $actions_count);
501
502		show_messages(true, $message);
503		uncheckTableRows();
504	}
505	else {
506		$message = $status == ACTION_STATUS_ENABLED
507			? _n('Cannot enable action', 'Cannot enable actions', $actions_count)
508			: _n('Cannot disable action', 'Cannot disable actions', $actions_count);
509
510		show_messages(false, null, $message);
511	}
512}
513elseif (hasRequest('action') && getRequest('action') == 'action.massdelete' && hasRequest('g_actionid')) {
514	$result = API::Action()->delete(getRequest('g_actionid'));
515
516	if ($result) {
517		uncheckTableRows();
518	}
519	show_messages($result, _('Selected actions deleted'), _('Cannot delete selected actions'));
520}
521
522if (hasRequest('action') && hasRequest('g_actionid') && !$result) {
523	$actions = API::Action()->get([
524		'actionids' => getRequest('g_actionid'),
525		'output' => [],
526		'editable' => true
527	]);
528	uncheckTableRows(null, zbx_objectValues($actions, 'actionid'));
529}
530
531/*
532 * Display
533 */
534show_messages();
535
536$config = select_config();
537
538if (hasRequest('form')) {
539	$data = [
540		'form' => getRequest('form'),
541		'actionid' => getRequest('actionid'),
542		'new_condition' => getRequest('new_condition', []),
543		'new_operation' => getRequest('new_operation'),
544		'new_recovery_operation' => getRequest('new_recovery_operation'),
545		'new_ack_operation' => $new_ack_operation,
546		'config' => $config
547	];
548
549	if ($data['actionid']) {
550		$data['action'] = API::Action()->get([
551			'actionids' => $data['actionid'],
552			'selectOperations' => API_OUTPUT_EXTEND,
553			'selectRecoveryOperations' => ['operationid', 'actionid', 'operationtype', 'opmessage', 'opmessage_grp',
554				'opmessage_usr', 'opcommand', 'opcommand_hst', 'opcommand_grp'
555			],
556			'selectAcknowledgeOperations' => ['operationid', 'actionid', 'operationtype', 'opmessage', 'opmessage_grp',
557				'opmessage_usr', 'opcommand', 'opcommand_hst', 'opcommand_grp'
558			],
559			'selectFilter' => ['formula', 'conditions', 'evaltype'],
560			'output' => API_OUTPUT_EXTEND,
561			'editable' => true
562		]);
563		$data['action'] = reset($data['action']);
564
565		$data['action']['recovery_operations'] = $data['action']['recoveryOperations'];
566		$data['action']['ack_operations'] = $data['action']['acknowledgeOperations'];
567		unset($data['action']['recoveryOperations'], $data['action']['acknowledgeOperations']);
568
569		foreach ($data['action']['operations'] as &$operation) {
570			if ($operation['operationtype'] == OPERATION_TYPE_GROUP_ADD
571					|| $operation['operationtype'] == OPERATION_TYPE_GROUP_REMOVE) {
572				$operation = [
573					'actionid' => $operation['actionid'],
574					'operationid' => $operation['operationid'],
575					'operationtype' => $operation['operationtype'],
576					'groupids' => zbx_objectValues($operation['opgroup'], 'groupid')
577				];
578			}
579			elseif ($operation['operationtype'] == OPERATION_TYPE_TEMPLATE_ADD
580					|| $operation['operationtype'] == OPERATION_TYPE_TEMPLATE_REMOVE) {
581				$operation = [
582					'actionid' => $operation['actionid'],
583					'operationid' => $operation['operationid'],
584					'operationtype' => $operation['operationtype'],
585					'templateids' => zbx_objectValues($operation['optemplate'], 'templateid')
586				];
587			}
588		}
589		unset($operation);
590
591		$data['eventsource'] = $data['action']['eventsource'];
592	}
593	else {
594		$data['eventsource'] = getRequest('eventsource',
595			CProfile::get('web.actionconf.eventsource', EVENT_SOURCE_TRIGGERS)
596		);
597		$data['esc_period'] = getRequest('esc_period');
598	}
599
600	if (array_key_exists('action', $data) && array_key_exists('actionid', $data['action'])
601			&& !hasRequest('form_refresh')) {
602		sortOperations($data['eventsource'], $data['action']['operations']);
603	}
604	else {
605		$data['action']['name'] = getRequest('name');
606		$data['action']['esc_period'] = getRequest('esc_period', DB::getDefault('actions', 'esc_period'));
607		$data['action']['status'] = getRequest('status', hasRequest('form_refresh') ? 1 : 0);
608		$data['action']['operations'] = getRequest('operations', []);
609		$data['action']['recovery_operations'] = getRequest('recovery_operations', []);
610		$data['action']['ack_operations'] = $ack_operations;
611
612		$data['action']['filter']['evaltype'] = getRequest('evaltype');
613		$data['action']['filter']['formula'] = getRequest('formula');
614		$data['action']['filter']['conditions'] = getRequest('conditions', []);
615
616		if ($data['actionid'] && hasRequest('form_refresh')) {
617			$data['action']['def_shortdata'] = getRequest('def_shortdata', '');
618			$data['action']['def_longdata'] = getRequest('def_longdata', '');
619			$data['action']['r_shortdata'] = getRequest('r_shortdata', '');
620			$data['action']['r_longdata'] = getRequest('r_longdata', '');
621			$data['action']['ack_shortdata'] = getRequest('ack_shortdata', '');
622			$data['action']['ack_longdata'] = getRequest('ack_longdata', '');
623
624			if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS) {
625				$data['action']['pause_suppressed'] = getRequest('pause_suppressed', ACTION_PAUSE_SUPPRESSED_FALSE);
626			}
627		}
628		else {
629			if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS) {
630				$data['action']['def_shortdata'] = getRequest('def_shortdata', ACTION_DEFAULT_SUBJ_PROBLEM);
631				$data['action']['def_longdata'] = getRequest('def_longdata', ACTION_DEFAULT_MSG_PROBLEM);
632				$data['action']['r_shortdata'] = getRequest('r_shortdata', ACTION_DEFAULT_SUBJ_RECOVERY);
633				$data['action']['r_longdata'] = getRequest('r_longdata', ACTION_DEFAULT_MSG_RECOVERY);
634				$data['action']['ack_shortdata'] = getRequest('ack_shortdata', ACTION_DEFAULT_SUBJ_ACKNOWLEDGE);
635				$data['action']['ack_longdata'] = getRequest('ack_longdata', ACTION_DEFAULT_MSG_ACKNOWLEDGE);
636				$data['action']['pause_suppressed'] = getRequest('pause_suppressed',
637					hasRequest('form_refresh') ? ACTION_PAUSE_SUPPRESSED_FALSE : ACTION_PAUSE_SUPPRESSED_TRUE
638				);
639			}
640			elseif ($data['eventsource'] == EVENT_SOURCE_DISCOVERY) {
641				$data['action']['def_shortdata'] = getRequest('def_shortdata', ACTION_DEFAULT_SUBJ_DISCOVERY);
642				$data['action']['def_longdata'] = getRequest('def_longdata', ACTION_DEFAULT_MSG_DISCOVERY);
643			}
644			elseif ($data['eventsource'] == EVENT_SOURCE_AUTO_REGISTRATION) {
645				$data['action']['def_shortdata'] = getRequest('def_shortdata', ACTION_DEFAULT_SUBJ_AUTOREG);
646				$data['action']['def_longdata'] = getRequest('def_longdata', ACTION_DEFAULT_MSG_AUTOREG);
647			}
648			else {
649				$data['action']['def_shortdata'] = getRequest('def_shortdata', '');
650				$data['action']['def_longdata'] = getRequest('def_longdata', '');
651				$data['action']['r_shortdata'] = getRequest('r_shortdata', '');
652				$data['action']['r_longdata'] = getRequest('r_longdata', '');
653				$data['action']['ack_shortdata'] = getRequest('ack_shortdata', '');
654				$data['action']['ack_longdata'] = getRequest('ack_longdata', '');
655			}
656		}
657	}
658
659	$data['allowedConditions'] = get_conditions_by_eventsource($data['eventsource']);
660	$data['allowedOperations'] = getAllowedOperations($data['eventsource']);
661
662	if (!hasRequest('add_condition')) {
663		$data['action']['filter']['conditions'] = CConditionHelper::sortConditionsByFormulaId(
664			$data['action']['filter']['conditions']
665		);
666	}
667
668	// Add default values for new condition.
669	$data['new_condition'] += [
670		'conditiontype'	=> CONDITION_TYPE_TRIGGER_NAME,
671		'operator'		=> CONDITION_OPERATOR_LIKE,
672		'value'			=> ''
673	];
674
675	if (!str_in_array($data['new_condition']['conditiontype'], $data['allowedConditions'])) {
676		$data['new_condition']['conditiontype'] = $data['allowedConditions'][0];
677	}
678
679	// New operation.
680	if ($data['new_operation'] && !is_array($data['new_operation'])) {
681		$data['new_operation'] = [
682			'operationtype' => OPERATION_TYPE_MESSAGE,
683			'esc_period' => '0',
684			'esc_step_from' => 1,
685			'esc_step_to' => 1,
686			'evaltype' => 0
687		];
688	}
689
690	if (is_array($data['new_operation'])) {
691		switch ($data['new_operation']['operationtype']) {
692			case OPERATION_TYPE_GROUP_ADD:
693			case OPERATION_TYPE_GROUP_REMOVE:
694				if (!array_key_exists('groupids', $data['new_operation'])) {
695					$data['new_operation']['groupids'] = [];
696				}
697
698				if ($data['new_operation']['groupids']) {
699					$data['new_operation']['groups'] = API::HostGroup()->get([
700						'groupids' => $data['new_operation']['groupids'],
701						'output' => ['groupid', 'name'],
702						'editable' => true
703					]);
704
705					foreach ($data['new_operation']['groups'] as &$group) {
706						$group['id'] = $group['groupid'];
707						unset($group['groupid']);
708					}
709					unset($group);
710				}
711				else {
712					$data['new_operation']['groups'] = [];
713				}
714				break;
715
716			case OPERATION_TYPE_TEMPLATE_ADD:
717			case OPERATION_TYPE_TEMPLATE_REMOVE:
718				if (!array_key_exists('templateids', $data['new_operation'])) {
719					$data['new_operation']['templateids'] = [];
720				}
721
722				if ($data['new_operation']['templateids']) {
723					$data['new_operation']['templates'] = API::Template()->get([
724						'templateids' => $data['new_operation']['templateids'],
725						'output' => ['templateid', 'name'],
726						'editable' => true
727					]);
728
729					foreach ($data['new_operation']['templates'] as &$template) {
730						$template['id'] = $template['templateid'];
731						unset($template['templateid']);
732					}
733					unset($template);
734				}
735				else {
736					$data['new_operation']['templates'] = [];
737				}
738				break;
739
740			case OPERATION_TYPE_HOST_INVENTORY:
741				if (!array_key_exists('opinventory', $data['new_operation'])) {
742					$data['new_operation']['opinventory'] = ['inventory_mode' => HOST_INVENTORY_MANUAL];
743				}
744				break;
745		}
746	}
747
748	// New recovery operation.
749	if ($data['new_recovery_operation'] && !is_array($data['new_recovery_operation'])) {
750		$data['new_recovery_operation'] = ['operationtype' => OPERATION_TYPE_MESSAGE];
751	}
752
753	$data['available_mediatypes'] = API::MediaType()->get(['output' => ['mediatypeid', 'description', 'status']]);
754	order_result($data['available_mediatypes'], 'description');
755
756	if ($data['new_ack_operation'] && !is_array($data['new_ack_operation'])) {
757		$data['new_ack_operation'] = [
758			'operationtype' => OPERATION_TYPE_MESSAGE,
759			'ack_short' => ACTION_DEFAULT_SUBJ_ACKNOWLEDGE,
760			'ack_long' => ACTION_DEFAULT_MSG_ACKNOWLEDGE
761		];
762	}
763	if ($data['new_ack_operation'] && !array_key_exists('opmessage', $data['new_ack_operation'])
764			&& $data['new_ack_operation']['operationtype'] != OPERATION_TYPE_COMMAND) {
765		$data['new_ack_operation']['opmessage'] = [
766			'default_msg'	=> 1,
767			'mediatypeid'	=> 0,
768			'subject'	=> ACTION_DEFAULT_SUBJ_ACKNOWLEDGE,
769			'message'	=> ACTION_DEFAULT_MSG_ACKNOWLEDGE
770		];
771	}
772
773	// Render view.
774	$actionView = new CView('configuration.action.edit', $data);
775	$actionView->render();
776	$actionView->show();
777}
778else {
779	$sortField = getRequest('sort', CProfile::get('web.'.$page['file'].'.sort', 'name'));
780	$sortOrder = getRequest('sortorder', CProfile::get('web.'.$page['file'].'.sortorder', ZBX_SORT_UP));
781
782	CProfile::update('web.'.$page['file'].'.sort', $sortField, PROFILE_TYPE_STR);
783	CProfile::update('web.'.$page['file'].'.sortorder', $sortOrder, PROFILE_TYPE_STR);
784
785	// filter
786	if (hasRequest('filter_set')) {
787		CProfile::update('web.actionconf.filter_name', getRequest('filter_name', ''), PROFILE_TYPE_STR);
788		CProfile::update('web.actionconf.filter_status', getRequest('filter_status', -1), PROFILE_TYPE_INT);
789	}
790	elseif (hasRequest('filter_rst')) {
791		CProfile::delete('web.actionconf.filter_name');
792		CProfile::delete('web.actionconf.filter_status');
793	}
794
795	$filter = [
796		'name' => CProfile::get('web.actionconf.filter_name', ''),
797		'status' => CProfile::get('web.actionconf.filter_status', -1)
798	];
799
800	$data = [
801		'eventsource' => getRequest('eventsource', CProfile::get('web.actionconf.eventsource', EVENT_SOURCE_TRIGGERS)),
802		'sort' => $sortField,
803		'sortorder' => $sortOrder,
804		'filter' => $filter,
805		'config' => $config,
806		'profileIdx' => 'web.actionconf.filter',
807		'active_tab' => CProfile::get('web.actionconf.filter.active', 1)
808	];
809
810	$data['actions'] = API::Action()->get([
811		'output' => API_OUTPUT_EXTEND,
812		'search' => [
813			'name' => ($filter['name'] === '') ? null : $filter['name']
814		],
815		'filter' => [
816			'eventsource' => $data['eventsource'],
817			'status' => ($filter['status'] == -1) ? null : $filter['status']
818		],
819		'selectFilter' => ['formula', 'conditions', 'evaltype'],
820		'selectOperations' => API_OUTPUT_EXTEND,
821		'editable' => true,
822		'sortfield' => $sortField,
823		'limit' => $config['search_limit'] + 1
824	]);
825
826	foreach ($data['actions'] as &$action) {
827		foreach ($action['operations'] as &$operation) {
828			switch ($operation['operationtype']) {
829				case OPERATION_TYPE_GROUP_ADD:
830				case OPERATION_TYPE_GROUP_REMOVE:
831					$operation = [
832						'operationtype' => $operation['operationtype'],
833						'groupids' => zbx_objectValues($operation['opgroup'], 'groupid')
834					];
835					break;
836
837				case OPERATION_TYPE_TEMPLATE_ADD:
838				case OPERATION_TYPE_TEMPLATE_REMOVE:
839					$operation = [
840						'operationtype' => $operation['operationtype'],
841						'templateids' => zbx_objectValues($operation['optemplate'], 'templateid')
842					];
843					break;
844			}
845		}
846		unset($operation);
847	}
848	unset($action);
849
850	// sorting && paging
851	order_result($data['actions'], $sortField, $sortOrder);
852	$data['paging'] = getPagingLine($data['actions'], $sortOrder, new CUrl('actionconf.php'));
853
854	// render view
855	$actionView = new CView('configuration.action.list', $data);
856	$actionView->render();
857	$actionView->show();
858}
859
860require_once dirname(__FILE__).'/include/page_footer.php';
861