You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

874 lines
27 KiB

1 year ago
<?php
/*
** Zabbix
** Copyright (C) 2001-2023 Zabbix SIA
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
/**
* Returns all supported event source-object pairs.
*/
function eventSourceObjects(): array {
return [
['source' => EVENT_SOURCE_TRIGGERS, 'object' => EVENT_OBJECT_TRIGGER],
['source' => EVENT_SOURCE_DISCOVERY, 'object' => EVENT_OBJECT_DHOST],
['source' => EVENT_SOURCE_DISCOVERY, 'object' => EVENT_OBJECT_DSERVICE],
['source' => EVENT_SOURCE_AUTOREGISTRATION, 'object' => EVENT_OBJECT_AUTOREGHOST],
['source' => EVENT_SOURCE_INTERNAL, 'object' => EVENT_OBJECT_TRIGGER],
['source' => EVENT_SOURCE_INTERNAL, 'object' => EVENT_OBJECT_ITEM],
['source' => EVENT_SOURCE_INTERNAL, 'object' => EVENT_OBJECT_LLDRULE],
['source' => EVENT_SOURCE_SERVICE, 'object' => EVENT_OBJECT_SERVICE]
];
}
function get_events_unacknowledged($db_element, $value_trigger = null, $value_event = null, $ack = false) {
$elements = ['hosts' => [], 'hosts_groups' => [], 'triggers' => []];
get_map_elements($db_element, $elements);
if (empty($elements['hosts_groups']) && empty($elements['hosts']) && empty($elements['triggers'])) {
return 0;
}
$options = [
'output' => ['triggerid'],
'monitored' => 1,
'skipDependent' => 1,
'limit' => CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT) + 1
];
if (!is_null($value_trigger)) {
$options['filter'] = ['value' => $value_trigger];
}
if (!empty($elements['hosts_groups'])) {
$options['groupids'] = array_unique($elements['hosts_groups']);
}
if (!empty($elements['hosts'])) {
$options['hostids'] = array_unique($elements['hosts']);
}
if (!empty($elements['triggers'])) {
$options['triggerids'] = array_unique($elements['triggers']);
}
$triggerids = API::Trigger()->get($options);
return API::Event()->get([
'source' => EVENT_SOURCE_TRIGGERS,
'object' => EVENT_OBJECT_TRIGGER,
'countOutput' => true,
'objectids' => zbx_objectValues($triggerids, 'triggerid'),
'filter' => [
'value' => $value_event,
'acknowledged' => $ack ? 1 : 0
]
]);
}
/**
*
* @param array $event An array of event data.
* @param string $event['eventid'] Event ID.
* @param string $event['r_eventid'] OK event ID.
* @param string $event['cause_eventid'] Cause event ID.
* @param string $event['correlationid'] OK Event correlation ID.
* @param string $event['userid'] User ID who generated the OK event.
* @param string $event['name'] Event name.
* @param string $event['acknowledged'] State of acknowledgement.
* @param CCOl $event['opdata'] Operational data with expanded macros.
* @param string $event['comments'] Trigger description with expanded macros.
* @param array $allowed An array of user role rules.
* @param bool $allowed['ui_correlation'] Whether user is allowed to visit event correlation page.
*
* @return CTableInfo
*/
function make_event_details(array $event, array $allowed) {
$is_acknowledged = ($event['acknowledged'] == EVENT_ACKNOWLEDGED);
$table = (new CTableInfo())
->addRow([
_('Event'),
(new CCol($event['name']))->addClass(ZBX_STYLE_WORDWRAP)
])
->addRow([
_('Operational data'),
$event['opdata']->addClass(ZBX_STYLE_WORDBREAK)
])
->addRow([
_('Severity'),
CSeverityHelper::makeSeverityCell((int) $event['severity'])
])
->addRow([
_('Time'),
zbx_date2str(DATE_TIME_FORMAT_SECONDS, $event['clock'])
])
->addRow([
_('Acknowledged'),
(new CSpan($is_acknowledged ? _('Yes') : _('No')))->addClass(
$is_acknowledged ? ZBX_STYLE_GREEN : ZBX_STYLE_RED
)
]);
if ($event['r_eventid'] != 0) {
if ($event['correlationid'] != 0) {
$correlations = API::Correlation()->get([
'output' => ['correlationid', 'name'],
'correlationids' => [$event['correlationid']]
]);
if ($correlations) {
if ($allowed['ui_correlation']) {
$correlation_name = (new CLink($correlations[0]['name'],
(new CUrl('zabbix.php'))
->setArgument('action', 'correlation.edit')
->setArgument('correlationid', $correlations[0]['correlationid'])
->getUrl()
))->addClass(ZBX_STYLE_LINK_ALT);
}
else {
$correlation_name = $correlations[0]['name'];
}
}
else {
$correlation_name = _('Event correlation rule');
}
$table->addRow([_('Resolved by'), $correlation_name]);
}
elseif ($event['userid'] != 0) {
if ($event['userid'] == CWebUser::$data['userid']) {
$table->addRow([_('Resolved by'), getUserFullname([
'username' => CWebUser::$data['username'],
'name' => CWebUser::$data['name'],
'surname' => CWebUser::$data['surname']
])]);
}
else {
$user = API::User()->get([
'output' => ['username', 'name', 'surname'],
'userids' => [$event['userid']]
]);
if ($user) {
$table->addRow([_('Resolved by'), getUserFullname($user[0])]);
}
else {
$table->addRow([_('Resolved by'), _('Inaccessible user')]);
}
}
}
else {
$table->addRow([_('Resolved by'), _('Trigger')]);
}
}
$tags = makeTags([$event]);
$table
->addRow([_('Tags'), $tags[$event['eventid']]])
->addRow([_('Description'), (new CDiv(zbx_str2links($event['comments'])))->addClass(ZBX_STYLE_WORDBREAK)]);
if ($event['cause_eventid'] == 0) {
$table->addRow([_('Rank'), _('Cause')]);
}
else {
$cause_event = API::Event()->get([
'output' => ['name', 'objectid'],
'eventids' => $event['cause_eventid']
]);
if ($cause_event) {
$cause_event = reset($cause_event);
$has_trigger = (bool) API::Trigger()->get([
'output' => [],
'triggerids' => [$cause_event['objectid']]
]);
$table->addRow([_('Rank'),
[
_('Symptom'),
' (',
$has_trigger
? new CLink(
$cause_event['name'],
(new CUrl('tr_events.php'))
->setArgument('triggerid', $cause_event['objectid'])
->setArgument('eventid', $event['cause_eventid'])
)
: $cause_event['name'],
')'
]
]);
}
}
return $table;
}
/**
* Check if event status is UPDATING depending on acknowledges task ID.
*
* @param bool $in_closing True if problem is in CLOSING state.
* @param array $event Event data.
* @param array $event['acknowledges'] List of event acknowledges.
* @param int $event['acknowledges'][]['action'] Event action type.
* @param string $event['acknowledges'][]['taskid'] Task ID.
*
* @return bool
*/
function isEventUpdating(bool $in_closing, array $event): bool {
$in_updating = false;
if (!$in_closing) {
foreach ($event['acknowledges'] as $acknowledge) {
if (($acknowledge['action'] & ZBX_PROBLEM_UPDATE_RANK_TO_CAUSE) ==
ZBX_PROBLEM_UPDATE_RANK_TO_CAUSE
|| ($acknowledge['action'] & ZBX_PROBLEM_UPDATE_RANK_TO_SYMPTOM) ==
ZBX_PROBLEM_UPDATE_RANK_TO_SYMPTOM) {
// If currently is cause or symptom and there is an active task.
if ($acknowledge['taskid'] != 0) {
$in_updating = true;
break;
}
}
}
}
return $in_updating;
}
/**
* Calculate and return a rank change icon depending on current event rank change. If event is currently a cause event
* and it is undergoing a rank change, return cause event icon. If event is currently a symptom event and it is
* undergoing a rank change, return symptom event icon. Icon can be displayed regarless if current status is in closing.
*
* @param array $event Event data.
* @param array $event['acknowledges'] List of event acknowledges.
* @param int $event['acknowledges'][]['action'] Event action type.
* @param string $event['acknowledges'][]['taskid'] Task ID.
*
* @return Ctag|null
*/
function getEventStatusUpdateIcon(array $event): ?Ctag {
$icon = null;
$icon_class = '';
foreach ($event['acknowledges'] as $acknowledge) {
// If currently is symptom and there is an active task to convert to cause, set icon style to cause.
if (($acknowledge['action'] & ZBX_PROBLEM_UPDATE_RANK_TO_CAUSE) == ZBX_PROBLEM_UPDATE_RANK_TO_CAUSE
&& $acknowledge['taskid'] != 0) {
$icon_class = ZBX_ICON_ARROW_RIGHT_TOP;
break;
}
// If currently is cause and there is an active task to convert to symptom, set icon style to symptom.
if (($acknowledge['action'] & ZBX_PROBLEM_UPDATE_RANK_TO_SYMPTOM) ==
ZBX_PROBLEM_UPDATE_RANK_TO_SYMPTOM && $acknowledge['taskid'] != 0) {
$icon_class = ZBX_ICON_ARROW_TOP_RIGHT;
break;
}
}
if ($icon_class !== '') {
$icon = (new CSpan())
->addClass($icon_class)
->addClass('js-blink')
->setTitle(_('Updating'));
}
return $icon;
}
/**
* Calculate and return event status string: PROBLEM, RESOLVED, CLOSING or UPDATING depending on acknowledges task ID.
*
* @param bool $in_closing True if problem is in CLOSING state.
* @param array $event Event data.
*
* @return string
*/
function getEventStatusString(bool $in_closing, array $event): string {
if ($event['r_eventid'] != 0) {
$value_str = isEventUpdating($in_closing, $event) ? _('UPDATING') : _('RESOLVED');
}
else {
if ($in_closing) {
$value_str = _('CLOSING');
}
else {
$value_str = isEventUpdating($in_closing, $event) ? _('UPDATING') : _('PROBLEM');
}
}
return $value_str;
}
/**
*
* @param array $startEvent An array of event data.
* @param string $startEvent['eventid'] Event ID.
* @param string $startEvent['objectid'] Object ID.
* @param array $allowed An array of user role rules.
* @param bool $allowed['add_comments'] Whether user is allowed to add problems comments.
* @param bool $allowed['change_severity'] Whether user is allowed to change problems severity.
* @param bool $allowed['acknowledge'] Whether user is allowed to acknowledge problems.
* @param bool $allowed['close'] Whether user is allowed to close problems.
* @param bool $allowed['suppress_problems'] Whether user is allowed to suppress/unsuppress problems.
* @param bool $allowed['rank_change'] Whether user is allowed to change problem ranking.
*
* @return CTableInfo
*/
function make_small_eventlist(array $startEvent, array $allowed) {
$table = (new CTableInfo())
->setHeader([
_('Time'),
_('Recovery time'),
_('Status'),
_('Age'),
_('Duration'),
_('Update'),
_('Actions')
]);
$events = API::Event()->get([
'output' => ['eventid', 'source', 'object', 'objectid', 'acknowledged', 'clock', 'ns', 'severity', 'r_eventid',
'cause_eventid'
],
'selectAcknowledges' => ['userid', 'clock', 'message', 'action', 'old_severity', 'new_severity',
'suppress_until', 'taskid'
],
'source' => EVENT_SOURCE_TRIGGERS,
'object' => EVENT_OBJECT_TRIGGER,
'value' => TRIGGER_VALUE_TRUE,
'objectids' => $startEvent['objectid'],
'eventid_till' => $startEvent['eventid'],
'sortfield' => ['clock', 'eventid'],
'sortorder' => ZBX_SORT_DOWN,
'limit' => 20,
'preservekeys' => true
]);
$r_eventids = [];
foreach ($events as $event) {
$r_eventids[$event['r_eventid']] = true;
}
unset($r_eventids[0]);
$r_events = $r_eventids
? API::Event()->get([
'output' => ['clock'],
'source' => EVENT_SOURCE_TRIGGERS,
'object' => EVENT_OBJECT_TRIGGER,
'eventids' => array_keys($r_eventids),
'preservekeys' => true
])
: [];
$triggerids = [];
foreach ($events as &$event) {
$triggerids[] = $event['objectid'];
$event['r_clock'] = array_key_exists($event['r_eventid'], $r_events)
? $r_events[$event['r_eventid']]['clock']
: 0;
}
unset($event);
// Get trigger severities.
$triggers = $triggerids
? API::Trigger()->get([
'output' => ['priority', 'manual_close'],
'triggerids' => $triggerids,
'preservekeys' => true
])
: [];
$actions = getEventsActionsIconsData($events, $triggers);
$users = API::User()->get([
'output' => ['username', 'name', 'surname'],
'userids' => array_keys($actions['userids']),
'preservekeys' => true
]);
foreach ($events as $event) {
$duration = ($event['r_eventid'] != 0)
? zbx_date2age($event['clock'], $event['r_clock'])
: zbx_date2age($event['clock']);
$can_be_closed = $allowed['close'];
$in_closing = false;
if ($event['r_eventid'] != 0) {
$value = TRIGGER_VALUE_FALSE;
$value_clock = $event['r_clock'];
$can_be_closed = false;
}
else {
if (hasEventCloseAction($event['acknowledges'])) {
$in_closing = true;
$can_be_closed = false;
}
$value = $in_closing ? TRIGGER_VALUE_FALSE : TRIGGER_VALUE_TRUE;
$value_clock = $in_closing ? time() : $event['clock'];
}
$value_str = getEventStatusString($in_closing, $event);
$is_acknowledged = ($event['acknowledged'] == EVENT_ACKNOWLEDGED);
$cell_status = new CSpan($value_str);
if (isEventUpdating($in_closing, $event)) {
$cell_status->addClass('js-blink');
}
/*
* Add colors to span depending on configuration and trigger parameters. No blinking added to status,
* since the page is not on autorefresh.
*/
addTriggerValueStyle($cell_status, $value, $value_clock, $is_acknowledged);
// Create acknowledge link.
$problem_update_link = ($allowed['add_comments'] || $allowed['change_severity'] || $allowed['acknowledge']
|| $can_be_closed || $allowed['suppress_problems'] || $allowed['rank_change'])
? (new CLink(_('Update')))
->addClass(ZBX_STYLE_LINK_ALT)
->setAttribute('data-eventid', $event['eventid'])
->onClick('acknowledgePopUp({eventids: [this.dataset.eventid]}, this);')
: new CSpan(_('Update'));
$table->addRow([
(new CLink(zbx_date2str(DATE_TIME_FORMAT_SECONDS, $event['clock']),
'tr_events.php?triggerid='.$event['objectid'].'&eventid='.$event['eventid']
))->addClass('action'),
($event['r_eventid'] == 0)
? ''
: (new CLink(zbx_date2str(DATE_TIME_FORMAT_SECONDS, $event['r_clock']),
'tr_events.php?triggerid='.$event['objectid'].'&eventid='.$event['eventid']
))->addClass('action'),
$cell_status,
zbx_date2age($event['clock']),
$duration,
$problem_update_link,
makeEventActionsIcons($event['eventid'], $actions['data'], $users, $is_acknowledged)
]);
}
return $table;
}
/**
* Checks if event is closed.
*
* @param array $event Event object.
* @param array $event['r_eventid'] OK event id. 0 if not resolved.
* @param array $event['acknowledges'] List of problem updates.
* @param int $event['acknowledges'][]['action'] Action performed in update.
*
* @return bool
*/
function isEventClosed(array $event): bool {
if ($event['r_eventid'] != 0) {
return true;
}
else {
return hasEventCloseAction($event['acknowledges']);
}
}
/**
* Checks if event has manual close action.
*
* @param array $event Event object.
* @param array $event['acknowledges'] List of problem updates.
* @param int $event['acknowledges'][]['action'] Action performed in update.
*
* @return bool
*/
function hasEventCloseAction(array $acknowledges): bool {
foreach ($acknowledges as $acknowledge) {
if (($acknowledge['action'] & ZBX_PROBLEM_UPDATE_CLOSE) == ZBX_PROBLEM_UPDATE_CLOSE) {
// If at least one manual close update was found, event is closing.
return true;
}
}
return false;
}
/**
* Returns true if event is suppressed and not unsuppressed after that.
*
* @param array $acknowledges
* @param int $acknowledges['action']
* @param ?array $unsuppression_action [OUT] Variable to store suppression action data.
*
* @return bool
*/
function isEventRecentlySuppressed(array $acknowledges, &$suppression_action = null): bool {
CArrayHelper::sort($acknowledges, [['field' => 'clock', 'order' => ZBX_SORT_DOWN]]);
foreach ($acknowledges as $ack) {
if (!array_key_exists('suppress_until', $ack)) {
continue;
}
if (($ack['action'] & ZBX_PROBLEM_UPDATE_UNSUPPRESS) == ZBX_PROBLEM_UPDATE_UNSUPPRESS) {
return false;
}
elseif (($ack['action'] & ZBX_PROBLEM_UPDATE_SUPPRESS) == ZBX_PROBLEM_UPDATE_SUPPRESS) {
if ($ack['suppress_until'] == ZBX_PROBLEM_SUPPRESS_TIME_INDEFINITE || $ack['suppress_until'] > time()) {
$suppression_action = $ack;
return true;
}
break;
}
}
return false;
}
/**
* Returns true if event is unsuppressed and not suppressed after that.
*
* @param array $acknowledges
* @param int $acknowledges['action']
* @param ?array $unsuppression_action [OUT] Variable to store unsuppression action data.
*
* @return bool
*/
function isEventRecentlyUnsuppressed(array $acknowledges, &$unsuppression_action = null): bool {
CArrayHelper::sort($acknowledges, [['field' => 'clock', 'order' => ZBX_SORT_DOWN]]);
foreach ($acknowledges as $ack) {
if (($ack['action'] & ZBX_PROBLEM_UPDATE_SUPPRESS) == ZBX_PROBLEM_UPDATE_SUPPRESS) {
return false;
}
elseif (($ack['action'] & ZBX_PROBLEM_UPDATE_UNSUPPRESS) == ZBX_PROBLEM_UPDATE_UNSUPPRESS) {
$unsuppression_action = $ack;
return true;
}
}
return false;
}
/**
* Place filter tags at the beginning of tags array.
*
* @param array $event_tags
* @param string $event_tags[]['tag']
* @param string $event_tags[]['value']
* @param array $f_tags
* @param int $f_tags[<tag>][]['operator']
* @param string $f_tags[<tag>][]['value']
*
* @return array
*/
function orderEventTags(array $event_tags, array $f_tags) {
$first_tags = [];
foreach ($event_tags as $i => $tag) {
if (array_key_exists($tag['tag'], $f_tags)) {
foreach ($f_tags[$tag['tag']] as $f_tag) {
if (($f_tag['operator'] == TAG_OPERATOR_EQUAL && $tag['value'] === $f_tag['value'])
|| ($f_tag['operator'] == TAG_OPERATOR_LIKE
&& ($f_tag['value'] === '' || stripos($tag['value'], $f_tag['value']) !== false))) {
$first_tags[] = $tag;
unset($event_tags[$i]);
break;
}
}
}
}
return array_merge($first_tags, $event_tags);
}
/**
* Place priority tags at the beginning of tags array.
*
* @param array $event_tags An array of event tags.
* @param string $event_tags[]['tag'] Tag name.
* @param string $event_tags[]['value'] Tag value.
* @param array $priorities An array of priority tag names.
*
* @return array
*/
function orderEventTagsByPriority(array $event_tags, array $priorities) {
$first_tags = [];
foreach ($priorities as $priority) {
foreach ($event_tags as $i => $tag) {
if ($tag['tag'] === $priority) {
$first_tags[] = $tag;
unset($event_tags[$i]);
}
}
}
return array_merge($first_tags, $event_tags);
}
/**
* Create element with tags.
*
* @param array $list
* @param string $list[][$key]
* @param array $list[]['tags']
* @param string $list[]['tags'][]['tag']
* @param string $list[]['tags'][]['value']
* @param bool $html
* @param string $key Name of tag source ID. Possible values:
* - 'eventid' - for events and problems (default);
* - 'hostid' - for hosts and host prototypes;
* - 'templateid' - for templates;
* - 'triggerid' - for triggers;
* - 'httptestid' - for web scenarios.
* @param int $list_tag_count Maximum number of tags to display.
* @param array $filter_tags An array of tag filtering data.
* @param ?array $subfilter_tags Array of selected sub-filter tags. Null when tags are not clickable.
* @param array $subfilter_tags[<tag>]
* @param array $subfilter_tags[<tag>][<value1>]
* @param array $subfilter_tags[<tag>][<value2>]
* @param array $subfilter_tags[<tag>][<value...>]
* @param string $filter_tags[]['tag']
* @param int $filter_tags[]['operator']
* @param string $filter_tags[]['value']
* @param int $tag_name_format Tag name format. Possible values:
* - TAG_NAME_FULL (default);
* - TAG_NAME_SHORTENED;
* - TAG_NAME_NONE.
* @param string $tag_priority A list of comma-separated tag names.
*
* @return array
*/
function makeTags(array $list, bool $html = true, string $key = 'eventid', int $list_tag_count = ZBX_TAG_COUNT_DEFAULT,
array $filter_tags = [], ?array $subfilter_tags = null, int $tag_name_format = TAG_NAME_FULL,
string $tag_priority = ''): array {
$tags = [];
if ($html) {
// Convert $filter_tags to a more usable format.
$f_tags = [];
foreach ($filter_tags as $tag) {
$f_tags[$tag['tag']][] = [
'operator' => $tag['operator'],
'value' => $tag['value']
];
}
}
if ($tag_priority !== '') {
$p_tags = explode(',', $tag_priority);
$p_tags = array_map('trim', $p_tags);
}
foreach ($list as $element) {
$tags[$element[$key]] = [];
if (!$element['tags']) {
continue;
}
CArrayHelper::sort($element['tags'], ['tag', 'value']);
if ($html) {
// Show first n tags and "..." with hint box if there are more.
$e_tags = $f_tags ? orderEventTags($element['tags'], $f_tags) : $element['tags'];
if ($tag_priority !== '') {
$e_tags = orderEventTagsByPriority($e_tags, $p_tags);
}
$tags_shown = 0;
foreach ($e_tags as $tag) {
$value = getTagString($tag, $tag_name_format);
if ($value !== '') {
if ($subfilter_tags !== null
&& !(array_key_exists($tag['tag'], $subfilter_tags)
&& array_key_exists($tag['value'], $subfilter_tags[$tag['tag']]))) {
$tags[$element[$key]][] = (new CSimpleButton($value))
->setAttribute('data-key', $tag['tag'])
->setAttribute('data-value', $tag['value'])
->onClick(
'view.setSubfilter([`subfilter_tags[${encodeURIComponent(this.dataset.key)}][]`,'.
'this.dataset.value'.
']);'
)
->addClass(ZBX_STYLE_BTN_TAG)
->setHint(getTagString($tag), '', false);
}
else {
$tags[$element[$key]][] = (new CSpan($value))
->addClass(ZBX_STYLE_TAG)
->setHint(getTagString($tag));
}
$tags_shown++;
if ($tags_shown >= $list_tag_count) {
break;
}
}
}
if (count($element['tags']) > $tags_shown) {
// Display all tags in hint box.
$hint_content = [];
foreach ($element['tags'] as $tag) {
$value = getTagString($tag);
if ($subfilter_tags !== null
&& !(array_key_exists($tag['tag'], $subfilter_tags)
&& array_key_exists($tag['value'], $subfilter_tags[$tag['tag']]))) {
$hint_content[$element[$key]][] = (new CSimpleButton($value))
->setAttribute('data-key', $tag['tag'])
->setAttribute('data-value', $tag['value'])
->onClick(
'view.setSubfilter([`subfilter_tags[${encodeURIComponent(this.dataset.key)}][]`,'.
'this.dataset.value'.
']);'
)
->addClass(ZBX_STYLE_BTN_TAG)
->setHint(getTagString($tag), '', false);
}
else {
$hint_content[$element[$key]][] = (new CSpan($value))
->addClass(ZBX_STYLE_TAG)
->setHint($value);
}
}
$tags[$element[$key]][] = (new CButtonIcon(ZBX_ICON_MORE))
->setHint($hint_content, ZBX_STYLE_HINTBOX_WRAP);
}
}
else {
// Show all and uncut for CSV.
foreach ($element['tags'] as $tag) {
$tags[$element[$key]][] = getTagString($tag);
}
}
}
return $tags;
}
/**
* Returns tag name in selected format.
*
* @param array $tag
* @param string $tag['tag']
* @param string $tag['value']
* @param int $tag_name_format TAG_NAME_*
*
* @return string
*/
function getTagString(array $tag, $tag_name_format = TAG_NAME_FULL) {
switch ($tag_name_format) {
case TAG_NAME_NONE:
return $tag['value'];
case TAG_NAME_SHORTENED:
return mb_substr($tag['tag'], 0, 3).(($tag['value'] === '') ? '' : ': '.$tag['value']);
default:
return $tag['tag'].(($tag['value'] === '') ? '' : ': '.$tag['value']);
}
}
/**
* Validate if the given events can change the rank by moving to a new cause. Linking a cause event with its symptoms
* (or only cause or only symptoms) to another different cause or symptom is allowed and will switch to the new cause as
* a result. Linking a cause to one of its own symptoms is also allowed and will simply switch the cause and symptom as
* a result. Linking a symptom to same cause is not allowed and that event ID is skipped. Linking a symptom to symptom
* of same cause is also not allowed and is skipped.
*
* @param array $eventids Array of event IDs that should be converted to symptom events.
* @param string $cause_eventid Event ID that will be the new cause ID for given $eventids.
*
* @return array Returns event IDs that are allowed to change rank.
*/
function validateEventRankChangeToSymptom(array $eventids, string $cause_eventid): array {
$eventids = array_fill_keys($eventids, true);
$all_eventids = $eventids;
$all_eventids[$cause_eventid] = true;
// Get all the events that were given in the request to check permissions.
$events = API::Event()->get([
'output' => ['eventid', 'cause_eventid'],
'eventids' => array_keys($all_eventids),
'preservekeys' => true
]);
// Early return. In case one of the events are missing, no rank change can occur.
if (count($events) != count($all_eventids)) {
return [];
}
// Early return. No matter if cause or symptom, source and destination cannot be the same.
if (count($eventids) == 1 && bccomp(key($eventids), $cause_eventid) == 0) {
return [];
}
$dst_event = $events[$cause_eventid];
foreach (array_keys($eventids) as $eventid) {
$event = $events[$eventid];
// Given cause is being moved.
if ($event['cause_eventid'] == 0) {
// Destination is cause. Cause is moved to same cause. Skip this event ID.
if ($dst_event['cause_eventid'] == 0 && bccomp($eventid, $dst_event['eventid']) == 0) {
unset($eventids[$eventid]);
}
}
// Given symptom is moved.
else {
// Destination is cause.
if ($dst_event['cause_eventid'] == 0) {
// Symptom current cause is the same as new cause. Skip this event ID.
if (bccomp($event['cause_eventid'], $dst_event['eventid']) == 0) {
unset($eventids[$eventid]);
}
}
// Destination is symptom.
else {
// Symptom destination is self. Skip this Event ID.
if (bccomp($eventid, $dst_event['eventid']) == 0) {
unset($eventids[$eventid]);
}
// If given symptom cause is not also in the list, skip this Event ID.
if (!array_key_exists($event['cause_eventid'], $eventids)) {
unset($eventids[$eventid]);
}
}
}
}
return array_keys($eventids);
}