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/triggers.inc.php'; 25require_once dirname(__FILE__).'/include/forms.inc.php'; 26 27$page['title'] = _('Configuration of triggers'); 28$page['file'] = 'triggers.php'; 29$page['scripts'] = ['multiselect.js']; 30 31require_once dirname(__FILE__).'/include/page_header.php'; 32 33// VAR TYPE OPTIONAL FLAGS VALIDATION EXCEPTION 34$fields = [ 35 'groupid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, null], 36 'hostid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, null], 37 'triggerid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, '(isset({form}) && ({form} == "update"))'], 38 'copy_type' => [T_ZBX_INT, O_OPT, P_SYS, 39 IN([COPY_TYPE_TO_HOST_GROUP, COPY_TYPE_TO_HOST, 40 COPY_TYPE_TO_TEMPLATE 41 ]), 42 'isset({copy})' 43 ], 44 'copy_mode' => [T_ZBX_INT, O_OPT, P_SYS, IN('0'), null], 45 'type' => [T_ZBX_INT, O_OPT, null, IN('0,1'), null], 46 'description' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 'isset({add}) || isset({update})', _('Name')], 47 'expression' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, 'isset({add}) || isset({update})', _('Expression')], 48 'recovery_expression' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, '(isset({add}) || isset({update})) && isset({recovery_mode}) && {recovery_mode} == '.ZBX_RECOVERY_MODE_RECOVERY_EXPRESSION.'', _('Recovery expression')], 49 'recovery_mode' => [T_ZBX_INT, O_OPT, null, IN(ZBX_RECOVERY_MODE_EXPRESSION.','.ZBX_RECOVERY_MODE_RECOVERY_EXPRESSION.','.ZBX_RECOVERY_MODE_NONE), null], 50 'priority' => [T_ZBX_INT, O_OPT, null, IN('0,1,2,3,4,5'), 'isset({add}) || isset({update})'], 51 'comments' => [T_ZBX_STR, O_OPT, null, null, 'isset({add}) || isset({update})'], 52 'url' => [T_ZBX_STR, O_OPT, null, null, 'isset({add}) || isset({update})'], 53 'correlation_mode' => [T_ZBX_STR, O_OPT, null, IN(ZBX_TRIGGER_CORRELATION_NONE.','.ZBX_TRIGGER_CORRELATION_TAG), null], 54 'correlation_tag' => [T_ZBX_STR, O_OPT, null, null, 'isset({add}) || isset({update})'], 55 'status' => [T_ZBX_STR, O_OPT, null, null, null], 56 'expression_constructor' => [T_ZBX_INT, O_OPT, null, NOT_EMPTY, 'isset({toggle_expression_constructor})'], 57 'recovery_expression_constructor' => [T_ZBX_INT, O_OPT, null, NOT_EMPTY, 'isset({toggle_recovery_expression_constructor})'], 58 'expr_temp' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, '(isset({add_expression}) || isset({and_expression}) || isset({or_expression}) || isset({replace_expression}))', _('Expression')], 59 'expr_target_single' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, '(isset({and_expression}) || isset({or_expression}) || isset({replace_expression}))', _('Target')], 60 'recovery_expr_temp' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, '(isset({add_recovery_expression}) || isset({and_recovery_expression}) || isset({or_recovery_expression}) || isset({replace_recovery_expression}))', _('Recovery expression')], 61 'recovery_expr_target_single' => [T_ZBX_STR, O_OPT, null, NOT_EMPTY, '(isset({and_recovery_expression}) || isset({or_recovery_expression}) || isset({replace_recovery_expression}))', _('Target')], 62 'dependencies' => [T_ZBX_INT, O_OPT, null, DB_ID, null], 63 'new_dependency' => [T_ZBX_INT, O_OPT, null, DB_ID.'{}>0', 'isset({add_dependency})'], 64 'g_triggerid' => [T_ZBX_INT, O_OPT, null, DB_ID, null], 65 'copy_targetids' => [T_ZBX_INT, O_OPT, null, DB_ID, null], 66 'visible' => [T_ZBX_STR, O_OPT, null, null, null], 67 'tags' => [T_ZBX_STR, O_OPT, null, null, null], 68 'manual_close' => [T_ZBX_INT, O_OPT, null, 69 IN([ZBX_TRIGGER_MANUAL_CLOSE_NOT_ALLOWED, 70 ZBX_TRIGGER_MANUAL_CLOSE_ALLOWED 71 ]), 72 null 73 ], 74 // filter 75 'filter_set' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 76 'filter_rst' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 77 'filter_priority' => [T_ZBX_INT, O_OPT, null, 78 IN([ 79 -1, TRIGGER_SEVERITY_NOT_CLASSIFIED, 80 TRIGGER_SEVERITY_INFORMATION, TRIGGER_SEVERITY_WARNING, 81 TRIGGER_SEVERITY_AVERAGE, TRIGGER_SEVERITY_HIGH, 82 TRIGGER_SEVERITY_DISASTER 83 ]), null 84 ], 85 'filter_state' => [T_ZBX_INT, O_OPT, null, 86 IN([-1, TRIGGER_STATE_NORMAL, TRIGGER_STATE_UNKNOWN]), null 87 ], 88 'filter_status' => [T_ZBX_INT, O_OPT, null, 89 IN([-1, TRIGGER_STATUS_ENABLED, TRIGGER_STATUS_DISABLED]), null 90 ], 91 'filter_value' => [T_ZBX_INT, O_OPT, null, 92 IN([-1, TRIGGER_VALUE_FALSE, TRIGGER_VALUE_TRUE]), null 93 ], 94 'filter_evaltype' => [T_ZBX_INT, O_OPT, null, 95 IN([TAG_EVAL_TYPE_AND_OR, TAG_EVAL_TYPE_OR]), null 96 ], 97 'filter_tags' => [T_ZBX_STR, O_OPT, null, null, null], 98 // actions 99 'action' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, 100 IN('"trigger.masscopyto","trigger.massdelete","trigger.massdisable",'. 101 '"trigger.massenable","trigger.massupdate","trigger.massupdateform"' 102 ), 103 null 104 ], 105 'toggle_expression_constructor' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 106 'toggle_recovery_expression_constructor' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 107 'add_expression' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 108 'add_recovery_expression' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 109 'and_expression' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 110 'and_recovery_expression' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 111 'or_expression' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 112 'or_recovery_expression' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 113 'replace_expression' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 114 'replace_recovery_expression' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 115 'remove_expression' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 116 'remove_recovery_expression' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 117 'test_expression' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 118 'add_dependency' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 119 'group_enable' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 120 'group_disable' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 121 'group_delete' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 122 'copy' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 123 'clone' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 124 'add' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 125 'update' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 126 'massupdate' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 127 'delete' => [T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, null], 128 'cancel' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 129 'form' => [T_ZBX_STR, O_OPT, P_SYS, null, null], 130 'form_refresh' => [T_ZBX_INT, O_OPT, null, null, null], 131 // sort and sortorder 132 'sort' => [T_ZBX_STR, O_OPT, P_SYS, IN('"description","priority","status"'), null], 133 'sortorder' => [T_ZBX_STR, O_OPT, P_SYS, IN('"'.ZBX_SORT_DOWN.'","'.ZBX_SORT_UP.'"'), null] 134]; 135 136check_fields($fields); 137 138$_REQUEST['status'] = isset($_REQUEST['status']) ? TRIGGER_STATUS_ENABLED : TRIGGER_STATUS_DISABLED; 139 140// Validate permissions to single trigger. 141$triggerId = getRequest('triggerid'); 142 143if ($triggerId !== null) { 144 $trigger = API::Trigger()->get([ 145 'output' => ['triggerid'], 146 'triggerids' => [$triggerId], 147 'editable' => true 148 ]); 149 150 if (!$trigger) { 151 access_deny(); 152 } 153} 154 155// Validate permissions to a group of triggers for mass enable/disable actions. 156$triggerIds = getRequest('g_triggerid', []); 157$triggerIds = zbx_toArray($triggerIds); 158 159if ($triggerIds) { 160 $triggerIds = array_unique($triggerIds); 161 162 $triggers = API::Trigger()->get([ 163 'output' => [], 164 'triggerids' => $triggerIds, 165 'editable' => true 166 ]); 167 168 if (count($triggers) != count($triggerIds)) { 169 uncheckTableRows(getRequest('hostid'), zbx_objectValues($triggers, 'triggerid')); 170 } 171} 172 173if (getRequest('groupid') && !isWritableHostGroups([getRequest('groupid')])) { 174 access_deny(); 175} 176if (getRequest('hostid') && !isWritableHostTemplates([getRequest('hostid')])) { 177 access_deny(); 178} 179 180/* 181 * Actions 182 */ 183$expression_action = ''; 184if (hasRequest('add_expression')) { 185 $_REQUEST['expression'] = getRequest('expr_temp'); 186 $_REQUEST['expr_temp'] = ''; 187} 188elseif (hasRequest('and_expression')) { 189 $expression_action = 'and'; 190} 191elseif (hasRequest('or_expression')) { 192 $expression_action = 'or'; 193} 194elseif (hasRequest('replace_expression')) { 195 $expression_action = 'r'; 196} 197elseif (hasRequest('remove_expression')) { 198 $expression_action = 'R'; 199 $_REQUEST['expr_target_single'] = getRequest('remove_expression'); 200} 201 202$recovery_expression_action = ''; 203if (hasRequest('add_recovery_expression')) { 204 $_REQUEST['recovery_expression'] = getRequest('recovery_expr_temp'); 205 $_REQUEST['recovery_expr_temp'] = ''; 206} 207elseif (hasRequest('and_recovery_expression')) { 208 $recovery_expression_action = 'and'; 209} 210elseif (hasRequest('or_recovery_expression')) { 211 $recovery_expression_action = 'or'; 212} 213elseif (hasRequest('replace_recovery_expression')) { 214 $recovery_expression_action = 'r'; 215} 216elseif (hasRequest('remove_recovery_expression')) { 217 $recovery_expression_action = 'R'; 218 $_REQUEST['recovery_expr_target_single'] = getRequest('remove_recovery_expression'); 219} 220 221if (hasRequest('clone') && hasRequest('triggerid')) { 222 unset($_REQUEST['triggerid']); 223 $_REQUEST['form'] = 'clone'; 224} 225elseif (hasRequest('add') || hasRequest('update')) { 226 $tags = getRequest('tags', []); 227 $dependencies = zbx_toObject(getRequest('dependencies', []), 'triggerid'); 228 229 // Remove empty new tag lines. 230 foreach ($tags as $key => $tag) { 231 if ($tag['tag'] === '' && $tag['value'] === '') { 232 unset($tags[$key]); 233 } 234 } 235 236 $description = getRequest('description', ''); 237 $expression = getRequest('expression', ''); 238 $recovery_mode = getRequest('recovery_mode', ZBX_RECOVERY_MODE_EXPRESSION); 239 $recovery_expression = getRequest('recovery_expression', ''); 240 $type = getRequest('type', 0); 241 $url = getRequest('url', ''); 242 $priority = getRequest('priority', TRIGGER_SEVERITY_NOT_CLASSIFIED); 243 $comments = getRequest('comments', ''); 244 $correlation_mode = getRequest('correlation_mode', ZBX_TRIGGER_CORRELATION_NONE); 245 $correlation_tag = getRequest('correlation_tag', ''); 246 $manual_close = getRequest('manual_close', ZBX_TRIGGER_MANUAL_CLOSE_NOT_ALLOWED); 247 $status = getRequest('status', TRIGGER_STATUS_ENABLED); 248 249 if (hasRequest('add')) { 250 $trigger = [ 251 'description' => $description, 252 'expression' => $expression, 253 'recovery_mode' => $recovery_mode, 254 'type' => $type, 255 'url' => $url, 256 'priority' => $priority, 257 'comments' => $comments, 258 'tags' => $tags, 259 'manual_close' => $manual_close, 260 'dependencies' => $dependencies, 261 'status' => $status 262 ]; 263 switch ($recovery_mode) { 264 case ZBX_RECOVERY_MODE_RECOVERY_EXPRESSION: 265 $trigger['recovery_expression'] = $recovery_expression; 266 // break; is not missing here 267 268 case ZBX_RECOVERY_MODE_EXPRESSION: 269 $trigger['correlation_mode'] = $correlation_mode; 270 if ($correlation_mode == ZBX_TRIGGER_CORRELATION_TAG) { 271 $trigger['correlation_tag'] = $correlation_tag; 272 } 273 break; 274 } 275 276 $result = (bool) API::Trigger()->create($trigger); 277 278 show_messages($result, _('Trigger added'), _('Cannot add trigger')); 279 } 280 else { 281 $db_triggers = API::Trigger()->get([ 282 'output' => ['expression', 'description', 'url', 'status', 'priority', 'comments', 'templateid', 'type', 283 'flags', 'recovery_mode', 'recovery_expression', 'correlation_mode', 'correlation_tag', 'manual_close' 284 ], 285 'selectDependencies' => ['triggerid'], 286 'selectTags' => ['tag', 'value'], 287 'triggerids' => getRequest('triggerid') 288 ]); 289 290 $db_triggers = CMacrosResolverHelper::resolveTriggerExpressions($db_triggers, 291 ['sources' => ['expression', 'recovery_expression']] 292 ); 293 294 $db_trigger = reset($db_triggers); 295 296 $trigger = []; 297 298 if ($db_trigger['flags'] == ZBX_FLAG_DISCOVERY_NORMAL) { 299 if ($db_trigger['templateid'] == 0) { 300 if ($db_trigger['description'] !== $description) { 301 $trigger['description'] = $description; 302 } 303 if ($db_trigger['expression'] !== $expression) { 304 $trigger['expression'] = $expression; 305 } 306 if ($db_trigger['recovery_mode'] != $recovery_mode) { 307 $trigger['recovery_mode'] = $recovery_mode; 308 } 309 switch ($recovery_mode) { 310 case ZBX_RECOVERY_MODE_RECOVERY_EXPRESSION: 311 if ($db_trigger['recovery_expression'] !== $recovery_expression) { 312 $trigger['recovery_expression'] = $recovery_expression; 313 } 314 // break; is not missing here 315 316 case ZBX_RECOVERY_MODE_EXPRESSION: 317 if ($db_trigger['correlation_mode'] != $correlation_mode) { 318 $trigger['correlation_mode'] = $correlation_mode; 319 } 320 if ($correlation_mode == ZBX_TRIGGER_CORRELATION_TAG 321 && $db_trigger['correlation_tag'] !== $correlation_tag) { 322 $trigger['correlation_tag'] = $correlation_tag; 323 } 324 break; 325 } 326 } 327 328 if ($db_trigger['type'] != $type) { 329 $trigger['type'] = $type; 330 } 331 if ($db_trigger['url'] !== $url) { 332 $trigger['url'] = $url; 333 } 334 if ($db_trigger['priority'] != $priority) { 335 $trigger['priority'] = $priority; 336 } 337 if ($db_trigger['comments'] !== $comments) { 338 $trigger['comments'] = $comments; 339 } 340 341 $db_tags = $db_trigger['tags']; 342 CArrayHelper::sort($db_tags, ['tag', 'value']); 343 CArrayHelper::sort($tags, ['tag', 'value']); 344 if (array_values($db_tags) !== array_values($tags)) { 345 $trigger['tags'] = $tags; 346 } 347 348 if ($db_trigger['manual_close'] != $manual_close) { 349 $trigger['manual_close'] = $manual_close; 350 } 351 352 $db_dependencies = $db_trigger['dependencies']; 353 CArrayHelper::sort($db_dependencies, ['triggerid']); 354 CArrayHelper::sort($dependencies, ['triggerid']); 355 if (array_values($db_dependencies) !== array_values($dependencies)) { 356 $trigger['dependencies'] = $dependencies; 357 } 358 } 359 360 if ($db_trigger['status'] != $status) { 361 $trigger['status'] = $status; 362 } 363 364 if ($trigger) { 365 $trigger['triggerid'] = getRequest('triggerid'); 366 367 $result = (bool) API::Trigger()->update($trigger); 368 } 369 else { 370 $result = true; 371 } 372 373 show_messages($result, _('Trigger updated'), _('Cannot update trigger')); 374 } 375 376 if ($result) { 377 unset($_REQUEST['form']); 378 uncheckTableRows(getRequest('hostid')); 379 } 380} 381elseif (isset($_REQUEST['delete']) && isset($_REQUEST['triggerid'])) { 382 $result = API::Trigger()->delete([getRequest('triggerid')]); 383 384 if ($result) { 385 unset($_REQUEST['form'], $_REQUEST['triggerid']); 386 uncheckTableRows(getRequest('hostid')); 387 } 388 show_messages($result, _('Trigger deleted'), _('Cannot delete trigger')); 389} 390elseif (isset($_REQUEST['add_dependency']) && isset($_REQUEST['new_dependency'])) { 391 if (!isset($_REQUEST['dependencies'])) { 392 $_REQUEST['dependencies'] = []; 393 } 394 foreach ($_REQUEST['new_dependency'] as $triggerid) { 395 if (!uint_in_array($triggerid, $_REQUEST['dependencies'])) { 396 array_push($_REQUEST['dependencies'], $triggerid); 397 } 398 } 399} 400elseif (hasRequest('action') && getRequest('action') === 'trigger.massupdate' 401 && hasRequest('massupdate') && hasRequest('g_triggerid')) { 402 $result = true; 403 $visible = getRequest('visible', []); 404 405 if ($visible) { 406 $triggerids = getRequest('g_triggerid'); 407 $triggers_to_update = []; 408 409 $triggers = API::Trigger()->get([ 410 'output' => ['triggerid', 'templateid'], 411 'triggerids' => $triggerids, 412 'filter' => ['flags' => ZBX_FLAG_DISCOVERY_NORMAL], 413 'preservekeys' => true 414 ]); 415 416 if ($triggers) { 417 $tags = getRequest('tags', []); 418 419 // Remove empty new tag lines. 420 foreach ($tags as $key => $tag) { 421 if ($tag['tag'] === '' && $tag['value'] === '') { 422 unset($tags[$key]); 423 } 424 } 425 426 foreach ($triggerids as $triggerid) { 427 if (array_key_exists($triggerid, $triggers)) { 428 $trigger = ['triggerid' => $triggerid]; 429 430 if (array_key_exists('priority', $visible)) { 431 $trigger['priority'] = getRequest('priority'); 432 } 433 434 if (array_key_exists('dependencies', $visible)) { 435 $trigger['dependencies'] = zbx_toObject(getRequest('dependencies', []), 'triggerid'); 436 } 437 438 if (array_key_exists('tags', $visible)) { 439 $trigger['tags'] = $tags; 440 } 441 442 if ($triggers[$triggerid]['templateid'] == 0 && array_key_exists('manual_close', $visible)) { 443 $trigger['manual_close'] = getRequest('manual_close'); 444 } 445 446 $triggers_to_update[] = $trigger; 447 } 448 } 449 } 450 451 if ($triggers_to_update) { 452 $result = (bool) API::Trigger()->update($triggers_to_update); 453 } 454 } 455 456 if ($result) { 457 unset($_REQUEST['form'], $_REQUEST['g_triggerid']); 458 uncheckTableRows(getRequest('hostid')); 459 } 460 show_messages($result, _('Trigger updated'), _('Cannot update trigger')); 461} 462elseif (hasRequest('action') && str_in_array(getRequest('action'), ['trigger.massenable', 'trigger.massdisable']) && hasRequest('g_triggerid')) { 463 $enable = (getRequest('action') == 'trigger.massenable'); 464 $status = $enable ? TRIGGER_STATUS_ENABLED : TRIGGER_STATUS_DISABLED; 465 $update = []; 466 467 // get requested triggers with permission check 468 $dbTriggers = API::Trigger()->get([ 469 'output' => ['triggerid', 'status'], 470 'triggerids' => getRequest('g_triggerid'), 471 'editable' => true 472 ]); 473 474 if ($dbTriggers) { 475 foreach ($dbTriggers as $dbTrigger) { 476 $update[] = [ 477 'triggerid' => $dbTrigger['triggerid'], 478 'status' => $status 479 ]; 480 } 481 482 $result = API::Trigger()->update($update); 483 } 484 else { 485 $result = true; 486 } 487 488 $updated = count($update); 489 $messageSuccess = $enable 490 ? _n('Trigger enabled', 'Triggers enabled', $updated) 491 : _n('Trigger disabled', 'Triggers disabled', $updated); 492 $messageFailed = $enable 493 ? _n('Cannot enable trigger', 'Cannot enable triggers', $updated) 494 : _n('Cannot disable trigger', 'Cannot disable triggers', $updated); 495 496 if ($result) { 497 uncheckTableRows(getRequest('hostid')); 498 unset($_REQUEST['g_triggerid']); 499 } 500 show_messages($result, $messageSuccess, $messageFailed); 501} 502elseif (hasRequest('action') && getRequest('action') === 'trigger.masscopyto' && hasRequest('copy') 503 && hasRequest('g_triggerid')) { 504 if (getRequest('copy_targetids', []) && hasRequest('copy_type')) { 505 // hosts or templates 506 if (getRequest('copy_type') == COPY_TYPE_TO_HOST || getRequest('copy_type') == COPY_TYPE_TO_TEMPLATE) { 507 $hosts_ids = getRequest('copy_targetids'); 508 } 509 // host groups 510 else { 511 $hosts_ids = []; 512 $group_ids = getRequest('copy_targetids'); 513 514 $db_hosts = DBselect( 515 'SELECT DISTINCT h.hostid'. 516 ' FROM hosts h,hosts_groups hg'. 517 ' WHERE h.hostid=hg.hostid'. 518 ' AND '.dbConditionInt('hg.groupid', $group_ids) 519 ); 520 while ($db_host = DBfetch($db_hosts)) { 521 $hosts_ids[] = $db_host['hostid']; 522 } 523 } 524 525 DBstart(); 526 527 $result = copyTriggersToHosts(getRequest('g_triggerid'), $hosts_ids, getRequest('hostid')); 528 $result = DBend($result); 529 530 $triggers_count = count(getRequest('g_triggerid')); 531 532 if ($result) { 533 uncheckTableRows(getRequest('hostid')); 534 unset($_REQUEST['g_triggerid']); 535 } 536 show_messages($result, 537 _n('Trigger copied', 'Triggers copied', $triggers_count), 538 _n('Cannot copy trigger', 'Cannot copy triggers', $triggers_count) 539 ); 540 } 541 else { 542 show_error_message(_('No target selected')); 543 } 544} 545elseif (hasRequest('action') && getRequest('action') == 'trigger.massdelete' && hasRequest('g_triggerid')) { 546 $result = API::Trigger()->delete(getRequest('g_triggerid')); 547 548 if ($result) { 549 uncheckTableRows(getRequest('hostid')); 550 } 551 show_messages($result, _('Triggers deleted'), _('Cannot delete triggers')); 552} 553 554$config = select_config(); 555 556/* 557 * Display 558 */ 559if ((getRequest('action') === 'trigger.massupdateform' || hasRequest('massupdate')) && hasRequest('g_triggerid')) { 560 $data = getTriggerMassupdateFormData(); 561 $data['action'] = 'trigger.massupdate'; 562 $triggersView = new CView('configuration.triggers.massupdate', $data); 563 $triggersView->render(); 564 $triggersView->show(); 565} 566elseif (isset($_REQUEST['form'])) { 567 $data = [ 568 'config' => $config, 569 'form' => getRequest('form'), 570 'form_refresh' => getRequest('form_refresh'), 571 'parent_discoveryid' => null, 572 'dependencies' => getRequest('dependencies', []), 573 'db_dependencies' => [], 574 'triggerid' => getRequest('triggerid'), 575 'expression' => getRequest('expression', ''), 576 'recovery_expression' => getRequest('recovery_expression', ''), 577 'expr_temp' => getRequest('expr_temp', ''), 578 'recovery_expr_temp' => getRequest('recovery_expr_temp', ''), 579 'recovery_mode' => getRequest('recovery_mode', 0), 580 'description' => getRequest('description', ''), 581 'type' => getRequest('type', 0), 582 'priority' => getRequest('priority', TRIGGER_SEVERITY_NOT_CLASSIFIED), 583 'status' => getRequest('status', TRIGGER_STATUS_ENABLED), 584 'comments' => getRequest('comments', ''), 585 'url' => getRequest('url', ''), 586 'expression_constructor' => getRequest('expression_constructor', IM_ESTABLISHED), 587 'recovery_expression_constructor' => getRequest('recovery_expression_constructor', IM_ESTABLISHED), 588 'limited' => false, 589 'templates' => [], 590 'hostid' => getRequest('hostid', 0), 591 'expression_action' => $expression_action, 592 'recovery_expression_action' => $recovery_expression_action, 593 'tags' => array_values(getRequest('tags', [])), 594 'correlation_mode' => getRequest('correlation_mode', ZBX_TRIGGER_CORRELATION_NONE), 595 'correlation_tag' => getRequest('correlation_tag', ''), 596 'manual_close' => getRequest('manual_close', ZBX_TRIGGER_MANUAL_CLOSE_NOT_ALLOWED), 597 'groupid' => getRequest('groupid', 0) 598 ]; 599 600 $triggersView = new CView('configuration.triggers.edit', getTriggerFormData($data)); 601 $triggersView->render(); 602 $triggersView->show(); 603} 604elseif (hasRequest('action') && getRequest('action') === 'trigger.masscopyto' && hasRequest('g_triggerid')) { 605 $data = getCopyElementsFormData('g_triggerid', _('Triggers')); 606 $data['action'] = 'trigger.masscopyto'; 607 608 // render view 609 $triggersView = new CView('configuration.copy.elements', $data); 610 $triggersView->render(); 611 $triggersView->show(); 612} 613else { 614 $data = [ 615 'pageFilter' => new CPageFilter([ 616 'groups' => [ 617 'with_hosts_and_templates' => true, 618 'editable' => true 619 ], 620 'hosts' => [ 621 'templated_hosts' => true, 622 'editable' => true 623 ], 624 'triggers' => ['editable' => true], 625 'groupid' => getRequest('groupid'), 626 'hostid' => getRequest('hostid') 627 ]) 628 ]; 629 630 $data += [ 631 'config' => $config, 632 'hostid' => $data['pageFilter']->hostid, 633 'groupid' => $data['pageFilter']->groupid, 634 'triggers' => [], 635 'profileIdx' => 'web.triggers.filter', 636 'active_tab' => CProfile::get('web.triggers.filter.active', 1), 637 'sort' => getRequest('sort', CProfile::get('web.'.$page['file'].'.sort', 'description')), 638 'sortorder' => getRequest('sortorder', CProfile::get('web.'.$page['file'].'.sortorder', ZBX_SORT_UP)), 639 'show_value_column' => false 640 ]; 641 642 if ($data['hostid'] == 0) { 643 foreach ($data['pageFilter']->hosts as $host) { 644 if ($host['status'] == HOST_STATUS_MONITORED || $host['status'] == HOST_STATUS_NOT_MONITORED) { 645 $data['show_value_column'] = true; 646 break; 647 } 648 } 649 } 650 else { 651 $data['show_value_column'] = ($data['pageFilter']->hosts[$data['hostid']]['status'] == HOST_STATUS_MONITORED 652 || $data['pageFilter']->hosts[$data['hostid']]['status'] == HOST_STATUS_NOT_MONITORED 653 ); 654 } 655 656 CProfile::update('web.'.$page['file'].'.sort', $data['sort'], PROFILE_TYPE_STR); 657 CProfile::update('web.'.$page['file'].'.sortorder', $data['sortorder'], PROFILE_TYPE_STR); 658 659 if (hasRequest('filter_set')) { 660 CProfile::update('web.triggers.filter_priority', getRequest('filter_priority', -1), PROFILE_TYPE_INT); 661 CProfile::update('web.triggers.filter_state', getRequest('filter_state', -1), PROFILE_TYPE_INT); 662 CProfile::update('web.triggers.filter_status', getRequest('filter_status', -1), PROFILE_TYPE_INT); 663 664 if ($data['show_value_column']) { 665 CProfile::update('web.triggers.filter_value', getRequest('filter_value', -1), PROFILE_TYPE_INT); 666 } 667 668 CProfile::update('web.triggers.filter.evaltype', getRequest('filter_evaltype', TAG_EVAL_TYPE_AND_OR), 669 PROFILE_TYPE_INT 670 ); 671 672 $filter_tags = ['tags' => [], 'values' => [], 'operators' => []]; 673 foreach (getRequest('filter_tags', []) as $filter_tag) { 674 if ($filter_tag['tag'] === '' && $filter_tag['value'] === '') { 675 continue; 676 } 677 678 $filter_tags['tags'][] = $filter_tag['tag']; 679 $filter_tags['values'][] = $filter_tag['value']; 680 $filter_tags['operators'][] = $filter_tag['operator']; 681 } 682 CProfile::updateArray('web.triggers.filter.tags.tag', $filter_tags['tags'], PROFILE_TYPE_STR); 683 CProfile::updateArray('web.triggers.filter.tags.value', $filter_tags['values'], PROFILE_TYPE_STR); 684 CProfile::updateArray('web.triggers.filter.tags.operator', $filter_tags['operators'], PROFILE_TYPE_INT); 685 } 686 elseif (hasRequest('filter_rst')) { 687 CProfile::delete('web.triggers.filter_priority'); 688 CProfile::delete('web.triggers.filter_state'); 689 CProfile::delete('web.triggers.filter_status'); 690 691 if ($data['show_value_column']) { 692 CProfile::delete('web.triggers.filter_value'); 693 } 694 695 CProfile::delete('web.triggers.filter.evaltype'); 696 CProfile::deleteIdx('web.triggers.filter.tags.tag'); 697 CProfile::deleteIdx('web.triggers.filter.tags.value'); 698 CProfile::deleteIdx('web.triggers.filter.tags.operator'); 699 } 700 701 $data += [ 702 'filter_priority' => CProfile::get('web.triggers.filter_priority', -1), 703 'filter_state' => CProfile::get('web.triggers.filter_state', -1), 704 'filter_status' => CProfile::get('web.triggers.filter_status', -1) 705 ]; 706 707 if ($data['show_value_column']) { 708 $data['filter_value'] = CProfile::get('web.triggers.filter_value', -1); 709 } 710 711 $data['filter_evaltype'] = CProfile::get('web.triggers.filter.evaltype', TAG_EVAL_TYPE_AND_OR); 712 713 $data['filter_tags'] = []; 714 foreach (CProfile::getArray('web.triggers.filter.tags.tag', []) as $i => $tag) { 715 $data['filter_tags'][] = [ 716 'tag' => $tag, 717 'value' => CProfile::get('web.triggers.filter.tags.value', null, $i), 718 'operator' => CProfile::get('web.triggers.filter.tags.operator', null, $i) 719 ]; 720 } 721 722 // get triggers 723 if ($data['pageFilter']->hostsSelected) { 724 $options = [ 725 'editable' => true, 726 'sortfield' => $data['sort'], 727 'limit' => $config['search_limit'] + 1 728 ]; 729 730 if ($data['sort'] === 'status') { 731 $options['output'] = ['triggerid', 'status', 'state']; 732 } 733 else { 734 $options['output'] = ['triggerid', $data['sort']]; 735 } 736 737 if ($data['filter_priority'] != -1) { 738 $options['filter']['priority'] = $data['filter_priority']; 739 } 740 741 switch ($data['filter_state']) { 742 case TRIGGER_STATE_NORMAL: 743 $options['filter']['state'] = TRIGGER_STATE_NORMAL; 744 $options['filter']['status'] = TRIGGER_STATUS_ENABLED; 745 break; 746 747 case TRIGGER_STATE_UNKNOWN: 748 $options['filter']['state'] = TRIGGER_STATE_UNKNOWN; 749 $options['filter']['status'] = TRIGGER_STATUS_ENABLED; 750 break; 751 752 default: 753 if ($data['filter_status'] != -1) { 754 $options['filter']['status'] = $data['filter_status']; 755 } 756 } 757 758 if ($data['filter_tags']) { 759 $options['evaltype'] = $data['filter_evaltype']; 760 $options['tags'] = $data['filter_tags']; 761 } 762 763 if ($data['pageFilter']->hostid > 0) { 764 $options['hostids'] = $data['pageFilter']->hostid; 765 } 766 elseif ($data['pageFilter']->groupid > 0) { 767 $options['groupids'] = $data['pageFilter']->groupids; 768 } 769 770 if ($data['show_value_column'] && $data['filter_value'] != -1) { 771 $options['filter']['value'] = $data['filter_value']; 772 773 // Exclude templates when all hosts selected and filtered by specific values. 774 if ($data['hostid'] == 0) { 775 $hosts = API::Host()->get([ 776 'output' => [], 777 'editable' => true, 778 'groupids' => ($data['pageFilter']->groupid > 0) ? $data['pageFilter']->groupid : null, 779 'preservekeys' => true 780 ]); 781 $options['hostids'] = array_keys($hosts); 782 } 783 } 784 785 $data['triggers'] = API::Trigger()->get($options); 786 } 787 788 // sort for paging 789 if ($data['sort'] === 'status') { 790 orderTriggersByStatus($data['triggers'], $data['sortorder']); 791 } 792 else { 793 order_result($data['triggers'], $data['sort'], $data['sortorder']); 794 } 795 796 // paging 797 $url = (new CUrl('triggers.php')) 798 ->setArgument('groupid', $data['groupid']) 799 ->setArgument('hostid', $data['hostid']); 800 801 $data['paging'] = getPagingLine($data['triggers'], $data['sortorder'], $url); 802 803 $data['triggers'] = API::Trigger()->get([ 804 'output' => ['triggerid', 'expression', 'description', 'status', 'priority', 'error', 'templateid', 'state', 805 'recovery_mode', 'recovery_expression', 'value' 806 ], 807 'selectHosts' => ['hostid', 'host', 'name', 'status'], 808 'selectDependencies' => ['triggerid', 'description'], 809 'selectDiscoveryRule' => ['itemid', 'name'], 810 'selectTags' => ['tag', 'value'], 811 'triggerids' => zbx_objectValues($data['triggers'], 'triggerid') 812 ]); 813 814 // sort for displaying full results 815 if ($data['sort'] === 'status') { 816 orderTriggersByStatus($data['triggers'], $data['sortorder']); 817 } 818 else { 819 order_result($data['triggers'], $data['sort'], $data['sortorder']); 820 } 821 822 $data['tags'] = makeTags($data['triggers'], true, 'triggerid', ZBX_TAG_COUNT_DEFAULT, $data['filter_tags']); 823 824 $depTriggerIds = []; 825 foreach ($data['triggers'] as $trigger) { 826 foreach ($trigger['dependencies'] as $depTrigger) { 827 $depTriggerIds[$depTrigger['triggerid']] = true; 828 } 829 } 830 831 $dependencyTriggers = []; 832 if ($depTriggerIds) { 833 $dependencyTriggers = API::Trigger()->get([ 834 'output' => ['triggerid', 'description', 'status', 'flags'], 835 'selectHosts' => ['hostid', 'name'], 836 'triggerids' => array_keys($depTriggerIds), 837 'preservekeys' => true 838 ]); 839 840 foreach ($data['triggers'] as &$trigger) { 841 order_result($trigger['dependencies'], 'description', ZBX_SORT_UP); 842 } 843 unset($trigger); 844 845 foreach ($dependencyTriggers as &$dependencyTrigger) { 846 order_result($dependencyTrigger['hosts'], 'name', ZBX_SORT_UP); 847 } 848 unset($dependencyTrigger); 849 } 850 851 $data['dependencyTriggers'] = $dependencyTriggers; 852 853 $data['parent_templates'] = getTriggerParentTemplates($data['triggers'], ZBX_FLAG_DISCOVERY_NORMAL); 854 855 // Do not show 'Info' column, if it is a template. 856 if ($data['hostid']) { 857 $data['showInfoColumn'] = (bool) API::Host()->get([ 858 'output' => [], 859 'hostids' => $data['hostid'] 860 ]); 861 } 862 else { 863 $data['showInfoColumn'] = true; 864 } 865 866 // render view 867 $triggersView = new CView('configuration.triggers.list', $data); 868 $triggersView->render(); 869 $triggersView->show(); 870} 871 872require_once dirname(__FILE__).'/include/page_footer.php'; 873