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 22function condition_operator2str($operator) { 23 $operators = [ 24 CONDITION_OPERATOR_EQUAL => _('equals'), 25 CONDITION_OPERATOR_NOT_EQUAL => _('does not equal'), 26 CONDITION_OPERATOR_LIKE => _('contains'), 27 CONDITION_OPERATOR_NOT_LIKE => _('does not contain'), 28 CONDITION_OPERATOR_IN => _('in'), 29 CONDITION_OPERATOR_MORE_EQUAL => _('is greater than or equals'), 30 CONDITION_OPERATOR_LESS_EQUAL => _('is less than or equals'), 31 CONDITION_OPERATOR_NOT_IN => _('not in'), 32 CONDITION_OPERATOR_YES => _('Yes'), 33 CONDITION_OPERATOR_NO => _('No'), 34 CONDITION_OPERATOR_REGEXP => _('matches'), 35 CONDITION_OPERATOR_NOT_REGEXP => _('does not match') 36 ]; 37 38 return $operators[$operator]; 39} 40 41function condition_type2str($type) { 42 $types = [ 43 CONDITION_TYPE_SUPPRESSED => _('Problem is suppressed'), 44 CONDITION_TYPE_TRIGGER_NAME => _('Trigger name'), 45 CONDITION_TYPE_TRIGGER_SEVERITY => _('Trigger severity'), 46 CONDITION_TYPE_TRIGGER => _('Trigger'), 47 CONDITION_TYPE_HOST_NAME => _('Host name'), 48 CONDITION_TYPE_HOST_GROUP => _('Host group'), 49 CONDITION_TYPE_TEMPLATE => _('Template'), 50 CONDITION_TYPE_HOST => _('Host'), 51 CONDITION_TYPE_TIME_PERIOD => _('Time period'), 52 CONDITION_TYPE_DRULE => _('Discovery rule'), 53 CONDITION_TYPE_DCHECK => _('Discovery check'), 54 CONDITION_TYPE_DOBJECT => _('Discovery object'), 55 CONDITION_TYPE_DHOST_IP => _('Host IP'), 56 CONDITION_TYPE_DSERVICE_TYPE => _('Service type'), 57 CONDITION_TYPE_DSERVICE_PORT => _('Service port'), 58 CONDITION_TYPE_DSTATUS => _('Discovery status'), 59 CONDITION_TYPE_DUPTIME => _('Uptime/Downtime'), 60 CONDITION_TYPE_DVALUE => _('Received value'), 61 CONDITION_TYPE_EVENT_ACKNOWLEDGED => _('Event acknowledged'), 62 CONDITION_TYPE_APPLICATION => _('Application'), 63 CONDITION_TYPE_PROXY => _('Proxy'), 64 CONDITION_TYPE_EVENT_TYPE => _('Event type'), 65 CONDITION_TYPE_HOST_METADATA => _('Host metadata'), 66 CONDITION_TYPE_EVENT_TAG => _('Tag name'), 67 CONDITION_TYPE_EVENT_TAG_VALUE => _('Tag value') 68 ]; 69 70 return $types[$type]; 71} 72 73function discovery_object2str($object = null) { 74 $objects = [ 75 EVENT_OBJECT_DHOST => _('Device'), 76 EVENT_OBJECT_DSERVICE => _('Service') 77 ]; 78 79 if ($object === null) { 80 return $objects; 81 } 82 83 return $objects[$object]; 84} 85 86/** 87 * Converts numerical action condition values to their corresponding string values according to action condition type. 88 * 89 * For action condition types such as: hosts, host groups, templates, proxies, triggers, discovery rules 90 * and discovery checks, action condition values contain IDs. All unique IDs are first collected and then queried. 91 * For other action condition types values are returned as they are or converted using simple string conversion 92 * functions according to action condition type. 93 * 94 * @param array $actions array of actions 95 * @param array $action['filter'] array containing arrays of action conditions and other data 96 * @param array $action['filter']['conditions'] array of action conditions 97 * @param array $config array containing configuration parameters for getting trigger 98 * severity names 99 * 100 * @return array returns an array of actions condition string values 101 */ 102function actionConditionValueToString(array $actions, array $config) { 103 $result = []; 104 105 $groupIds = []; 106 $triggerIds = []; 107 $hostIds = []; 108 $templateIds = []; 109 $proxyIds = []; 110 $dRuleIds = []; 111 $dCheckIds = []; 112 113 foreach ($actions as $i => $action) { 114 $result[$i] = []; 115 116 foreach ($action['filter']['conditions'] as $j => $condition) { 117 // unknown types and all of the default values for other types are 'Unknown' 118 $result[$i][$j] = _('Unknown'); 119 120 switch ($condition['conditiontype']) { 121 case CONDITION_TYPE_HOST_GROUP: 122 $groupIds[$condition['value']] = $condition['value']; 123 break; 124 125 case CONDITION_TYPE_TRIGGER: 126 $triggerIds[$condition['value']] = $condition['value']; 127 break; 128 129 case CONDITION_TYPE_HOST: 130 $hostIds[$condition['value']] = $condition['value']; 131 break; 132 133 case CONDITION_TYPE_TEMPLATE: 134 $templateIds[$condition['value']] = $condition['value']; 135 break; 136 137 case CONDITION_TYPE_PROXY: 138 $proxyIds[$condition['value']] = $condition['value']; 139 break; 140 141 // return values as is for following condition types 142 case CONDITION_TYPE_TRIGGER_NAME: 143 case CONDITION_TYPE_HOST_METADATA: 144 case CONDITION_TYPE_HOST_NAME: 145 case CONDITION_TYPE_TIME_PERIOD: 146 case CONDITION_TYPE_DHOST_IP: 147 case CONDITION_TYPE_DSERVICE_PORT: 148 case CONDITION_TYPE_DUPTIME: 149 case CONDITION_TYPE_DVALUE: 150 case CONDITION_TYPE_APPLICATION: 151 case CONDITION_TYPE_EVENT_TAG: 152 case CONDITION_TYPE_EVENT_TAG_VALUE: 153 $result[$i][$j] = $condition['value']; 154 break; 155 156 case CONDITION_TYPE_EVENT_ACKNOWLEDGED: 157 $result[$i][$j] = $condition['value'] ? _('Ack') : _('Not Ack'); 158 break; 159 160 case CONDITION_TYPE_TRIGGER_SEVERITY: 161 $result[$i][$j] = getSeverityName($condition['value'], $config); 162 break; 163 164 case CONDITION_TYPE_DRULE: 165 $dRuleIds[$condition['value']] = $condition['value']; 166 break; 167 168 case CONDITION_TYPE_DCHECK: 169 $dCheckIds[$condition['value']] = $condition['value']; 170 break; 171 172 case CONDITION_TYPE_DOBJECT: 173 $result[$i][$j] = discovery_object2str($condition['value']); 174 break; 175 176 case CONDITION_TYPE_DSERVICE_TYPE: 177 $result[$i][$j] = discovery_check_type2str($condition['value']); 178 break; 179 180 case CONDITION_TYPE_DSTATUS: 181 $result[$i][$j] = discovery_object_status2str($condition['value']); 182 break; 183 184 case CONDITION_TYPE_EVENT_TYPE: 185 $result[$i][$j] = eventType($condition['value']); 186 break; 187 } 188 } 189 } 190 191 $groups = []; 192 $triggers = []; 193 $hosts = []; 194 $templates = []; 195 $proxies = []; 196 $dRules = []; 197 $dChecks = []; 198 199 if ($groupIds) { 200 $groups = API::HostGroup()->get([ 201 'output' => ['name'], 202 'groupids' => $groupIds, 203 'preservekeys' => true 204 ]); 205 } 206 207 if ($triggerIds) { 208 $triggers = API::Trigger()->get([ 209 'output' => ['description'], 210 'triggerids' => $triggerIds, 211 'expandDescription' => true, 212 'selectHosts' => ['name'], 213 'preservekeys' => true 214 ]); 215 } 216 217 if ($hostIds) { 218 $hosts = API::Host()->get([ 219 'output' => ['name'], 220 'hostids' => $hostIds, 221 'preservekeys' => true 222 ]); 223 } 224 225 if ($templateIds) { 226 $templates = API::Template()->get([ 227 'output' => ['name'], 228 'templateids' => $templateIds, 229 'preservekeys' => true 230 ]); 231 } 232 233 if ($proxyIds) { 234 $proxies = API::Proxy()->get([ 235 'output' => ['host'], 236 'proxyids' => $proxyIds, 237 'preservekeys' => true 238 ]); 239 } 240 241 if ($dRuleIds) { 242 $dRules = API::DRule()->get([ 243 'output' => ['name'], 244 'druleids' => $dRuleIds, 245 'preservekeys' => true 246 ]); 247 } 248 249 if ($dCheckIds) { 250 $dChecks = API::DCheck()->get([ 251 'output' => ['type', 'key_', 'ports'], 252 'dcheckids' => $dCheckIds, 253 'selectDRules' => ['name'], 254 'preservekeys' => true 255 ]); 256 } 257 258 if ($groups || $triggers || $hosts || $templates || $proxies || $dRules || $dChecks) { 259 foreach ($actions as $i => $action) { 260 foreach ($action['filter']['conditions'] as $j => $condition) { 261 $id = $condition['value']; 262 263 switch ($condition['conditiontype']) { 264 case CONDITION_TYPE_HOST_GROUP: 265 if (isset($groups[$id])) { 266 $result[$i][$j] = $groups[$id]['name']; 267 } 268 break; 269 270 case CONDITION_TYPE_TRIGGER: 271 if (isset($triggers[$id])) { 272 $host = reset($triggers[$id]['hosts']); 273 $result[$i][$j] = $host['name'].NAME_DELIMITER.$triggers[$id]['description']; 274 } 275 break; 276 277 case CONDITION_TYPE_HOST: 278 if (isset($hosts[$id])) { 279 $result[$i][$j] = $hosts[$id]['name']; 280 } 281 break; 282 283 case CONDITION_TYPE_TEMPLATE: 284 if (isset($templates[$id])) { 285 $result[$i][$j] = $templates[$id]['name']; 286 } 287 break; 288 289 case CONDITION_TYPE_PROXY: 290 if (isset($proxies[$id])) { 291 $result[$i][$j] = $proxies[$id]['host']; 292 } 293 break; 294 295 case CONDITION_TYPE_DRULE: 296 if (isset($dRules[$id])) { 297 $result[$i][$j] = $dRules[$id]['name']; 298 } 299 break; 300 301 case CONDITION_TYPE_DCHECK: 302 if (isset($dChecks[$id])) { 303 $drule = reset($dChecks[$id]['drules']); 304 $type = $dChecks[$id]['type']; 305 $key_ = $dChecks[$id]['key_']; 306 $ports = $dChecks[$id]['ports']; 307 308 $dCheck = discovery_check2str($type, $key_, $ports); 309 310 $result[$i][$j] = $drule['name'].NAME_DELIMITER.$dCheck; 311 } 312 break; 313 } 314 } 315 } 316 } 317 318 return $result; 319} 320 321/** 322 * Returns the HTML representation of an action condition and action operation condition. 323 * 324 * @param string $condition_type 325 * @param string $operator 326 * @param string $value 327 * @param string $value2 328 * 329 * @return array 330 */ 331function getConditionDescription($condition_type, $operator, $value, $value2) { 332 if ($condition_type == CONDITION_TYPE_EVENT_TAG_VALUE) { 333 $description = [_('Value of tag')]; 334 $description[] = ' '; 335 $description[] = italic(CHtml::encode($value2)); 336 $description[] = ' '; 337 } 338 elseif ($condition_type == CONDITION_TYPE_SUPPRESSED) { 339 return ($operator == CONDITION_OPERATOR_YES) 340 ? [_('Problem is suppressed')] 341 : [_('Problem is not suppressed')]; 342 } 343 elseif ($condition_type == CONDITION_TYPE_EVENT_ACKNOWLEDGED) { 344 return $value ? _('Event is acknowledged') : _('Event is not acknowledged'); 345 } 346 else { 347 $description = [condition_type2str($condition_type)]; 348 $description[] = ' '; 349 } 350 351 $description[] = condition_operator2str($operator); 352 $description[] = ' '; 353 $description[] = italic(CHtml::encode($value)); 354 355 return $description; 356} 357 358/** 359 * Gathers media types, user groups, users, host groups, hosts and templates for actions and their operations, and 360 * returns the HTML representation of action operation values according to action operation type. 361 * 362 * @param array $actions Array of actions 363 * @param int $type Operations recovery type (ACTION_OPERATION or ACTION_RECOVERY_OPERATION) 364 * 365 * @return array Returns an array of actions operation descriptions. 366 */ 367function getActionOperationDescriptions(array $actions, $type) { 368 $result = []; 369 370 $media_typeids = []; 371 $userids = []; 372 $usr_grpids = []; 373 $hostids = []; 374 $groupids = []; 375 $templateids = []; 376 377 foreach ($actions as $i => $action) { 378 $result[$i] = []; 379 380 if ($type == ACTION_OPERATION) { 381 foreach ($action['operations'] as $j => $operation) { 382 $result[$i][$j] = []; 383 384 switch ($operation['operationtype']) { 385 case OPERATION_TYPE_MESSAGE: 386 $media_typeid = $operation['opmessage']['mediatypeid']; 387 388 if ($media_typeid != 0) { 389 $media_typeids[$media_typeid] = $media_typeid; 390 } 391 392 if (array_key_exists('opmessage_usr', $operation) && $operation['opmessage_usr']) { 393 foreach ($operation['opmessage_usr'] as $users) { 394 $userids[$users['userid']] = $users['userid']; 395 } 396 } 397 398 if (array_key_exists('opmessage_grp', $operation) && $operation['opmessage_grp']) { 399 foreach ($operation['opmessage_grp'] as $user_groups) { 400 $usr_grpids[$user_groups['usrgrpid']] = $user_groups['usrgrpid']; 401 } 402 } 403 break; 404 405 case OPERATION_TYPE_COMMAND: 406 if (array_key_exists('opcommand_hst', $operation) && $operation['opcommand_hst']) { 407 foreach ($operation['opcommand_hst'] as $host) { 408 if ($host['hostid'] != 0) { 409 $hostids[$host['hostid']] = $host['hostid']; 410 } 411 } 412 } 413 414 if (array_key_exists('opcommand_grp', $operation) && $operation['opcommand_grp']) { 415 foreach ($operation['opcommand_grp'] as $host_group) { 416 $groupids[$host_group['groupid']] = true; 417 } 418 } 419 break; 420 421 case OPERATION_TYPE_GROUP_ADD: 422 case OPERATION_TYPE_GROUP_REMOVE: 423 foreach ($operation['opgroup'] as $groupid) { 424 $groupids[$groupid['groupid']] = true; 425 } 426 break; 427 428 case OPERATION_TYPE_TEMPLATE_ADD: 429 case OPERATION_TYPE_TEMPLATE_REMOVE: 430 foreach ($operation['optemplate'] as $templateid) { 431 $templateids[$templateid['templateid']] = true; 432 } 433 break; 434 } 435 } 436 } 437 else { 438 $operations_key = ($type == ACTION_RECOVERY_OPERATION) 439 ? 'recovery_operations' 440 : 'ack_operations'; 441 442 foreach ($action[$operations_key] as $j => $operation) { 443 $result[$i][$j] = []; 444 445 switch ($operation['operationtype']) { 446 case OPERATION_TYPE_MESSAGE: 447 $media_typeid = $operation['opmessage']['mediatypeid']; 448 449 if ($media_typeid != 0) { 450 $media_typeids[$media_typeid] = $media_typeid; 451 } 452 453 if (array_key_exists('opmessage_usr', $operation) && $operation['opmessage_usr']) { 454 foreach ($operation['opmessage_usr'] as $users) { 455 $userids[$users['userid']] = $users['userid']; 456 } 457 } 458 459 if (array_key_exists('opmessage_grp', $operation) && $operation['opmessage_grp']) { 460 foreach ($operation['opmessage_grp'] as $user_groups) { 461 $usr_grpids[$user_groups['usrgrpid']] = $user_groups['usrgrpid']; 462 } 463 } 464 break; 465 466 case OPERATION_TYPE_COMMAND: 467 if (array_key_exists('opcommand_hst', $operation) && $operation['opcommand_hst']) { 468 foreach ($operation['opcommand_hst'] as $host) { 469 if ($host['hostid'] != 0) { 470 $hostids[$host['hostid']] = $host['hostid']; 471 } 472 } 473 } 474 475 if (array_key_exists('opcommand_grp', $operation) && $operation['opcommand_grp']) { 476 foreach ($operation['opcommand_grp'] as $host_group) { 477 $groupids[$host_group['groupid']] = true; 478 } 479 } 480 break; 481 } 482 } 483 } 484 } 485 486 $media_types = []; 487 $users = []; 488 $user_groups = []; 489 $hosts = []; 490 $host_groups = []; 491 $templates = []; 492 493 if ($media_typeids) { 494 $media_types = API::Mediatype()->get([ 495 'output' => ['name'], 496 'mediatypeids' => $media_typeids, 497 'preservekeys' => true 498 ]); 499 } 500 501 if ($userids) { 502 $fullnames = []; 503 504 $users = API::User()->get([ 505 'output' => ['userid', 'alias', 'name', 'surname'], 506 'userids' => $userids 507 ]); 508 509 foreach ($users as $user) { 510 $fullnames[$user['userid']] = getUserFullname($user); 511 } 512 } 513 514 if ($usr_grpids) { 515 $user_groups = API::UserGroup()->get([ 516 'output' => ['name'], 517 'usrgrpids' => $usr_grpids, 518 'preservekeys' => true 519 ]); 520 } 521 522 if ($hostids) { 523 $hosts = API::Host()->get([ 524 'output' => ['name'], 525 'hostids' => $hostids, 526 'preservekeys' => true 527 ]); 528 } 529 530 if ($groupids) { 531 $host_groups = API::HostGroup()->get([ 532 'output' => ['name'], 533 'groupids' => array_keys($groupids), 534 'preservekeys' => true 535 ]); 536 } 537 538 if ($templateids) { 539 $templates = API::Template()->get([ 540 'output' => ['name'], 541 'templateids' => array_keys($templateids), 542 'preservekeys' => true 543 ]); 544 } 545 546 // Format the HTML output. 547 foreach ($actions as $i => $action) { 548 if ($type == ACTION_OPERATION) { 549 foreach ($action['operations'] as $j => $operation) { 550 switch ($operation['operationtype']) { 551 case OPERATION_TYPE_MESSAGE: 552 $media_type = _('all media'); 553 $media_typeid = $operation['opmessage']['mediatypeid']; 554 555 if ($media_typeid != 0 && isset($media_types[$media_typeid])) { 556 $media_type = $media_types[$media_typeid]['name']; 557 } 558 559 if (array_key_exists('opmessage_usr', $operation) && $operation['opmessage_usr']) { 560 $user_names_list = []; 561 562 foreach ($operation['opmessage_usr'] as $user) { 563 if (isset($fullnames[$user['userid']])) { 564 $user_names_list[] = $fullnames[$user['userid']]; 565 } 566 } 567 568 order_result($user_names_list); 569 570 $result[$i][$j][] = bold(_('Send message to users').': '); 571 $result[$i][$j][] = [implode(', ', $user_names_list), SPACE, _('via'), SPACE, 572 $media_type 573 ]; 574 $result[$i][$j][] = BR(); 575 } 576 577 if (array_key_exists('opmessage_grp', $operation) && $operation['opmessage_grp']) { 578 $user_groups_list = []; 579 580 foreach ($operation['opmessage_grp'] as $userGroup) { 581 if (isset($user_groups[$userGroup['usrgrpid']])) { 582 $user_groups_list[] = $user_groups[$userGroup['usrgrpid']]['name']; 583 } 584 } 585 586 order_result($user_groups_list); 587 588 $result[$i][$j][] = bold(_('Send message to user groups').': '); 589 $result[$i][$j][] = [implode(', ', $user_groups_list), SPACE, _('via'), SPACE, 590 $media_type 591 ]; 592 $result[$i][$j][] = BR(); 593 } 594 break; 595 596 case OPERATION_TYPE_COMMAND: 597 if (array_key_exists('opcommand_hst', $operation) && $operation['opcommand_hst']) { 598 $host_list = []; 599 600 foreach ($operation['opcommand_hst'] as $host) { 601 if ($host['hostid'] == 0) { 602 $result[$i][$j][] = [ 603 bold(_('Run remote commands on current host')), 604 BR() 605 ]; 606 } 607 elseif (isset($hosts[$host['hostid']])) { 608 $host_list[] = $hosts[$host['hostid']]['name']; 609 } 610 } 611 612 if ($host_list) { 613 order_result($host_list); 614 615 $result[$i][$j][] = bold(_('Run remote commands on hosts').': '); 616 $result[$i][$j][] = [implode(', ', $host_list), BR()]; 617 } 618 } 619 620 if (array_key_exists('opcommand_grp', $operation) && $operation['opcommand_grp']) { 621 $host_group_list = []; 622 623 foreach ($operation['opcommand_grp'] as $host_group) { 624 if (isset($host_groups[$host_group['groupid']])) { 625 $host_group_list[] = $host_groups[$host_group['groupid']]['name']; 626 } 627 } 628 629 order_result($host_group_list); 630 631 $result[$i][$j][] = bold(_('Run remote commands on host groups').': '); 632 $result[$i][$j][] = [implode(', ', $host_group_list), BR()]; 633 } 634 break; 635 636 case OPERATION_TYPE_HOST_ADD: 637 $result[$i][$j][] = [bold(_('Add host')), BR()]; 638 break; 639 640 case OPERATION_TYPE_HOST_REMOVE: 641 $result[$i][$j][] = [bold(_('Remove host')), BR()]; 642 break; 643 644 case OPERATION_TYPE_HOST_ENABLE: 645 $result[$i][$j][] = [bold(_('Enable host')), BR()]; 646 break; 647 648 case OPERATION_TYPE_HOST_DISABLE: 649 $result[$i][$j][] = [bold(_('Disable host')), BR()]; 650 break; 651 652 case OPERATION_TYPE_GROUP_ADD: 653 case OPERATION_TYPE_GROUP_REMOVE: 654 $host_group_list = []; 655 656 foreach ($operation['opgroup'] as $groupid) { 657 if (array_key_exists($groupid['groupid'], $host_groups)) { 658 $host_group_list[] = $host_groups[$groupid['groupid']]['name']; 659 } 660 } 661 662 order_result($host_group_list); 663 664 if ($operation['operationtype'] == OPERATION_TYPE_GROUP_ADD) { 665 $result[$i][$j][] = bold(_('Add to host groups').': '); 666 } 667 else { 668 $result[$i][$j][] = bold(_('Remove from host groups').': '); 669 } 670 671 $result[$i][$j][] = [implode(', ', $host_group_list), BR()]; 672 break; 673 674 case OPERATION_TYPE_TEMPLATE_ADD: 675 case OPERATION_TYPE_TEMPLATE_REMOVE: 676 $template_list = []; 677 678 foreach ($operation['optemplate'] as $templateid) { 679 if (array_key_exists($templateid['templateid'], $templates)) { 680 $template_list[] = $templates[$templateid['templateid']]['name']; 681 } 682 } 683 684 order_result($template_list); 685 686 if ($operation['operationtype'] == OPERATION_TYPE_TEMPLATE_ADD) { 687 $result[$i][$j][] = bold(_('Link to templates').': '); 688 } 689 else { 690 $result[$i][$j][] = bold(_('Unlink from templates').': '); 691 } 692 693 $result[$i][$j][] = [implode(', ', $template_list), BR()]; 694 break; 695 696 case OPERATION_TYPE_HOST_INVENTORY: 697 $host_inventory_modes = getHostInventoryModes(); 698 $result[$i][$j][] = bold(operation_type2str(OPERATION_TYPE_HOST_INVENTORY).': '); 699 $result[$i][$j][] = [ 700 $host_inventory_modes[$operation['opinventory']['inventory_mode']], 701 BR() 702 ]; 703 break; 704 } 705 } 706 } 707 else { 708 $operations_key = ($type == ACTION_RECOVERY_OPERATION) 709 ? 'recovery_operations' 710 : 'ack_operations'; 711 712 foreach ($action[$operations_key] as $j => $operation) { 713 switch ($operation['operationtype']) { 714 case OPERATION_TYPE_MESSAGE: 715 $media_type = _('all media'); 716 $media_typeid = $operation['opmessage']['mediatypeid']; 717 718 if ($media_typeid != 0 && isset($media_types[$media_typeid])) { 719 $media_type = $media_types[$media_typeid]['name']; 720 } 721 722 if (array_key_exists('opmessage_usr', $operation) && $operation['opmessage_usr']) { 723 $user_names_list = []; 724 725 foreach ($operation['opmessage_usr'] as $user) { 726 if (isset($fullnames[$user['userid']])) { 727 $user_names_list[] = $fullnames[$user['userid']]; 728 } 729 } 730 731 order_result($user_names_list); 732 733 $result[$i][$j][] = bold(_('Send message to users').': '); 734 $result[$i][$j][] = [implode(', ', $user_names_list), SPACE, _('via'), SPACE, 735 $media_type 736 ]; 737 $result[$i][$j][] = BR(); 738 } 739 740 if (array_key_exists('opmessage_grp', $operation) && $operation['opmessage_grp']) { 741 $user_groups_list = []; 742 743 foreach ($operation['opmessage_grp'] as $userGroup) { 744 if (isset($user_groups[$userGroup['usrgrpid']])) { 745 $user_groups_list[] = $user_groups[$userGroup['usrgrpid']]['name']; 746 } 747 } 748 749 order_result($user_groups_list); 750 751 $result[$i][$j][] = bold(_('Send message to user groups').': '); 752 $result[$i][$j][] = [implode(', ', $user_groups_list), SPACE, _('via'), SPACE, 753 $media_type 754 ]; 755 $result[$i][$j][] = BR(); 756 } 757 break; 758 759 case OPERATION_TYPE_COMMAND: 760 if (array_key_exists('opcommand_hst', $operation) && $operation['opcommand_hst']) { 761 $host_list = []; 762 763 foreach ($operation['opcommand_hst'] as $host) { 764 if ($host['hostid'] == 0) { 765 $result[$i][$j][] = [ 766 bold(_('Run remote commands on current host')), 767 BR() 768 ]; 769 } 770 elseif (isset($hosts[$host['hostid']])) { 771 $host_list[] = $hosts[$host['hostid']]['name']; 772 } 773 } 774 775 if ($host_list) { 776 order_result($host_list); 777 778 $result[$i][$j][] = bold(_('Run remote commands on hosts').': '); 779 $result[$i][$j][] = [implode(', ', $host_list), BR()]; 780 } 781 } 782 783 if (array_key_exists('opcommand_grp', $operation) && $operation['opcommand_grp']) { 784 $host_group_list = []; 785 786 foreach ($operation['opcommand_grp'] as $host_group) { 787 if (isset($host_groups[$host_group['groupid']])) { 788 $host_group_list[] = $host_groups[$host_group['groupid']]['name']; 789 } 790 } 791 792 order_result($host_group_list); 793 794 $result[$i][$j][] = bold(_('Run remote commands on host groups').': '); 795 $result[$i][$j][] = [implode(', ', $host_group_list), BR()]; 796 } 797 break; 798 799 case OPERATION_TYPE_RECOVERY_MESSAGE: 800 case OPERATION_TYPE_ACK_MESSAGE: 801 $result[$i][$j][] = bold(_('Notify all involved')); 802 break; 803 } 804 } 805 } 806 } 807 808 return $result; 809} 810 811/** 812 * Gathers action operation script details and returns the HTML items representing action operation with hint. 813 * 814 * @param array $operations Array of action operations. 815 * @param string $operation['operationtype'] Action operation type. 816 * Possible values: OPERATION_TYPE_MESSAGE, OPERATION_TYPE_COMMAND, 817 * OPERATION_TYPE_ACK_MESSAGE and OPERATION_TYPE_RECOVERY_MESSAGE 818 * @param string $operation['opcommand']['type'] Action operation command type. 819 * Possible values: ZBX_SCRIPT_TYPE_IPMI, ZBX_SCRIPT_TYPE_SSH, 820 * ZBX_SCRIPT_TYPE_TELNET, ZBX_SCRIPT_TYPE_CUSTOM_SCRIPT 821 * and ZBX_SCRIPT_TYPE_GLOBAL_SCRIPT 822 * 823 * @return array Returns an array of action operation hints. 824 */ 825function getActionOperationHints(array $operations) { 826 $result = []; 827 $scriptids = []; 828 $scripts = []; 829 830 foreach ($operations as $operation) { 831 if ($operation['operationtype'] == OPERATION_TYPE_COMMAND 832 && $operation['opcommand']['type'] == ZBX_SCRIPT_TYPE_GLOBAL_SCRIPT) { 833 $scriptids[$operation['opcommand']['scriptid']] = true; 834 } 835 } 836 837 if ($scriptids) { 838 $scripts = API::Script()->get([ 839 'output' => ['name'], 840 'scriptids' => array_keys($scriptids), 841 'preservekeys' => true 842 ]); 843 } 844 845 foreach ($operations as $key => $operation) { 846 $result[$key] = []; 847 848 if ($operation['operationtype'] == OPERATION_TYPE_COMMAND) { 849 switch ($operation['opcommand']['type']) { 850 case ZBX_SCRIPT_TYPE_IPMI: 851 $result[$key][] = [bold(_('Run IPMI command').': '), BR(), 852 italic(zbx_nl2br($operation['opcommand']['command'])) 853 ]; 854 break; 855 856 case ZBX_SCRIPT_TYPE_SSH: 857 $result[$key][] = [bold(_('Run SSH commands').': '), BR(), 858 italic(zbx_nl2br($operation['opcommand']['command'])) 859 ]; 860 break; 861 862 case ZBX_SCRIPT_TYPE_TELNET: 863 $result[$key][] = [bold(_('Run TELNET commands').': '), BR(), 864 italic(zbx_nl2br($operation['opcommand']['command'])) 865 ]; 866 break; 867 868 case ZBX_SCRIPT_TYPE_CUSTOM_SCRIPT: 869 if ($operation['opcommand']['execute_on'] == ZBX_SCRIPT_EXECUTE_ON_AGENT) { 870 $result[$key][] = [bold(_s('Run custom commands on %1$s', _('Zabbix agent')).': '), 871 BR(), italic(zbx_nl2br($operation['opcommand']['command'])) 872 ]; 873 } 874 elseif ($operation['opcommand']['execute_on'] == ZBX_SCRIPT_EXECUTE_ON_PROXY) { 875 $result[$key][] = [bold(_s('Run custom commands on %1$s', _('Zabbix server (proxy)')).': '), 876 BR(), italic(zbx_nl2br($operation['opcommand']['command'])) 877 ]; 878 } 879 else { 880 $result[$key][] = [bold(_s('Run custom commands on %1$s', _('Zabbix server')).': '), 881 BR(), italic(zbx_nl2br($operation['opcommand']['command'])) 882 ]; 883 } 884 break; 885 886 case ZBX_SCRIPT_TYPE_GLOBAL_SCRIPT: 887 $scriptId = $operation['opcommand']['scriptid']; 888 889 if (isset($scripts[$scriptId])) { 890 $result[$key][] = [bold(_('Run global script').': '), 891 italic($scripts[$scriptId]['name']) 892 ]; 893 } 894 break; 895 896 default: 897 $result[$key][] = [bold(_('Run commands').': '), BR(), 898 italic(zbx_nl2br($operation['opcommand']['command'])) 899 ]; 900 } 901 } 902 } 903 904 return $result; 905} 906 907/** 908 * Return an array of action conditions supported by the given event source. 909 * 910 * @param int $eventsource 911 * 912 * @return mixed 913 */ 914function get_conditions_by_eventsource($eventsource) { 915 $conditions[EVENT_SOURCE_TRIGGERS] = [ 916 CONDITION_TYPE_TRIGGER_NAME, 917 CONDITION_TYPE_TRIGGER, 918 CONDITION_TYPE_TRIGGER_SEVERITY, 919 CONDITION_TYPE_APPLICATION, 920 CONDITION_TYPE_HOST, 921 CONDITION_TYPE_HOST_GROUP, 922 CONDITION_TYPE_SUPPRESSED, 923 CONDITION_TYPE_EVENT_TAG, 924 CONDITION_TYPE_EVENT_TAG_VALUE, 925 CONDITION_TYPE_TEMPLATE, 926 CONDITION_TYPE_TIME_PERIOD 927 ]; 928 $conditions[EVENT_SOURCE_DISCOVERY] = [ 929 CONDITION_TYPE_DHOST_IP, 930 CONDITION_TYPE_DCHECK, 931 CONDITION_TYPE_DOBJECT, 932 CONDITION_TYPE_DRULE, 933 CONDITION_TYPE_DSTATUS, 934 CONDITION_TYPE_PROXY, 935 CONDITION_TYPE_DVALUE, 936 CONDITION_TYPE_DSERVICE_PORT, 937 CONDITION_TYPE_DSERVICE_TYPE, 938 CONDITION_TYPE_DUPTIME 939 ]; 940 $conditions[EVENT_SOURCE_AUTOREGISTRATION] = [ 941 CONDITION_TYPE_HOST_NAME, 942 CONDITION_TYPE_HOST_METADATA, 943 CONDITION_TYPE_PROXY 944 ]; 945 $conditions[EVENT_SOURCE_INTERNAL] = [ 946 CONDITION_TYPE_APPLICATION, 947 CONDITION_TYPE_EVENT_TYPE, 948 CONDITION_TYPE_HOST, 949 CONDITION_TYPE_HOST_GROUP, 950 CONDITION_TYPE_TEMPLATE 951 ]; 952 953 if (isset($conditions[$eventsource])) { 954 return $conditions[$eventsource]; 955 } 956 957 return $conditions[EVENT_SOURCE_TRIGGERS]; 958} 959 960function get_opconditions_by_eventsource($eventsource) { 961 $conditions = [ 962 EVENT_SOURCE_TRIGGERS => [CONDITION_TYPE_EVENT_ACKNOWLEDGED], 963 EVENT_SOURCE_DISCOVERY => [] 964 ]; 965 966 if (isset($conditions[$eventsource])) { 967 return $conditions[$eventsource]; 968 } 969} 970 971/** 972 * Return allowed operations types. 973 * 974 * @param int $eventsource 975 * 976 * @return array 977 */ 978function getAllowedOperations($eventsource) { 979 if ($eventsource == EVENT_SOURCE_TRIGGERS) { 980 $operations = [ 981 ACTION_OPERATION => [ 982 OPERATION_TYPE_MESSAGE, 983 OPERATION_TYPE_COMMAND 984 ], 985 ACTION_RECOVERY_OPERATION => [ 986 OPERATION_TYPE_MESSAGE, 987 OPERATION_TYPE_COMMAND, 988 OPERATION_TYPE_RECOVERY_MESSAGE 989 ], 990 ACTION_ACKNOWLEDGE_OPERATION => [ 991 OPERATION_TYPE_MESSAGE, 992 OPERATION_TYPE_COMMAND, 993 OPERATION_TYPE_ACK_MESSAGE 994 ] 995 ]; 996 } 997 998 if ($eventsource == EVENT_SOURCE_DISCOVERY) { 999 $operations[ACTION_OPERATION] = [ 1000 OPERATION_TYPE_MESSAGE, 1001 OPERATION_TYPE_COMMAND, 1002 OPERATION_TYPE_HOST_ADD, 1003 OPERATION_TYPE_HOST_REMOVE, 1004 OPERATION_TYPE_GROUP_ADD, 1005 OPERATION_TYPE_GROUP_REMOVE, 1006 OPERATION_TYPE_TEMPLATE_ADD, 1007 OPERATION_TYPE_TEMPLATE_REMOVE, 1008 OPERATION_TYPE_HOST_ENABLE, 1009 OPERATION_TYPE_HOST_DISABLE, 1010 OPERATION_TYPE_HOST_INVENTORY 1011 ]; 1012 } 1013 1014 if ($eventsource == EVENT_SOURCE_AUTOREGISTRATION) { 1015 $operations[ACTION_OPERATION] = [ 1016 OPERATION_TYPE_MESSAGE, 1017 OPERATION_TYPE_COMMAND, 1018 OPERATION_TYPE_HOST_ADD, 1019 OPERATION_TYPE_HOST_REMOVE, 1020 OPERATION_TYPE_GROUP_ADD, 1021 OPERATION_TYPE_GROUP_REMOVE, 1022 OPERATION_TYPE_TEMPLATE_ADD, 1023 OPERATION_TYPE_TEMPLATE_REMOVE, 1024 OPERATION_TYPE_HOST_ENABLE, 1025 OPERATION_TYPE_HOST_DISABLE, 1026 OPERATION_TYPE_HOST_INVENTORY 1027 ]; 1028 } 1029 1030 if ($eventsource == EVENT_SOURCE_INTERNAL) { 1031 $operations = [ 1032 ACTION_OPERATION => [OPERATION_TYPE_MESSAGE], 1033 ACTION_RECOVERY_OPERATION => [ 1034 OPERATION_TYPE_MESSAGE, 1035 OPERATION_TYPE_RECOVERY_MESSAGE 1036 ] 1037 ]; 1038 } 1039 1040 return $operations; 1041} 1042 1043/** 1044 * Get operation type text label according $type value. If $type is equal null array of all available operation types 1045 * will be returned. 1046 * 1047 * @param int|null $type Operation type, one of OPERATION_TYPE_* constant or null. 1048 * 1049 * @return string|array 1050 */ 1051function operation_type2str($type) { 1052 $types = [ 1053 OPERATION_TYPE_MESSAGE => _('Send message'), 1054 OPERATION_TYPE_COMMAND => _('Remote command'), 1055 OPERATION_TYPE_HOST_ADD => _('Add host'), 1056 OPERATION_TYPE_HOST_REMOVE => _('Remove host'), 1057 OPERATION_TYPE_HOST_ENABLE => _('Enable host'), 1058 OPERATION_TYPE_HOST_DISABLE => _('Disable host'), 1059 OPERATION_TYPE_GROUP_ADD => _('Add to host group'), 1060 OPERATION_TYPE_GROUP_REMOVE => _('Remove from host group'), 1061 OPERATION_TYPE_TEMPLATE_ADD => _('Link to template'), 1062 OPERATION_TYPE_TEMPLATE_REMOVE => _('Unlink from template'), 1063 OPERATION_TYPE_HOST_INVENTORY => _('Set host inventory mode'), 1064 OPERATION_TYPE_RECOVERY_MESSAGE => _('Notify all involved'), 1065 OPERATION_TYPE_ACK_MESSAGE => _('Notify all involved') 1066 ]; 1067 1068 if (is_null($type)) { 1069 return order_result($types); 1070 } 1071 elseif (isset($types[$type])) { 1072 return $types[$type]; 1073 } 1074 else { 1075 return _('Unknown'); 1076 } 1077} 1078 1079function sortOperations($eventsource, &$operations) { 1080 if ($eventsource == EVENT_SOURCE_TRIGGERS || $eventsource == EVENT_SOURCE_INTERNAL) { 1081 $esc_step_from = []; 1082 $esc_step_to = []; 1083 $esc_period = []; 1084 $operationTypes = []; 1085 1086 $simple_interval_parser = new CSimpleIntervalParser(); 1087 1088 foreach ($operations as $key => $operation) { 1089 $esc_step_from[$key] = $operation['esc_step_from']; 1090 $esc_step_to[$key] = $operation['esc_step_to']; 1091 // Try to sort by "esc_period" in seconds, otherwise sort as string in case it's a macro or something invalid. 1092 $esc_period[$key] = ($simple_interval_parser->parse($operation['esc_period']) == CParser::PARSE_SUCCESS) 1093 ? timeUnitToSeconds($operation['esc_period']) 1094 : $operation['esc_period']; 1095 1096 $operationTypes[$key] = $operation['operationtype']; 1097 } 1098 array_multisort($esc_step_from, SORT_ASC, $esc_step_to, SORT_ASC, $esc_period, SORT_ASC, $operationTypes, SORT_ASC, $operations); 1099 } 1100 else { 1101 CArrayHelper::sort($operations, ['operationtype']); 1102 } 1103} 1104 1105/** 1106 * Return an array of operators supported by the given action condition. 1107 * 1108 * @param int $conditiontype 1109 * 1110 * @return array 1111 */ 1112function get_operators_by_conditiontype($conditiontype) { 1113 $operators[CONDITION_TYPE_HOST_GROUP] = [ 1114 CONDITION_OPERATOR_EQUAL, 1115 CONDITION_OPERATOR_NOT_EQUAL 1116 ]; 1117 $operators[CONDITION_TYPE_TEMPLATE] = [ 1118 CONDITION_OPERATOR_EQUAL, 1119 CONDITION_OPERATOR_NOT_EQUAL 1120 ]; 1121 $operators[CONDITION_TYPE_HOST] = [ 1122 CONDITION_OPERATOR_EQUAL, 1123 CONDITION_OPERATOR_NOT_EQUAL 1124 ]; 1125 $operators[CONDITION_TYPE_TRIGGER] = [ 1126 CONDITION_OPERATOR_EQUAL, 1127 CONDITION_OPERATOR_NOT_EQUAL 1128 ]; 1129 $operators[CONDITION_TYPE_TRIGGER_NAME] = [ 1130 CONDITION_OPERATOR_LIKE, 1131 CONDITION_OPERATOR_NOT_LIKE 1132 ]; 1133 $operators[CONDITION_TYPE_TRIGGER_SEVERITY] = [ 1134 CONDITION_OPERATOR_EQUAL, 1135 CONDITION_OPERATOR_NOT_EQUAL, 1136 CONDITION_OPERATOR_MORE_EQUAL, 1137 CONDITION_OPERATOR_LESS_EQUAL 1138 ]; 1139 $operators[CONDITION_TYPE_TIME_PERIOD] = [ 1140 CONDITION_OPERATOR_IN, 1141 CONDITION_OPERATOR_NOT_IN 1142 ]; 1143 $operators[CONDITION_TYPE_SUPPRESSED] = [ 1144 CONDITION_OPERATOR_NO, 1145 CONDITION_OPERATOR_YES 1146 ]; 1147 $operators[CONDITION_TYPE_DRULE] = [ 1148 CONDITION_OPERATOR_EQUAL, 1149 CONDITION_OPERATOR_NOT_EQUAL 1150 ]; 1151 $operators[CONDITION_TYPE_DCHECK] = [ 1152 CONDITION_OPERATOR_EQUAL, 1153 CONDITION_OPERATOR_NOT_EQUAL 1154 ]; 1155 $operators[CONDITION_TYPE_DOBJECT] = [ 1156 CONDITION_OPERATOR_EQUAL 1157 ]; 1158 $operators[CONDITION_TYPE_PROXY] = [ 1159 CONDITION_OPERATOR_EQUAL, 1160 CONDITION_OPERATOR_NOT_EQUAL 1161 ]; 1162 $operators[CONDITION_TYPE_DHOST_IP] = [ 1163 CONDITION_OPERATOR_EQUAL, 1164 CONDITION_OPERATOR_NOT_EQUAL 1165 ]; 1166 $operators[CONDITION_TYPE_DSERVICE_TYPE] = [ 1167 CONDITION_OPERATOR_EQUAL, 1168 CONDITION_OPERATOR_NOT_EQUAL 1169 ]; 1170 $operators[CONDITION_TYPE_DSERVICE_PORT] = [ 1171 CONDITION_OPERATOR_EQUAL, 1172 CONDITION_OPERATOR_NOT_EQUAL 1173 ]; 1174 $operators[CONDITION_TYPE_DSTATUS] = [ 1175 CONDITION_OPERATOR_EQUAL 1176 ]; 1177 $operators[CONDITION_TYPE_DUPTIME] = [ 1178 CONDITION_OPERATOR_MORE_EQUAL, 1179 CONDITION_OPERATOR_LESS_EQUAL 1180 ]; 1181 $operators[CONDITION_TYPE_DVALUE] = [ 1182 CONDITION_OPERATOR_EQUAL, 1183 CONDITION_OPERATOR_NOT_EQUAL, 1184 CONDITION_OPERATOR_MORE_EQUAL, 1185 CONDITION_OPERATOR_LESS_EQUAL, 1186 CONDITION_OPERATOR_LIKE, 1187 CONDITION_OPERATOR_NOT_LIKE 1188 ]; 1189 $operators[CONDITION_TYPE_EVENT_ACKNOWLEDGED] = [ 1190 CONDITION_OPERATOR_EQUAL 1191 ]; 1192 $operators[CONDITION_TYPE_APPLICATION] = [ 1193 CONDITION_OPERATOR_EQUAL, 1194 CONDITION_OPERATOR_LIKE, 1195 CONDITION_OPERATOR_NOT_LIKE 1196 ]; 1197 $operators[CONDITION_TYPE_HOST_NAME] = [ 1198 CONDITION_OPERATOR_LIKE, 1199 CONDITION_OPERATOR_NOT_LIKE, 1200 CONDITION_OPERATOR_REGEXP, 1201 CONDITION_OPERATOR_NOT_REGEXP 1202 ]; 1203 $operators[CONDITION_TYPE_EVENT_TYPE] = [ 1204 CONDITION_OPERATOR_EQUAL 1205 ]; 1206 $operators[CONDITION_TYPE_HOST_METADATA] = [ 1207 CONDITION_OPERATOR_LIKE, 1208 CONDITION_OPERATOR_NOT_LIKE, 1209 CONDITION_OPERATOR_REGEXP, 1210 CONDITION_OPERATOR_NOT_REGEXP 1211 ]; 1212 $operators[CONDITION_TYPE_EVENT_TAG] = [ 1213 CONDITION_OPERATOR_EQUAL, 1214 CONDITION_OPERATOR_NOT_EQUAL, 1215 CONDITION_OPERATOR_LIKE, 1216 CONDITION_OPERATOR_NOT_LIKE 1217 ]; 1218 $operators[CONDITION_TYPE_EVENT_TAG_VALUE] = [ 1219 CONDITION_OPERATOR_EQUAL, 1220 CONDITION_OPERATOR_NOT_EQUAL, 1221 CONDITION_OPERATOR_LIKE, 1222 CONDITION_OPERATOR_NOT_LIKE 1223 ]; 1224 1225 if (isset($operators[$conditiontype])) { 1226 return $operators[$conditiontype]; 1227 } 1228 1229 return []; 1230} 1231 1232function count_operations_delay($operations, $def_period) { 1233 $delays = [1 => 0]; 1234 $periods = []; 1235 $max_step = 0; 1236 1237 $simple_interval_parser = new CSimpleIntervalParser(); 1238 1239 $def_period = CMacrosResolverHelper::resolveTimeUnitMacros( 1240 [['def_period' => $def_period]], ['def_period'] 1241 )[0]['def_period']; 1242 1243 $def_period = ($simple_interval_parser->parse($def_period) == CParser::PARSE_SUCCESS) 1244 ? timeUnitToSeconds($def_period) 1245 : null; 1246 1247 $operations = CMacrosResolverHelper::resolveTimeUnitMacros($operations, ['esc_period']); 1248 1249 foreach ($operations as $operation) { 1250 $esc_period = ($simple_interval_parser->parse($operation['esc_period']) == CParser::PARSE_SUCCESS) 1251 ? timeUnitToSeconds($operation['esc_period']) 1252 : null; 1253 1254 $esc_period = ($esc_period === null || $esc_period != 0) ? $esc_period : $def_period; 1255 $step_to = ($operation['esc_step_to'] != 0) ? $operation['esc_step_to'] : 9999; 1256 1257 if ($max_step < $operation['esc_step_from']) { 1258 $max_step = $operation['esc_step_from']; 1259 } 1260 1261 for ($i = $operation['esc_step_from']; $i <= $step_to; $i++) { 1262 if (!array_key_exists($i, $periods) || $esc_period === null || $periods[$i] > $esc_period) { 1263 $periods[$i] = $esc_period; 1264 } 1265 } 1266 } 1267 1268 for ($i = 1; $i <= $max_step; $i++) { 1269 $esc_period = array_key_exists($i, $periods) ? $periods[$i] : $def_period; 1270 $delays[$i + 1] = ($esc_period !== null && $delays[$i] !== null) ? $delays[$i] + $esc_period : null; 1271 } 1272 1273 return $delays; 1274} 1275 1276/** 1277 * Returns the names of the "Event type" action condition values. 1278 * 1279 * If the $type parameter is passed, returns the name of the specific value, otherwise - returns an array of all 1280 * supported values. 1281 * 1282 * @param string $type 1283 * 1284 * @return array|string 1285 */ 1286function eventType($type = null) { 1287 $types = [ 1288 EVENT_TYPE_ITEM_NOTSUPPORTED => _('Item in "not supported" state'), 1289 EVENT_TYPE_LLDRULE_NOTSUPPORTED => _('Low-level discovery rule in "not supported" state'), 1290 EVENT_TYPE_TRIGGER_UNKNOWN => _('Trigger in "unknown" state') 1291 ]; 1292 1293 if (is_null($type)) { 1294 return $types; 1295 } 1296 1297 return $types[$type]; 1298} 1299 1300/** 1301 * Get data required to create messages, severity changes, actions icon with popup with event actions. 1302 * 1303 * @param array $events Array with event objects with acknowledges. 1304 * @param array $triggers Array of triggers. 1305 * 1306 * @return array 1307 */ 1308function getEventsActionsIconsData(array $events, array $triggers): array { 1309 $messages = getEventsMessages($events); 1310 $severities = getEventsSeverityChanges($events, $triggers); 1311 $actions = getEventsAlertsOverview($events); 1312 1313 return [ 1314 'data' => [ 1315 'messages' => $messages['data'], 1316 'severities' => $severities['data'], 1317 'actions' => $actions 1318 ], 1319 'userids' => $messages['userids'] + $severities['userids'] 1320 ]; 1321} 1322 1323/** 1324 * Get data, required to create messages icon with popup with event messages. 1325 * 1326 * @param array $events Array with event objects with acknowledges. 1327 * @param string $events[]['eventid'] Problem event ID. 1328 * @param array $events[]['acknowledges'] Array with manual updates to problem. 1329 * @param string $events[]['acknowledges'][]['action'] Action that was performed by problem update. 1330 * @param string $events[]['acknowledges'][]['message'] Message text. 1331 * @param string $events[]['acknowledges'][]['clock'] Time when message was added. 1332 * @param string $events[]['acknowledges'][]['userid'] Author's userid. 1333 * 1334 * @return array 1335 */ 1336function getEventsMessages(array $events) { 1337 $messages = []; 1338 $userids = []; 1339 1340 // Create array of messages for each event 1341 foreach ($events as $event) { 1342 $event_messages = []; 1343 1344 foreach ($event['acknowledges'] as $ack) { 1345 if (($ack['action'] & ZBX_PROBLEM_UPDATE_MESSAGE) == ZBX_PROBLEM_UPDATE_MESSAGE) { 1346 // Alias is mandatory for each user, so if alias is not returned, we don't have rights for this user. 1347 $event_messages[] = [ 1348 'message' => $ack['message'], 1349 'userid' => $ack['userid'], 1350 'clock' => $ack['clock'] 1351 ]; 1352 1353 $userids[$ack['userid']] = true; 1354 } 1355 } 1356 1357 CArrayHelper::sort($event_messages, [['field' => 'clock', 'order' => ZBX_SORT_DOWN]]); 1358 1359 $messages[$event['eventid']] = [ 1360 'messages' => array_values($event_messages), 1361 'count' => count($event_messages) 1362 ]; 1363 } 1364 1365 return [ 1366 'data' => $messages, 1367 'userids' => $userids 1368 ]; 1369} 1370 1371/** 1372 * Get data, required to create severity changes icon with popup with event severity changes. 1373 * 1374 * @param array $events Array with event objects with acknowledges. 1375 * @param string $events[]['eventid'] Problem event ID. 1376 * @param string $events[]['severity'] Current event severity. 1377 * @param string $events[]['objectid'] Related trigger ID. 1378 * @param array $events[]['acknowledges'] Array with manual updates to problem. 1379 * @param string $events[]['acknowledges'][]['action'] Action that was performed by problem update. 1380 * @param string $events[]['acknowledges'][]['clock'] Time when severity was changed. 1381 * @param string $events[]['acknowledges'][]['old_severity'] Severity before the change. 1382 * @param string $events[]['acknowledges'][]['new_severity'] Severity after the change. 1383 * @param string $events[]['acknowledges'][]['userid'] Responsible user's userid. 1384 * @param array $triggers Related trigger data. 1385 * @param string $triggers[]['priority'] Severity of trigger. 1386 * 1387 * @return array 1388 */ 1389function getEventsSeverityChanges(array $events, array $triggers) { 1390 $severities = []; 1391 $userids = []; 1392 1393 // Create array of messages for each event. 1394 foreach ($events as $event) { 1395 $event_severities = []; 1396 1397 foreach ($event['acknowledges'] as $ack) { 1398 if (($ack['action'] & ZBX_PROBLEM_UPDATE_SEVERITY) == ZBX_PROBLEM_UPDATE_SEVERITY) { 1399 $event_severities[] = [ 1400 'old_severity' => $ack['old_severity'], 1401 'new_severity' => $ack['new_severity'], 1402 'userid' => $ack['userid'], 1403 'clock' => $ack['clock'] 1404 ]; 1405 1406 $userids[$ack['userid']] = true; 1407 } 1408 } 1409 1410 CArrayHelper::sort($event_severities, [['field' => 'clock', 'order' => ZBX_SORT_DOWN]]); 1411 1412 $severities[$event['eventid']] = [ 1413 'severities' => array_values($event_severities), 1414 'count' => count($event_severities), 1415 'original_severity' => $triggers[$event['objectid']]['priority'], 1416 'current_severity' => $event['severity'] 1417 ]; 1418 } 1419 1420 return [ 1421 'data' => $severities, 1422 'userids' => $userids 1423 ]; 1424} 1425 1426/** 1427 * Get data, required to create actions icon. 1428 * 1429 * @param array $events Array with event objects with acknowledges. 1430 * @param string $events[]['eventid'] Problem event ID. 1431 * @param string $events[]['r_eventid'] OK event ID. 1432 * 1433 * @return array List indexed by eventid containing overview on event alerts. 1434 */ 1435function getEventsAlertsOverview(array $events): array { 1436 $alert_eventids = []; 1437 $actions = []; 1438 $event_alert_state = []; 1439 1440 foreach ($events as $event) { 1441 // Get alerts for event. 1442 $alert_eventids[$event['eventid']] = true; 1443 1444 // Get alerts for related recovery events. 1445 if ($event['r_eventid'] != 0) { 1446 $alert_eventids[$event['r_eventid']] = true; 1447 } 1448 } 1449 1450 if ($alert_eventids) { 1451 $event_alert_state = array_combine(array_keys($alert_eventids), array_fill(0, count($alert_eventids), [ 1452 'failed_cnt' => 0, 1453 'in_progress_cnt' => 0, 1454 'total_cnt' => 0 1455 ])); 1456 1457 $alerts = API::Alert()->get([ 1458 'groupCount' => true, 1459 'countOutput' => true, 1460 'filter' => ['status' => ALERT_STATUS_FAILED], 1461 'eventids' => array_keys($alert_eventids) 1462 ]); 1463 1464 foreach ($alerts as $alert) { 1465 $event_alert_state[$alert['eventid']]['failed_cnt'] = (int) $alert['rowscount']; 1466 } 1467 1468 $alerts = API::Alert()->get([ 1469 'groupCount' => true, 1470 'countOutput' => true, 1471 'filter' => ['status' => [ALERT_STATUS_NEW, ALERT_STATUS_NOT_SENT]], 1472 'eventids' => array_keys($alert_eventids) 1473 ]); 1474 1475 foreach ($alerts as $alert) { 1476 $event_alert_state[$alert['eventid']]['in_progress_cnt'] = (int) $alert['rowscount']; 1477 } 1478 1479 $alerts = API::Alert()->get([ 1480 'groupCount' => true, 1481 'countOutput' => true, 1482 'eventids' => array_keys($alert_eventids) 1483 ]); 1484 1485 foreach ($alerts as $alert) { 1486 $event_alert_state[$alert['eventid']]['total_cnt'] = (int) $alert['rowscount']; 1487 } 1488 } 1489 1490 // Create array of actions for each event. 1491 foreach ($events as $event) { 1492 $event_actions = $event_alert_state[$event['eventid']]; 1493 if ($event['r_eventid']) { 1494 $r_event_actions = $event_alert_state[$event['r_eventid']]; 1495 $event_actions['failed_cnt'] += $r_event_actions['failed_cnt']; 1496 $event_actions['total_cnt'] += $r_event_actions['total_cnt']; 1497 $event_actions['in_progress_cnt'] += $r_event_actions['in_progress_cnt']; 1498 } 1499 1500 $actions[$event['eventid']] = [ 1501 'count' => $event_actions['total_cnt'] + count($event['acknowledges']), 1502 'has_uncomplete_action' => (bool) $event_actions['in_progress_cnt'], 1503 'has_failed_action' => (bool) $event_actions['failed_cnt'] 1504 ]; 1505 } 1506 1507 return $actions; 1508} 1509 1510/** 1511 * Get data, required to create table with all (automatic and manual) actions for Event details page. 1512 * 1513 * @param array $event Event object with acknowledges. 1514 * @param string $event['eventid'] Problem event ID. 1515 * @param string $event['r_eventid'] OK event ID. 1516 * 1517 * @return array 1518 */ 1519function getEventDetailsActions(array $event) { 1520 $r_events = []; 1521 1522 // Select eventids for alert retrieval. 1523 $alert_eventids = [$event['eventid']]; 1524 1525 if ($event['r_eventid'] != 0) { 1526 $alert_eventids[] = $event['r_eventid']; 1527 1528 $r_events = API::Event()->get([ 1529 'output' => ['clock'], 1530 'eventids' => $event['r_eventid'], 1531 'preservekeys' => true 1532 ]); 1533 } 1534 1535 $config = select_config(); 1536 1537 // Get automatic actions (alerts). 1538 $alerts = API::Alert()->get([ 1539 'output' => ['alerttype', 'clock', 'error', 'eventid', 'esc_step', 'mediatypeid', 'message', 'retries', 1540 'sendto', 'status', 'subject', 'userid', 'p_eventid', 'acknowledgeid' 1541 ], 1542 'eventids' => $alert_eventids, 1543 'config' => $config['search_limit'] 1544 ]); 1545 1546 $actions = getSingleEventActions($event, $r_events, $alerts); 1547 1548 return [ 1549 'actions' => $actions['actions'], 1550 'mediatypeids' => $actions['mediatypeids'], 1551 'userids' => $actions['userids'], 1552 'count' => $actions['count'] 1553 ]; 1554} 1555 1556/** 1557 * Get array with all actions for single event. 1558 * 1559 * @param array $event Event objects with acknowledges. 1560 * @param string $event['eventid'] Problem event ID. 1561 * @param string $event['r_eventid'] OK event ID. 1562 * @param string $event['clock'] Time when event occurred. 1563 * @param array $event['acknowledges'] Array with manual updates to problem. 1564 * @param string $event['acknowledges'][]['userid'] User ID. 1565 * @param array $r_events Recovery event data for all requested events. 1566 * @param string $r_events[]['clock'] Recovery event creation time. 1567 * @param array $alerts Alert data for all requested alerts. 1568 * @param string $alerts[]['eventid'] If of problem event for which this alert was generated. 1569 * @param string $alerts[]['mediatypeid'] ID for mediatype used for alert. 1570 * @param string $alerts[]['alerttype'] Type of alert. 1571 * @param string $alerts[]['status'] Alert status. 1572 * @param string $alerts[]['userid'] ID of alert recipient. 1573 * 1574 * @return array 1575 */ 1576function getSingleEventActions(array $event, array $r_events, array $alerts) { 1577 $action_count = 0; 1578 $has_uncomplete_action = false; 1579 $has_failed_action = false; 1580 $mediatypeids = []; 1581 $userids = []; 1582 1583 // Create array of automatically and manually performed actions combined. 1584 $actions = []; 1585 1586 // Add row for problem generation event. 1587 $actions[] = [ 1588 'action_type' => ZBX_EVENT_HISTORY_PROBLEM_EVENT, 1589 'clock' => $event['clock'] 1590 ]; 1591 1592 // Add row for problem recovery event. 1593 if (array_key_exists($event['r_eventid'], $r_events)) { 1594 $actions[] = [ 1595 'action_type' => ZBX_EVENT_HISTORY_RECOVERY_EVENT, 1596 'clock' => $r_events[$event['r_eventid']]['clock'] 1597 ]; 1598 } 1599 1600 // Add manual operations. 1601 foreach ($event['acknowledges'] as $ack) { 1602 $ack['action_type'] = ZBX_EVENT_HISTORY_MANUAL_UPDATE; 1603 $actions[] = $ack; 1604 1605 $action_count++; 1606 $userids[$ack['userid']] = true; 1607 } 1608 1609 // Add alerts. 1610 foreach ($alerts as $alert) { 1611 // Add only alerts, related to current event. 1612 if (bccomp($alert['eventid'], $event['eventid']) == 0 1613 || bccomp($alert['eventid'], $event['r_eventid']) == 0) { 1614 $alert['action_type'] = ZBX_EVENT_HISTORY_ALERT; 1615 $actions[] = $alert; 1616 1617 $action_count++; 1618 1619 if ($alert['alerttype'] == ALERT_TYPE_MESSAGE) { 1620 if ($alert['mediatypeid'] != 0) { 1621 $mediatypeids[$alert['mediatypeid']] = true; 1622 } 1623 1624 if ($alert['userid'] != 0) { 1625 $userids[$alert['userid']] = true; 1626 } 1627 } 1628 1629 if ($alert['status'] == ALERT_STATUS_NEW || $alert['status'] == ALERT_STATUS_NOT_SENT) { 1630 $has_uncomplete_action = true; 1631 } 1632 elseif ($alert['status'] == ALERT_STATUS_FAILED) { 1633 $has_failed_action = true; 1634 } 1635 } 1636 } 1637 1638 // Sort by action_type is done to put Recovery event before actions, resulted from it. Same for other action_type. 1639 CArrayHelper::sort($actions, [ 1640 ['field' => 'clock', 'order' => ZBX_SORT_DOWN], 1641 ['field' => 'action_type', 'order' => ZBX_SORT_DOWN] 1642 ]); 1643 1644 return [ 1645 'actions' => array_values($actions), 1646 'count' => $action_count, 1647 'has_uncomplete_action' => $has_uncomplete_action, 1648 'has_failed_action' => $has_failed_action, 1649 'mediatypeids' => $mediatypeids, 1650 'userids' => $userids 1651 ]; 1652} 1653 1654/** 1655 * Get data required to create history list in problem update page. 1656 * 1657 * @param array $event Array with event objects with acknowledges. 1658 * @param array $event['acknowledges'] Array with manual updates to problem. 1659 * @param string $event['acknowledges'][]['clock'] Time when severity was changed. 1660 * @param string $event['acknowledges'][]['userid'] Responsible user's userid. 1661 * 1662 * @return array 1663 */ 1664function getEventUpdates(array $event) { 1665 $userids = []; 1666 1667 foreach ($event['acknowledges'] as $ack) { 1668 $userids[$ack['userid']] = true; 1669 } 1670 1671 CArrayHelper::sort($event['acknowledges'], [['field' => 'clock', 'order' => ZBX_SORT_DOWN]]); 1672 1673 return [ 1674 'data' => array_values($event['acknowledges']), 1675 'userids' => $userids 1676 ]; 1677} 1678 1679/** 1680 * Make icons (messages, severity changes, actions) for actions column. 1681 * 1682 * @param string $eventid Id for event, for which icons are created. 1683 * @param array $actions Array of actions data. 1684 * @param array $actions['messages'] Messages icon data. 1685 * @param array $actions['severities'] Severity change icon data. 1686 * @param array $actions['actions'] Actions icon data. 1687 * @param array $users User name, surname and alias. 1688 * @param array $config Zabbix config. 1689 * 1690 * @return CCol|string 1691 */ 1692function makeEventActionsIcons($eventid, $actions, $users, $config) { 1693 $messages_icon = makeEventMessagesIcon($actions['messages'][$eventid], $users); 1694 $severities_icon = makeEventSeverityChangesIcon($actions['severities'][$eventid], $users, $config); 1695 $actions_icon = makeEventActionsIcon($actions['actions'][$eventid], $eventid); 1696 1697 $action_icons = []; 1698 if ($messages_icon !== null) { 1699 $action_icons[] = $messages_icon; 1700 } 1701 if ($severities_icon !== null) { 1702 $action_icons[] = $severities_icon; 1703 } 1704 if ($actions_icon !== null) { 1705 $action_icons[] = $actions_icon; 1706 } 1707 1708 return $action_icons ? (new CCol($action_icons))->addClass(ZBX_STYLE_NOWRAP) : ''; 1709} 1710 1711/** 1712 * Create icon with hintbox for event messages. 1713 * 1714 * @param array $data 1715 * @param array $data['messages'] Array of messages. 1716 * @param string $data['messages'][]['message'] Message text. 1717 * @param string $data['messages'][]['clock'] Message creation time. 1718 * @param array $users User name, surname and alias. 1719 * 1720 * @return CSpan|null 1721 */ 1722function makeEventMessagesIcon(array $data, array $users) { 1723 $total = $data['count']; 1724 1725 $table = (new CTableInfo())->setHeader([_('Time'), _('User'), _('Message')]); 1726 1727 for ($i = 0; $i < $total && $i < ZBX_WIDGET_ROWS; $i++) { 1728 $message = $data['messages'][$i]; 1729 1730 // Added in order to reuse makeActionTableUser(). 1731 $message['action_type'] = ZBX_EVENT_HISTORY_MANUAL_UPDATE; 1732 1733 $table->addRow([ 1734 zbx_date2str(DATE_TIME_FORMAT_SECONDS, $message['clock']), 1735 makeActionTableUser($message, $users), 1736 zbx_nl2br($message['message']) 1737 ]); 1738 } 1739 1740 return $total 1741 ? makeActionIcon([ 1742 'icon' => ZBX_STYLE_ACTION_ICON_MSGS, 1743 'button' => true, 1744 'hint' => [ 1745 $table, 1746 ($total > ZBX_WIDGET_ROWS) 1747 ? (new CDiv( 1748 (new CDiv( 1749 (new CDiv(_s('Displaying %1$s of %2$s found', ZBX_WIDGET_ROWS, $total))) 1750 ->addClass(ZBX_STYLE_TABLE_STATS) 1751 ))->addClass(ZBX_STYLE_PAGING_BTN_CONTAINER) 1752 ))->addClass(ZBX_STYLE_TABLE_PAGING) 1753 : null 1754 ], 1755 'num' => $total, 1756 'aria-label' => _xn('%1$s message', '%1$s messages', $total, 'screen reader', $total) 1757 ]) 1758 : null; 1759} 1760 1761/** 1762 * Create icon with hintbox for event severity changes. 1763 * 1764 * @param array $data 1765 * @param array $data['severities'] Array of severities. 1766 * @param string $data['severities'][]['old_severity'] Event severity before change. 1767 * @param string $data['severities'][]['new_severity'] Event severity after change. 1768 * @param string $data['severities'][]['clock'] Severity change time. 1769 * @param string $data['original_severity'] Severity before change. 1770 * @param string $data['current_severity'] Current severity. 1771 * @param int $data['count'] Total number of severity changes. 1772 * @param array $users User name, surname and alias. 1773 * @param array $config Zabbix config. 1774 * 1775 * @return CSpan|null 1776 */ 1777function makeEventSeverityChangesIcon(array $data, array $users, array $config) { 1778 $total = $data['count']; 1779 1780 $table = (new CTableInfo())->setHeader([_('Time'), _('User'), _('Severity changes')]); 1781 1782 for ($i = 0; $i < $total && $i < ZBX_WIDGET_ROWS; $i++) { 1783 $severity = $data['severities'][$i]; 1784 1785 // Added in order to reuse makeActionTableUser(). 1786 $severity['action_type'] = ZBX_EVENT_HISTORY_MANUAL_UPDATE; 1787 1788 // severity changes 1789 $old_severity_name = getSeverityName($severity['old_severity'], $config); 1790 $new_severity_name = getSeverityName($severity['new_severity'], $config); 1791 1792 $table->addRow([ 1793 zbx_date2str(DATE_TIME_FORMAT_SECONDS, $severity['clock']), 1794 makeActionTableUser($severity, $users), 1795 $old_severity_name.' ⇒ '.$new_severity_name 1796 ]); 1797 } 1798 1799 // select icon 1800 if ($data['original_severity'] > $data['current_severity']) { 1801 $icon_style = ZBX_STYLE_ACTION_ICON_SEV_DOWN; 1802 $aria_label = _x('Severity decreased', 'screen reader'); 1803 } 1804 elseif ($data['original_severity'] < $data['current_severity']) { 1805 $icon_style = ZBX_STYLE_ACTION_ICON_SEV_UP; 1806 $aria_label = _x('Severity increased', 'screen reader'); 1807 } 1808 else { 1809 $icon_style = ZBX_STYLE_ACTION_ICON_SEV_CHANGED; 1810 $aria_label = _x('Severity changed', 'screen reader'); 1811 } 1812 1813 return $total 1814 ? makeActionIcon([ 1815 'button' => true, 1816 'icon' => $icon_style, 1817 'hint' => [ 1818 $table, 1819 ($total > ZBX_WIDGET_ROWS) 1820 ? (new CDiv( 1821 (new CDiv( 1822 (new CDiv(_s('Displaying %1$s of %2$s found', ZBX_WIDGET_ROWS, $total))) 1823 ->addClass(ZBX_STYLE_TABLE_STATS) 1824 ))->addClass(ZBX_STYLE_PAGING_BTN_CONTAINER) 1825 ))->addClass(ZBX_STYLE_TABLE_PAGING) 1826 : null 1827 ], 1828 'aria-label' => $aria_label 1829 ]) 1830 : null; 1831} 1832 1833/** 1834 * @param array $actions Array with all actions sorted by clock. 1835 * @param int $actions[]['action_type'] Type of action table entry (ZBX_EVENT_HISTORY_*). 1836 * @param string $actions[]['clock'] Time, when action was performed. 1837 * @param string $actions[]['message'] Message sent by alert, or written by manual update, or remote command text. 1838 * @param string $actions[]['action'] Flag with problem update operation performed (only for ZBX_EVENT_HISTORY_MANUAL_UPDATE). 1839 * @param string $actions[]['alerttype'] Type of alert (only for ZBX_EVENT_HISTORY_ALERT). 1840 * @param string $actions[]['mediatypeid'] Id for mediatype, where alert message was sent (only for ZBX_EVENT_HISTORY_ALERT). 1841 * @param string $actions[]['error'] Error message in case of failed alert (only for ZBX_EVENT_HISTORY_ALERT). 1842 * @param array $users User name, surname and alias. 1843 * @param array $mediatypes Mediatypes with maxattempts value and description. 1844 * @param string $mediatypes[]['name'] Mediatype name. 1845 * @param string $mediatypes[]['maxattempts'] Maximum attempts for this mediatype. 1846 * @param array $config Zabbix config. 1847 * 1848 * @return CTableInfo 1849 */ 1850function makeEventActionsTable(array $actions, array $users, array $mediatypes, array $config): CTableInfo { 1851 $action_count = count($actions); 1852 1853 $table = (new CTableInfo())->setHeader([ 1854 _('Time'), _('User/Recipient'), _('Action'), _('Message/Command'), _('Status'), _('Info') 1855 ]); 1856 1857 for ($i = 0; $i < $action_count && $i < ZBX_WIDGET_ROWS; $i++) { 1858 $action = $actions[$i]; 1859 1860 $message = ''; 1861 if ($action['action_type'] == ZBX_EVENT_HISTORY_MANUAL_UPDATE 1862 && ($action['action'] & ZBX_PROBLEM_UPDATE_MESSAGE) == ZBX_PROBLEM_UPDATE_MESSAGE) { 1863 $message = zbx_nl2br($action['message']); 1864 } 1865 elseif ($action['action_type'] == ZBX_EVENT_HISTORY_ALERT) { 1866 if ($action['alerttype'] == ALERT_TYPE_COMMAND) { 1867 $message = _('Remote command'); 1868 } 1869 elseif ($action['alerttype'] == ALERT_TYPE_MESSAGE) { 1870 $message = array_key_exists($action['mediatypeid'], $mediatypes) 1871 ? $mediatypes[$action['mediatypeid']]['name'] 1872 : ''; 1873 } 1874 } 1875 1876 $table->addRow([ 1877 zbx_date2str(DATE_TIME_FORMAT_SECONDS, $action['clock']), 1878 makeActionTableUser($action, $users), 1879 makeActionTableIcon($action, $config), 1880 $message, 1881 makeActionTableStatus($action), 1882 makeActionTableInfo($action, $mediatypes) 1883 ]); 1884 } 1885 1886 return $table; 1887} 1888 1889/** 1890 * Create icon with hintbox for event actions. 1891 * 1892 * @param array $data 1893 * @param int $data['count'] Number of actions. 1894 * @param bool $data['has_uncomplete_action'] Does the event have at least one uncompleted alert action. 1895 * @param bool $data['has_failed_action'] Does the event have at least one failed alert action. 1896 * @param string $eventid 1897 * 1898 * @return CButton|null 1899 */ 1900function makeEventActionsIcon(array $data, $eventid): ?CButton { 1901 // Number of meaningful actions. 1902 $total = $data['count']; 1903 1904 // select icon 1905 if ($data['has_failed_action']) { 1906 $icon_style = ZBX_STYLE_ACTIONS_NUM_RED; 1907 } 1908 elseif ($data['has_uncomplete_action']) { 1909 $icon_style = ZBX_STYLE_ACTIONS_NUM_YELLOW; 1910 } 1911 else { 1912 $icon_style = ZBX_STYLE_ACTIONS_NUM_GRAY; 1913 } 1914 1915 return $total 1916 ? makeActionIcon([ 1917 'icon' => $icon_style, 1918 'button' => true, 1919 'num' => $total, 1920 'aria-label' => _xn('%1$s action', '%1$s actions', $total, 'screen reader', $total) 1921 ])->setAjaxHint([ 1922 'type' => 'eventactions', 1923 'data' => ['eventid' => $eventid] 1924 ]) 1925 : null; 1926} 1927 1928/** 1929 * Get table with list of event actions for event details page. 1930 * 1931 * @param array $data 1932 * @param array $data['actions'] Array with all actions sorted by clock. 1933 * @param int $data['actions'][]['action_type'] Type of action table entry (ZBX_EVENT_HISTORY_*). 1934 * @param string $data['actions'][]['clock'] Time, when action was performed. 1935 * @param string $data['actions'][]['message'] Message sent by alert, or written by manual update, or remote command text. 1936 * @param string $data['actions'][]['alerttype'] Type of alert (only for ZBX_EVENT_HISTORY_ALERT). 1937 * @param string $data['actions'][]['esc_step'] Alert escalation step (only for ZBX_EVENT_HISTORY_ALERT). 1938 * @param string $data['actions'][]['subject'] Message alert subject (only for ZBX_EVENT_HISTORY_ALERT). 1939 * @param string $data['actions'][]['p_eventid'] Problem eventid that was reason for alert (only for ZBX_EVENT_HISTORY_ALERT). 1940 * @param string $data['actions'][]['acknowledgeid'] Problem update action that was reason for alert (only for ZBX_EVENT_HISTORY_ALERT). 1941 * @param array $users User name, surname and alias. 1942 * @param array $mediatypes Mediatypes with maxattempts value. 1943 * @param array $config Zabbix config. 1944 * 1945 * @return CTableInfo 1946 */ 1947function makeEventDetailsActionsTable(array $data, array $users, array $mediatypes, array $config) { 1948 $table = (new CTableInfo())->setHeader([ 1949 _('Step'), _('Time'), _('User/Recipient'), _('Action'), _('Message/Command'), _('Status'), _('Info') 1950 ]); 1951 1952 foreach ($data['actions'] as $action) { 1953 $esc_step = ''; 1954 1955 if ($action['action_type'] == ZBX_EVENT_HISTORY_ALERT && $action['p_eventid'] == 0 1956 && $action['acknowledgeid'] == 0) { 1957 /* 1958 * Escalation step should be displayed, only if alert is caused by problem event. 1959 * Escalation step should not be displayed, if alert is caused by resolve event, or by problem update. 1960 */ 1961 $esc_step = $action['esc_step']; 1962 } 1963 1964 $message = ''; 1965 if ($action['action_type'] == ZBX_EVENT_HISTORY_ALERT && $action['alerttype'] == ALERT_TYPE_MESSAGE) { 1966 $message = [bold($action['subject']), BR(), BR(), zbx_nl2br($action['message'])]; 1967 } 1968 elseif (($action['action_type'] == ZBX_EVENT_HISTORY_ALERT && $action['alerttype'] == ALERT_TYPE_COMMAND) 1969 || $action['action_type'] == ZBX_EVENT_HISTORY_MANUAL_UPDATE) { 1970 $message = zbx_nl2br($action['message']); 1971 } 1972 1973 $table->addRow([ 1974 $esc_step, 1975 zbx_date2str(DATE_TIME_FORMAT_SECONDS, $action['clock']), 1976 makeEventDetailsTableUser($action, $users), 1977 makeActionTableIcon($action, $config), 1978 $message, 1979 makeActionTableStatus($action), 1980 makeActionTableInfo($action, $mediatypes) 1981 ]); 1982 } 1983 1984 return $table; 1985} 1986 1987/** 1988 * Get table with list of event updates for update event page. 1989 * 1990 * @param array $actions Array with all actions sorted by clock. 1991 * @param string $actions[]['clock'] Time, when action was performed. 1992 * @param string $actions[]['message'] Message sent by alert, or written by manual update, or remote command text. 1993 * @param array $users User name, surname and alias. 1994 * @param array $config Zabbix config. 1995 * 1996 * @return CTable 1997 */ 1998function makeEventHistoryTable(array $actions, array $users, array $config) { 1999 $table = (new CTable()) 2000 ->addStyle('width: 100%;') 2001 ->setHeader([_('Time'), _('User'), _('User action'), _('Message')]); 2002 2003 foreach ($actions as $action) { 2004 // Added in order to reuse makeActionTableUser() and makeActionTableIcon() 2005 $action['action_type'] = ZBX_EVENT_HISTORY_MANUAL_UPDATE; 2006 2007 $table->addRow([ 2008 zbx_date2str(DATE_TIME_FORMAT_SECONDS, $action['clock']), 2009 makeActionTableUser($action, $users), 2010 makeActionTableIcon($action, $config), 2011 (new CCol(zbx_nl2br($action['message'])))->addClass(ZBX_STYLE_TABLE_FORMS_OVERFLOW_BREAK) 2012 ]); 2013 } 2014 2015 return $table; 2016} 2017 2018/** 2019 * Creates username for message author or alert receiver. 2020 * 2021 * @param array $action Array of action data. 2022 * @param int $action['action_type'] Type of event table action (ZBX_EVENT_HISTORY_*). 2023 * @param string $action['alerttype'] Type of alert. 2024 * @param string $action['userid'] ID of message author, or alert receiver. 2025 * @param array $users Array with user data - alias, name, surname. 2026 * 2027 * @return string 2028 */ 2029function makeActionTableUser(array $action, array $users) { 2030 if (($action['action_type'] == ZBX_EVENT_HISTORY_ALERT && $action['alerttype'] == ALERT_TYPE_MESSAGE) 2031 || $action['action_type'] == ZBX_EVENT_HISTORY_MANUAL_UPDATE) { 2032 return array_key_exists($action['userid'], $users) 2033 ? getUserFullname($users[$action['userid']]) 2034 : _('Inaccessible user'); 2035 } 2036 else { 2037 return ''; 2038 } 2039} 2040 2041/** 2042 * Creates username for message author or alert receiver. Also contains 'sendto' for message actions. 2043 * 2044 * @param array $action 2045 * @param int $action['action_type'] Type of event table action (ZBX_EVENT_HISTORY_*). 2046 * @param string $action['alerttype'] Type of alert. 2047 * @param array $action['userid'] ID of message author, or alert receiver. 2048 * @param array $action['sendto'] Receiver media address for automatic action. 2049 * @param array $users Array with user data - alias, name, surname. 2050 * 2051 * @return string 2052 */ 2053function makeEventDetailsTableUser(array $action, array $users) { 2054 if ($action['action_type'] == ZBX_EVENT_HISTORY_ALERT && $action['alerttype'] == ALERT_TYPE_MESSAGE) { 2055 return array_key_exists($action['userid'], $users) 2056 ? [getUserFullname($users[$action['userid']]), BR(), italic(zbx_nl2br($action['sendto']))] 2057 : _('Inaccessible user'); 2058 } 2059 elseif ($action['action_type'] == ZBX_EVENT_HISTORY_MANUAL_UPDATE) { 2060 return array_key_exists($action['userid'], $users) 2061 ? getUserFullname($users[$action['userid']]) 2062 : _('Inaccessible user'); 2063 } 2064 else { 2065 return ''; 2066 } 2067} 2068 2069/** 2070 * Make appropriate icon for event action. 2071 * 2072 * @param array $action Array with actions table data. 2073 * @param int $action['action_type'] Type of action table entry (ZBX_EVENT_HISTORY_*). 2074 * @param int $action['action'] Flag with problem update operation performed. (only for ZBX_EVENT_HISTORY_MANUAL_UPDATE) 2075 * @param int $action['old_severity'] Severity before problem update. (only for ZBX_EVENT_HISTORY_MANUAL_UPDATE) 2076 * @param int $action['new_severity'] Severity after problem update. (only for ZBX_EVENT_HISTORY_MANUAL_UPDATE) 2077 * @param int $action['alerttype'] Type of alert. (only for ZBX_EVENT_HISTORY_ALERT) 2078 * @param array $config Zabbix config. 2079 * 2080 * @return CSpan 2081 */ 2082function makeActionTableIcon(array $action, array $config) { 2083 switch ($action['action_type']) { 2084 case ZBX_EVENT_HISTORY_PROBLEM_EVENT: 2085 return makeActionIcon(['icon' => ZBX_STYLE_PROBLEM_GENERATED, 'title' => _('Problem created')]); 2086 2087 case ZBX_EVENT_HISTORY_RECOVERY_EVENT: 2088 return makeActionIcon(['icon' => ZBX_STYLE_PROBLEM_RECOVERY, 'title' => _('Problem resolved')]); 2089 2090 case ZBX_EVENT_HISTORY_MANUAL_UPDATE: 2091 $action_icons = []; 2092 2093 if (($action['action'] & ZBX_PROBLEM_UPDATE_CLOSE) == ZBX_PROBLEM_UPDATE_CLOSE) { 2094 $action_icons[] = makeActionIcon([ 2095 'icon' => ZBX_STYLE_ACTION_ICON_CLOSE, 2096 'title' => _('Manually closed') 2097 ]); 2098 } 2099 2100 if (($action['action'] & ZBX_PROBLEM_UPDATE_ACKNOWLEDGE) == ZBX_PROBLEM_UPDATE_ACKNOWLEDGE) { 2101 $action_icons[] = makeActionIcon(['icon' => ZBX_STYLE_ACTION_ICON_ACK, 'title' => _('Acknowledged')]); 2102 } 2103 2104 if (($action['action'] & ZBX_PROBLEM_UPDATE_UNACKNOWLEDGE) == ZBX_PROBLEM_UPDATE_UNACKNOWLEDGE) { 2105 $action_icons[] = makeActionIcon(['icon' => ZBX_STYLE_ACTION_ICON_UNACK, 'title' => _('Unacknowledged')]); 2106 } 2107 2108 if (($action['action'] & ZBX_PROBLEM_UPDATE_MESSAGE) == ZBX_PROBLEM_UPDATE_MESSAGE) { 2109 $action_icons[] = makeActionIcon(['icon' => ZBX_STYLE_ACTION_ICON_MSG, 'title' => _('Message')]); 2110 } 2111 2112 if (($action['action'] & ZBX_PROBLEM_UPDATE_SEVERITY) == ZBX_PROBLEM_UPDATE_SEVERITY) { 2113 $action_type = ($action['new_severity'] > $action['old_severity']) 2114 ? ZBX_STYLE_ACTION_ICON_SEV_UP 2115 : ZBX_STYLE_ACTION_ICON_SEV_DOWN; 2116 2117 $old_severity_name = getSeverityName($action['old_severity'], $config); 2118 $new_severity_name = getSeverityName($action['new_severity'], $config); 2119 $hint = $old_severity_name.' ⇒ '.$new_severity_name; 2120 2121 $action_icons[] = makeActionIcon(['button' => true, 'icon' => $action_type, 'hint' => $hint]); 2122 } 2123 2124 return (new CCol($action_icons))->addClass(ZBX_STYLE_NOWRAP); 2125 2126 case ZBX_EVENT_HISTORY_ALERT: 2127 $action_icon = ($action['alerttype'] == ALERT_TYPE_COMMAND) 2128 ? ZBX_STYLE_ACTION_COMMAND 2129 : ZBX_STYLE_ACTION_MESSAGE; 2130 $title = ($action['alerttype'] == ALERT_TYPE_COMMAND) 2131 ? _('Remote command') 2132 : _('Alert message'); 2133 2134 return makeActionIcon(['icon' => $action_icon, 'title' => $title]); 2135 } 2136} 2137 2138/** 2139 * Creates span with alert status text. 2140 * 2141 * @param array $action 2142 * @param int $action['action_type'] Type of event table action (ZBX_EVENT_HISTORY_*). 2143 * @param string $action['status'] Alert status. 2144 * @param string $action['alerttype'] Type of alert. 2145 * 2146 * @return CSpan|string 2147 */ 2148function makeActionTableStatus(array $action) { 2149 if ($action['action_type'] == ZBX_EVENT_HISTORY_ALERT) { 2150 switch ($action['status']) { 2151 case ALERT_STATUS_SENT: 2152 $status_label = ($action['alerttype'] == ALERT_TYPE_COMMAND) 2153 ? _('Executed') 2154 : _('Sent'); 2155 $status_color = ZBX_STYLE_GREEN; 2156 break; 2157 2158 case ALERT_STATUS_NEW: 2159 case ALERT_STATUS_NOT_SENT: 2160 $status_label = _('In progress'); 2161 $status_color = ZBX_STYLE_YELLOW; 2162 break; 2163 2164 default: 2165 $status_label = _('Failed'); 2166 $status_color = ZBX_STYLE_RED; 2167 break; 2168 } 2169 2170 return (new CSpan($status_label))->addClass($status_color); 2171 } 2172 else { 2173 return ''; 2174 } 2175} 2176 2177/** 2178 * Creates div with alert info icons. 2179 * 2180 * @param array $action 2181 * @param int $action['action_type'] Type of event table action (ZBX_EVENT_HISTORY_*). 2182 * @param string $action['status'] Alert status. 2183 * @param string $action['alerttype'] Type of alert. 2184 * @param string $action['mediatypeid'] ID for mediatype, where alert message was sent. 2185 * @param string $action['retries'] How many retries was done for pending alert message. 2186 * @param array $mediatypes Array of media type data. 2187 * @param array $mediatypes[]['maxattempts'] Maximum attempts for this mediatype. 2188 * 2189 * @return CDiv|string 2190 */ 2191function makeActionTableInfo(array $action, array $mediatypes) { 2192 if ($action['action_type'] == ZBX_EVENT_HISTORY_ALERT) { 2193 $info_icons = []; 2194 2195 if ($action['alerttype'] == ALERT_TYPE_MESSAGE 2196 && ($action['status'] == ALERT_STATUS_NEW || $action['status'] == ALERT_STATUS_NOT_SENT)) { 2197 $info_icons[] = makeWarningIcon(array_key_exists($action['mediatypeid'], $mediatypes) 2198 ? _n('%1$s retry left', '%1$s retries left', 2199 $mediatypes[$action['mediatypeid']]['maxattempts'] - $action['retries'] 2200 ) 2201 : '' 2202 ); 2203 } 2204 elseif ($action['error'] !== '') { 2205 $info_icons[] = makeErrorIcon($action['error']); 2206 } 2207 2208 return makeInformationList($info_icons); 2209 } 2210 else { 2211 return ''; 2212 } 2213} 2214