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
22/**
23 * @var CView $this
24 */
25
26require_once dirname(__FILE__).'/js/configuration.action.edit.js.php';
27
28$widget = (new CWidget())->setTitle(_('Actions'));
29
30// create form
31$actionForm = (new CForm())
32	->setId('action-form')
33	->setName('action.edit')
34	->setAction((new CUrl('actionconf.php'))
35		->setArgument('eventsource', $data['eventsource'])
36		->getUrl()
37	)
38	->setAttribute('aria-labeledby', ZBX_STYLE_PAGE_TITLE)
39	->addVar('form', $data['form']);
40
41if ($data['actionid']) {
42	$actionForm->addVar('actionid', $data['actionid']);
43}
44
45// Action tab.
46$action_tab = (new CFormList())
47	->addRow(
48		(new CLabel(_('Name'), 'name'))->setAsteriskMark(),
49		(new CTextBox('name', $data['action']['name']))
50			->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH)
51			->setAriaRequired()
52			->setAttribute('autofocus', 'autofocus')
53	);
54
55// Create condition table.
56$condition_table = (new CTable(_('No conditions defined.')))
57	->setId('conditionTable')
58	->setAttribute('style', 'width: 100%;')
59	->setHeader([_('Label'), _('Name'), _('Action')]);
60
61$i = 0;
62
63if ($data['action']['filter']['conditions']) {
64	$actionConditionStringValues = actionConditionValueToString([$data['action']]);
65
66	foreach ($data['action']['filter']['conditions'] as $cIdx => $condition) {
67		if (!isset($condition['conditiontype'])) {
68			$condition['conditiontype'] = 0;
69		}
70		if (!isset($condition['operator'])) {
71			$condition['operator'] = 0;
72		}
73		if (!isset($condition['value'])) {
74			$condition['value'] = '';
75		}
76		if (!array_key_exists('value2', $condition)) {
77			$condition['value2'] = '';
78		}
79		if (!str_in_array($condition['conditiontype'], $data['allowedConditions'])) {
80			continue;
81		}
82
83		$label = isset($condition['formulaid']) ? $condition['formulaid'] : num2letter($i);
84
85		$labelSpan = (new CSpan($label))
86			->addClass('label')
87			->setAttribute('data-conditiontype', $condition['conditiontype'])
88			->setAttribute('data-formulaid', $label);
89
90		$condition_table->addRow(
91			[
92				$labelSpan,
93				(new CCol(getConditionDescription($condition['conditiontype'], $condition['operator'],
94					$actionConditionStringValues[0][$cIdx], $condition['value2']
95				)))->addClass(ZBX_STYLE_TABLE_FORMS_OVERFLOW_BREAK),
96				(new CCol([
97					(new CButton('remove', _('Remove')))
98						->onClick('javascript: removeCondition('.$i.');')
99						->addClass(ZBX_STYLE_BTN_LINK)
100						->removeId(),
101					new CVar('conditions['.$i.']', $condition)
102				]))->addClass(ZBX_STYLE_NOWRAP)
103			],
104			null, 'conditions_'.$i
105		);
106
107		$i++;
108	}
109}
110
111$formula = (new CTextBox('formula', $data['action']['filter']['formula']))
112	->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH)
113	->setId('formula')
114	->setAttribute('placeholder', 'A or (B and C) &hellip;');
115
116$action_tab->addRow(new CLabel(_('Type of calculation'), 'label-evaltype'), [
117	(new CSelect('evaltype'))
118		->setId('evaltype')
119		->setFocusableElementId('label-evaltype')
120		->setValue($data['action']['filter']['evaltype'])
121		->addOptions(CSelect::createOptionsFromArray([
122			CONDITION_EVAL_TYPE_AND_OR => _('And/Or'),
123			CONDITION_EVAL_TYPE_AND => _('And'),
124			CONDITION_EVAL_TYPE_OR => _('Or'),
125			CONDITION_EVAL_TYPE_EXPRESSION => _('Custom expression')
126		])),
127	(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
128	(new CSpan())->setId('conditionLabel'),
129	$formula
130]);
131
132$condition_table->addRow([
133	(new CSimpleButton(_('Add')))
134		->onClick('return PopUp("popup.condition.actions",'.json_encode([
135			'type' => ZBX_POPUP_CONDITION_TYPE_ACTION,
136			'source' => $data['eventsource']
137		]).', null, this);')
138		->addClass(ZBX_STYLE_BTN_LINK)
139]);
140
141$action_tab->addRow(_('Conditions'),
142	(new CDiv($condition_table))
143		->addClass(ZBX_STYLE_TABLE_FORMS_SEPARATOR)
144		->setAttribute('style', 'min-width: '.ZBX_TEXTAREA_BIG_WIDTH.'px;')
145);
146
147$action_tab->addRow(_('Enabled'),
148	(new CCheckBox('status', ACTION_STATUS_ENABLED))->setChecked($data['action']['status'] == ACTION_STATUS_ENABLED)
149);
150
151// Operations tab.
152$operation_tab = new CFormList();
153
154if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS || $data['eventsource'] == EVENT_SOURCE_INTERNAL) {
155	$operation_tab->addRow((new CLabel(_('Default operation step duration'), 'esc_period'))->setAsteriskMark(),
156		(new CTextBox('esc_period', $data['action']['esc_period']))
157			->setWidth(ZBX_TEXTAREA_SMALL_WIDTH)
158			->setAriaRequired()
159	);
160}
161
162if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS) {
163	$operation_tab->addRow(_('Pause operations for suppressed problems'),
164		(new CCheckBox('pause_suppressed', ACTION_PAUSE_SUPPRESSED_TRUE))
165			->setChecked($data['action']['pause_suppressed'] == ACTION_PAUSE_SUPPRESSED_TRUE)
166	);
167}
168
169// create operation table
170$operations_table = (new CTable())
171	->setId('op-table')
172	->setAttribute('style', 'width: 100%;');
173if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS || $data['eventsource'] == EVENT_SOURCE_INTERNAL) {
174	$operations_table->setHeader([_('Steps'), _('Details'), _('Start in'), _('Duration'), _('Action')]);
175	$delays = count_operations_delay($data['action']['operations'], $data['action']['esc_period']);
176}
177else {
178	$operations_table->setHeader([_('Details'), _('Action')]);
179}
180
181if ($data['action']['operations']) {
182	$actionOperationDescriptions = getActionOperationDescriptions([$data['action']], ACTION_OPERATION);
183
184	$simple_interval_parser = new CSimpleIntervalParser();
185
186	foreach ($data['action']['operations'] as $operationid => $operation) {
187		if (!str_in_array($operation['operationtype'], $data['allowedOperations'][ACTION_OPERATION])) {
188			continue;
189		}
190
191		if (array_key_exists('opcommand', $operation)) {
192			$operation['opcommand'] += [
193				'scriptid' => '0'
194			];
195		}
196
197		if (!isset($operation['opconditions'])) {
198			$operation['opconditions'] = [];
199		}
200		if (!isset($operation['mediatypeid'])) {
201			$operation['mediatypeid'] = 0;
202		}
203
204		$details = new CSpan($actionOperationDescriptions[0][$operationid]);
205
206		$operation_for_popup = array_merge($operation, ['id' => $operationid]);
207		foreach (['opcommand_grp' => 'groupid', 'opcommand_hst' => 'hostid'] as $var => $field) {
208			if (array_key_exists($var, $operation_for_popup)) {
209				$operation_for_popup[$var] = zbx_objectValues($operation_for_popup[$var], $field);
210			}
211		}
212
213		if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS || $data['eventsource'] == EVENT_SOURCE_INTERNAL) {
214			$esc_steps_txt = null;
215			$esc_period_txt = null;
216			$esc_delay_txt = null;
217
218			if ($operation['esc_step_from'] < 1) {
219				$operation['esc_step_from'] = 1;
220			}
221
222			$esc_steps_txt = $operation['esc_step_from'].' - '.$operation['esc_step_to'];
223
224			// display N-N as N
225			$esc_steps_txt = ($operation['esc_step_from'] == $operation['esc_step_to'])
226				? $operation['esc_step_from']
227				: $operation['esc_step_from'].' - '.$operation['esc_step_to'];
228
229			$esc_period_txt = ($simple_interval_parser->parse($operation['esc_period']) == CParser::PARSE_SUCCESS
230					&& timeUnitToSeconds($operation['esc_period']) == 0)
231				? _('Default')
232				: $operation['esc_period'];
233
234			$esc_delay_txt = ($delays[$operation['esc_step_from']] === null)
235				? _('Unknown')
236				: ($delays[$operation['esc_step_from']] != 0
237					? convertUnits(['value' => $delays[$operation['esc_step_from']], 'units' => 'uptime'])
238					: _('Immediately')
239				);
240
241			$operation_row = [
242				$esc_steps_txt,
243				$details,
244				$esc_delay_txt,
245				$esc_period_txt,
246				(new CCol(
247					new CHorList([
248						(new CSimpleButton(_('Edit')))
249							->addClass(ZBX_STYLE_BTN_LINK)
250							->addClass('js-edit-button')
251							->setAttribute('data-operation', json_encode([
252								'operationid' => $operationid,
253								'actionid' => $data['actionid'],
254								'eventsource' => $data['eventsource'],
255								'operationtype' => ACTION_OPERATION
256							])),
257						[
258							(new CButton('remove', _('Remove')))
259								->onClick('removeOperation('.$operationid.', '.ACTION_OPERATION.');')
260								->addClass(ZBX_STYLE_BTN_LINK)
261								->removeId(),
262							new CVar('operations['.$operationid.']', $operation),
263							new CVar('operations_for_popup['.ACTION_OPERATION.']['.$operationid.']',
264								json_encode($operation_for_popup)
265							)
266						]
267					])
268				))->addClass(ZBX_STYLE_NOWRAP)
269			];
270		}
271		else {
272			$operation_row = [
273				$details,
274				(new CCol(
275					new CHorList([
276						(new CSimpleButton(_('Edit')))
277							->addClass(ZBX_STYLE_BTN_LINK)
278							->addClass('js-edit-button')
279							->setAttribute('data-operation', json_encode([
280								'operationid' => $operationid,
281								'actionid' => $data['actionid'],
282								'eventsource' => $data['eventsource'],
283								'operationtype' => ACTION_OPERATION
284							])),
285						[
286							(new CButton('remove', _('Remove')))
287								->onClick('removeOperation('.$operationid.', '.ACTION_OPERATION.');')
288								->addClass(ZBX_STYLE_BTN_LINK)
289								->removeId(),
290							new CVar('operations['.$operationid.']', $operation),
291							new CVar('operations_for_popup['.ACTION_OPERATION.']['.$operationid.']',
292								json_encode($operation_for_popup)
293							)
294						]
295					])
296				))->addClass(ZBX_STYLE_NOWRAP)
297			];
298		}
299		$operations_table->addRow($operation_row, null, 'operations_'.$operationid);
300	}
301}
302
303$operations_table->addRow(
304	(new CSimpleButton(_('Add')))
305		->onClick('operation_details.open(this,'.$data['actionid'].','.$data['eventsource'].','.ACTION_OPERATION.')')
306		->addClass(ZBX_STYLE_BTN_LINK)
307);
308
309$operation_tab->addRow(_('Operations'),
310	(new CDiv($operations_table))
311		->addClass(ZBX_STYLE_TABLE_FORMS_SEPARATOR)
312		->setAttribute('style', 'min-width: '.ZBX_TEXTAREA_BIG_WIDTH.'px;')
313);
314
315// Recovery operation tab.
316if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS || $data['eventsource'] == EVENT_SOURCE_INTERNAL) {
317	// Create operation table.
318	$operations_table = (new CTable())
319		->setId('rec-table')
320		->setAttribute('style', 'width: 100%;');
321	$operations_table->setHeader([_('Details'), _('Action')]);
322
323	if ($data['action']['recovery_operations']) {
324		$actionOperationDescriptions = getActionOperationDescriptions([$data['action']], ACTION_RECOVERY_OPERATION);
325
326		foreach ($data['action']['recovery_operations'] as $operationid => $operation) {
327			if (!str_in_array($operation['operationtype'], $data['allowedOperations'][ACTION_RECOVERY_OPERATION])) {
328				continue;
329			}
330			if (!isset($operation['opconditions'])) {
331				$operation['opconditions'] = [];
332			}
333
334			if (!array_key_exists('opmessage', $operation)) {
335				$operation['opmessage'] = [];
336			}
337
338			$operation['opmessage'] += [
339				'mediatypeid' => '0',
340				'message' => '',
341				'subject' => '',
342				'default_msg' => '1'
343			];
344
345			$details = new CSpan($actionOperationDescriptions[0][$operationid]);
346
347			$operation_for_popup = array_merge($operation, ['id' => $operationid]);
348			foreach (['opcommand_grp' => 'groupid', 'opcommand_hst' => 'hostid'] as $var => $field) {
349				if (array_key_exists($var, $operation_for_popup)) {
350					$operation_for_popup[$var] = zbx_objectValues($operation_for_popup[$var], $field);
351				}
352			}
353
354			$operations_table->addRow([
355				$details,
356				(new CCol(
357					new CHorList([
358						(new CSimpleButton(_('Edit')))
359							->addClass(ZBX_STYLE_BTN_LINK)
360							->addClass('js-edit-button')
361							->setAttribute('data-operation', json_encode([
362								'operationid' => $operationid,
363								'actionid' => $data['actionid'],
364								'eventsource' => $data['eventsource'],
365								'operationtype' => ACTION_RECOVERY_OPERATION
366							])),
367						[
368							(new CButton('remove', _('Remove')))
369								->onClick(
370									'javascript: removeOperation('.$operationid.', '.ACTION_RECOVERY_OPERATION.');'
371								)
372								->addClass(ZBX_STYLE_BTN_LINK)
373								->removeId(),
374							new CVar('recovery_operations['.$operationid.']', $operation),
375							new CVar('operations_for_popup['.ACTION_RECOVERY_OPERATION.']['.$operationid.']',
376								json_encode($operation_for_popup)
377							)
378						]
379					])
380				))->addClass(ZBX_STYLE_NOWRAP)
381			], null, 'recovery_operations_'.$operationid);
382		}
383	}
384
385	$operations_table->addRow(
386		(new CSimpleButton(_('Add')))
387			->onClick('operation_details.open(this,'.$data['actionid'].','.$data['eventsource'].','.
388				ACTION_RECOVERY_OPERATION.')'
389			)
390			->addClass(ZBX_STYLE_BTN_LINK)
391	);
392
393	$operation_tab->addRow(_('Recovery operations'),
394		(new CDiv($operations_table))
395			->addClass(ZBX_STYLE_TABLE_FORMS_SEPARATOR)
396			->setAttribute('style', 'min-width: '.ZBX_TEXTAREA_BIG_WIDTH.'px;')
397	);
398}
399
400// Acknowledge operations
401if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS) {
402	$action_formname = $actionForm->getName();
403
404	$operations_table = (new CTable())
405		->setId('ack-table')
406		->setAttribute('style', 'width: 100%;');
407	$operations_table->setHeader([_('Details'), _('Action')]);
408
409	if ($data['action']['ack_operations']) {
410		$operation_descriptions = getActionOperationDescriptions([$data['action']], ACTION_ACKNOWLEDGE_OPERATION);
411
412		foreach ($data['action']['ack_operations'] as $operationid => $operation) {
413			if (!str_in_array($operation['operationtype'], $data['allowedOperations'][ACTION_ACKNOWLEDGE_OPERATION])) {
414				continue;
415			}
416			$operation += [
417				'opconditions'	=> [],
418				'mediatypeid'	=> 0
419			];
420
421			$details = new CSpan($operation_descriptions[0][$operationid]);
422
423			$operation_for_popup = array_merge($operation, ['id' => $operationid]);
424			foreach (['opcommand_grp' => 'groupid', 'opcommand_hst' => 'hostid'] as $var => $field) {
425				if (array_key_exists($var, $operation_for_popup)) {
426					$operation_for_popup[$var] = zbx_objectValues($operation_for_popup[$var], $field);
427				}
428			}
429
430			$operations_table->addRow([
431				$details,
432				(new CCol(
433					new CHorList([
434						(new CSimpleButton(_('Edit')))
435							->addClass(ZBX_STYLE_BTN_LINK)
436							->addClass('js-edit-button')
437							->setAttribute('data-operation', json_encode([
438								'operationid' => $operationid,
439								'actionid' => $data['actionid'],
440								'eventsource' => $data['eventsource'],
441								'operationtype' => ACTION_ACKNOWLEDGE_OPERATION
442							])),
443						[
444							(new CButton('remove', _('Remove')))
445								->onClick('javascript: removeOperation('.$operationid.', '.ACTION_ACKNOWLEDGE_OPERATION.
446									');'
447								)
448								->addClass(ZBX_STYLE_BTN_LINK)
449								->removeId(),
450							new CVar('ack_operations['.$operationid.']', $operation),
451							new CVar('operations_for_popup['.ACTION_ACKNOWLEDGE_OPERATION.']['.$operationid.']',
452								json_encode($operation_for_popup)
453							)
454						]
455					])
456				))->addClass(ZBX_STYLE_NOWRAP)
457			], null, 'ack_operations_'.$operationid);
458		}
459	}
460
461	$operations_table->addRow(
462		(new CSimpleButton(_('Add')))
463			->onClick('operation_details.open(this,'.$data['actionid'].','.$data['eventsource'].','.
464				ACTION_ACKNOWLEDGE_OPERATION.')'
465			)
466			->addClass(ZBX_STYLE_BTN_LINK)
467	);
468
469	$operation_tab->addRow(_('Update operations'),
470		(new CDiv($operations_table))
471			->addClass(ZBX_STYLE_TABLE_FORMS_SEPARATOR)
472			->addStyle('min-width: '.ZBX_TEXTAREA_BIG_WIDTH.'px;')
473	);
474}
475
476// Append tabs to form.
477$action_tabs = (new CTabView())
478	->addTab('actionTab', _('Action'), $action_tab)
479	->addTab('operationTab', _('Operations'), $operation_tab, TAB_INDICATOR_OPERATIONS);
480
481if (!hasRequest('form_refresh')) {
482	$action_tabs->setSelected(0);
483}
484
485// Append buttons to form.
486$others = [];
487if ($data['actionid']) {
488	$form_buttons = [
489		new CSubmit('update', _('Update')), [
490			new CButton('clone', _('Clone')),
491			new CButtonDelete(
492				_('Delete current action?'),
493				url_param('form').url_param('eventsource').url_param('actionid')
494			),
495			new CButtonCancel(url_param('actiontype').url_param('eventsource'))
496		]
497	];
498}
499else {
500	$form_buttons = [
501		new CSubmit('add', _('Add')),
502		[new CButtonCancel(url_param('actiontype').url_param('eventsource'))]
503	];
504}
505
506$action_tabs->setFooter([
507	(new CList())
508		->addClass(ZBX_STYLE_TABLE_FORMS)
509		->addItem([
510			new CDiv(''),
511			(new CDiv((new CLabel(_('At least one operation must exist.')))->setAsteriskMark()))
512				->addClass(ZBX_STYLE_TABLE_FORMS_TD_RIGHT)
513		]),
514	makeFormFooter($form_buttons[0], $form_buttons[1])
515]);
516$actionForm->addItem($action_tabs);
517
518// Append form to widget.
519$widget->addItem($actionForm);
520
521$widget->show();
522