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.

3813 lines
136 KiB

<?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.
**/
/**
* Class containing methods for operations with actions.
*/
class CAction extends CApiService {
public const ACCESS_RULES = [
'get' => ['min_user_type' => USER_TYPE_ZABBIX_USER],
'create' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN],
'update' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN],
'delete' => ['min_user_type' => USER_TYPE_ZABBIX_ADMIN]
];
protected $tableName = 'actions';
protected $tableAlias = 'a';
protected $sortColumns = ['actionid', 'name', 'status'];
/**
* Valid condition types for each event source.
*
* @var array
*/
private const VALID_CONDITION_TYPES = [
EVENT_SOURCE_TRIGGERS => [
CONDITION_TYPE_HOST_GROUP, CONDITION_TYPE_HOST, CONDITION_TYPE_TRIGGER, CONDITION_TYPE_TRIGGER_NAME,
CONDITION_TYPE_TRIGGER_SEVERITY, CONDITION_TYPE_TIME_PERIOD, CONDITION_TYPE_TEMPLATE,
CONDITION_TYPE_SUPPRESSED, CONDITION_TYPE_EVENT_TAG, CONDITION_TYPE_EVENT_TAG_VALUE
],
EVENT_SOURCE_DISCOVERY => [
CONDITION_TYPE_DHOST_IP, CONDITION_TYPE_DSERVICE_TYPE, CONDITION_TYPE_DSERVICE_PORT, CONDITION_TYPE_DSTATUS,
CONDITION_TYPE_DUPTIME, CONDITION_TYPE_DVALUE, CONDITION_TYPE_DRULE, CONDITION_TYPE_DCHECK,
CONDITION_TYPE_PROXY, CONDITION_TYPE_DOBJECT
],
EVENT_SOURCE_AUTOREGISTRATION => [
CONDITION_TYPE_PROXY, CONDITION_TYPE_HOST_NAME, CONDITION_TYPE_HOST_METADATA
],
EVENT_SOURCE_INTERNAL => [
CONDITION_TYPE_HOST_GROUP, CONDITION_TYPE_HOST, CONDITION_TYPE_TEMPLATE, CONDITION_TYPE_EVENT_TYPE,
CONDITION_TYPE_EVENT_TAG, CONDITION_TYPE_EVENT_TAG_VALUE
],
EVENT_SOURCE_SERVICE => [
CONDITION_TYPE_SERVICE, CONDITION_TYPE_SERVICE_NAME, CONDITION_TYPE_EVENT_TAG,
CONDITION_TYPE_EVENT_TAG_VALUE
]
];
/**
* Operation group names.
*
* @var array
*/
private const OPERATION_GROUPS = [
ACTION_OPERATION => 'operations',
ACTION_RECOVERY_OPERATION => 'recovery_operations',
ACTION_UPDATE_OPERATION => 'update_operations'
];
/**
* Get actions data
*
* @param array $options
* @param array $options['itemids']
* @param array $options['hostids']
* @param array $options['groupids']
* @param array $options['actionids']
* @param array $options['status']
* @param array $options['extendoutput']
* @param array $options['count']
* @param array $options['pattern']
* @param array $options['limit']
* @param array $options['order']
*
* @return array|int item data as array or false if error
*/
public function get($options = []) {
$result = [];
$sqlParts = [
'select' => ['actions' => 'a.actionid'],
'from' => ['actions' => 'actions a'],
'where' => [],
'order' => [],
'limit' => null
];
$defOptions = [
'groupids' => null,
'hostids' => null,
'actionids' => null,
'triggerids' => null,
'mediatypeids' => null,
'usrgrpids' => null,
'userids' => null,
'scriptids' => null,
// filter
'filter' => null,
'search' => null,
'searchByAny' => null,
'startSearch' => false,
'excludeSearch' => false,
'searchWildcardsEnabled' => null,
// output
'output' => API_OUTPUT_EXTEND,
'selectFilter' => null,
'selectOperations' => null,
'selectRecoveryOperations' => null,
'selectUpdateOperations' => null,
'countOutput' => false,
'preservekeys' => false,
'sortfield' => '',
'sortorder' => '',
'limit' => null
];
$options = zbx_array_merge($defOptions, $options);
// PERMISSION CHECK
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
// conditions are checked here by sql, operations after, by api queries
$userGroups = getUserGroupsByUserId(self::$userData['userid']);
// condition hostgroup
$sqlParts['where'][] = 'NOT EXISTS ('.
'SELECT NULL'.
' FROM conditions cc'.
' LEFT JOIN rights r'.
' ON r.id='.zbx_dbcast_2bigint('cc.value').
' AND '.dbConditionInt('r.groupid', $userGroups).
' WHERE a.actionid=cc.actionid'.
' AND cc.conditiontype='.CONDITION_TYPE_HOST_GROUP.
' GROUP BY cc.value'.
' HAVING MIN(r.permission) IS NULL'.
' OR MIN(r.permission)='.PERM_DENY.
' OR MAX(r.permission)<'.PERM_READ.
')';
// condition host or template
$sqlParts['where'][] = 'NOT EXISTS ('.
'SELECT NULL'.
' FROM conditions cc,hosts_groups hgg'.
' LEFT JOIN rights r'.
' ON r.id=hgg.groupid'.
' AND '.dbConditionInt('r.groupid', $userGroups).
' WHERE a.actionid=cc.actionid'.
' AND '.zbx_dbcast_2bigint('cc.value').'=hgg.hostid'.
' AND cc.conditiontype IN ('.CONDITION_TYPE_HOST.','.CONDITION_TYPE_TEMPLATE.')'.
' GROUP BY cc.value'.
' HAVING MIN(r.permission) IS NULL'.
' OR MIN(r.permission)='.PERM_DENY.
' OR MAX(r.permission)<'.PERM_READ.
')';
// condition trigger
$sqlParts['where'][] = 'NOT EXISTS ('.
'SELECT NULL'.
' FROM conditions cc,functions f,items i,hosts_groups hgg'.
' LEFT JOIN rights r'.
' ON r.id=hgg.groupid'.
' AND '.dbConditionInt('r.groupid', $userGroups).
' WHERE a.actionid=cc.actionid'.
' AND '.zbx_dbcast_2bigint('cc.value').'=f.triggerid'.
' AND f.itemid=i.itemid'.
' AND i.hostid=hgg.hostid'.
' AND cc.conditiontype='.CONDITION_TYPE_TRIGGER.
' GROUP BY cc.value'.
' HAVING MIN(r.permission) IS NULL'.
' OR MIN(r.permission)='.PERM_DENY.
' OR MAX(r.permission)<'.PERM_READ.
')';
}
// actionids
if (!is_null($options['actionids'])) {
zbx_value2array($options['actionids']);
$sqlParts['where'][] = dbConditionInt('a.actionid', $options['actionids']);
}
// groupids
if (!is_null($options['groupids'])) {
zbx_value2array($options['groupids']);
$sqlParts['from']['conditions_groups'] = 'conditions cg';
$sqlParts['where'][] = dbConditionString('cg.value', $options['groupids']);
$sqlParts['where']['ctg'] = 'cg.conditiontype='.CONDITION_TYPE_HOST_GROUP;
$sqlParts['where']['acg'] = 'a.actionid=cg.actionid';
}
// hostids
if (!is_null($options['hostids'])) {
zbx_value2array($options['hostids']);
$sqlParts['from']['conditions_hosts'] = 'conditions ch';
$sqlParts['where'][] = dbConditionString('ch.value', $options['hostids']);
$sqlParts['where']['cth'] = 'ch.conditiontype='.CONDITION_TYPE_HOST;
$sqlParts['where']['ach'] = 'a.actionid=ch.actionid';
}
// triggerids
if (!is_null($options['triggerids'])) {
zbx_value2array($options['triggerids']);
$sqlParts['from']['conditions_triggers'] = 'conditions ct';
$sqlParts['where'][] = dbConditionString('ct.value', $options['triggerids']);
$sqlParts['where']['ctt'] = 'ct.conditiontype='.CONDITION_TYPE_TRIGGER;
$sqlParts['where']['act'] = 'a.actionid=ct.actionid';
}
// mediatypeids
if (!is_null($options['mediatypeids'])) {
zbx_value2array($options['mediatypeids']);
$sqlParts['from']['opmessage'] = 'opmessage om';
$sqlParts['from']['operations_media'] = 'operations omed';
$sqlParts['where'][] = dbConditionId('om.mediatypeid', $options['mediatypeids']);
$sqlParts['where']['aomed'] = 'a.actionid=omed.actionid';
$sqlParts['where']['oom'] = 'omed.operationid=om.operationid';
}
// operation messages
// usrgrpids
if (!is_null($options['usrgrpids'])) {
zbx_value2array($options['usrgrpids']);
$sqlParts['from']['opmessage_grp'] = 'opmessage_grp omg';
$sqlParts['from']['operations_usergroups'] = 'operations oug';
$sqlParts['where'][] = dbConditionInt('omg.usrgrpid', $options['usrgrpids']);
$sqlParts['where']['aoug'] = 'a.actionid=oug.actionid';
$sqlParts['where']['oomg'] = 'oug.operationid=omg.operationid';
}
// userids
if (!is_null($options['userids'])) {
zbx_value2array($options['userids']);
$sqlParts['from']['opmessage_usr'] = 'opmessage_usr omu';
$sqlParts['from']['operations_users'] = 'operations ou';
$sqlParts['where'][] = dbConditionInt('omu.userid', $options['userids']);
$sqlParts['where']['aou'] = 'a.actionid=ou.actionid';
$sqlParts['where']['oomu'] = 'ou.operationid=omu.operationid';
}
// operation commands
// scriptids
if (!is_null($options['scriptids'])) {
zbx_value2array($options['scriptids']);
$sqlParts['from']['opcommand'] = 'opcommand oc';
$sqlParts['from']['operations_scripts'] = 'operations os';
$sqlParts['where'][] = dbConditionInt('oc.scriptid', $options['scriptids']);
$sqlParts['where']['aos'] = 'a.actionid=os.actionid';
$sqlParts['where']['ooc'] = 'os.operationid=oc.operationid';
}
// filter
if (is_array($options['filter'])) {
if (array_key_exists('esc_period', $options['filter']) && $options['filter']['esc_period'] !== null) {
$options['filter']['esc_period'] = getTimeUnitFilters($options['filter']['esc_period']);
}
$this->dbFilter('actions a', $options, $sqlParts);
}
// search
if (is_array($options['search'])) {
zbx_db_search('actions a', $options, $sqlParts);
}
// limit
if (zbx_ctype_digit($options['limit']) && $options['limit']) {
$sqlParts['limit'] = $options['limit'];
}
$actionIds = [];
$sqlParts = $this->applyQueryOutputOptions($this->tableName(), $this->tableAlias(), $options, $sqlParts);
$sqlParts = $this->applyQuerySortOptions($this->tableName(), $this->tableAlias(), $options, $sqlParts);
$dbRes = DBselect(self::createSelectQueryFromParts($sqlParts), $sqlParts['limit']);
while ($action = DBfetch($dbRes)) {
if ($options['countOutput']) {
$result = $action['rowscount'];
}
else {
$actionIds[$action['actionid']] = $action['actionid'];
$result[$action['actionid']] = $action;
}
}
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
// check hosts, templates
$hosts = [];
$hostIds = [];
$sql = 'SELECT o.actionid,och.hostid'.
' FROM operations o,opcommand_hst och'.
' WHERE o.operationid=och.operationid'.
' AND och.hostid<>0'.
' AND '.dbConditionInt('o.actionid', $actionIds);
$dbHosts = DBselect($sql);
while ($host = DBfetch($dbHosts)) {
if (!isset($hosts[$host['hostid']])) {
$hosts[$host['hostid']] = [];
}
$hosts[$host['hostid']][$host['actionid']] = $host['actionid'];
$hostIds[$host['hostid']] = $host['hostid'];
}
$dbTemplates = DBselect(
'SELECT o.actionid,ot.templateid'.
' FROM operations o,optemplate ot'.
' WHERE o.operationid=ot.operationid'.
' AND '.dbConditionInt('o.actionid', $actionIds)
);
while ($template = DBfetch($dbTemplates)) {
if (!isset($hosts[$template['templateid']])) {
$hosts[$template['templateid']] = [];
}
$hosts[$template['templateid']][$template['actionid']] = $template['actionid'];
$hostIds[$template['templateid']] = $template['templateid'];
}
$allowedHosts = API::Host()->get([
'hostids' => $hostIds,
'output' => ['hostid'],
'templated_hosts' => true,
'preservekeys' => true
]);
foreach ($hostIds as $hostId) {
if (isset($allowedHosts[$hostId])) {
continue;
}
foreach ($hosts[$hostId] as $actionId) {
unset($result[$actionId], $actionIds[$actionId]);
}
}
unset($allowedHosts);
// check hostgroups
$groups = [];
$groupIds = [];
$dbGroups = DBselect(
'SELECT o.actionid,ocg.groupid'.
' FROM operations o,opcommand_grp ocg'.
' WHERE o.operationid=ocg.operationid'.
' AND '.dbConditionInt('o.actionid', $actionIds)
);
while ($group = DBfetch($dbGroups)) {
if (!isset($groups[$group['groupid']])) {
$groups[$group['groupid']] = [];
}
$groups[$group['groupid']][$group['actionid']] = $group['actionid'];
$groupIds[$group['groupid']] = $group['groupid'];
}
$dbGroups = DBselect(
'SELECT o.actionid,og.groupid'.
' FROM operations o,opgroup og'.
' WHERE o.operationid=og.operationid'.
' AND '.dbConditionInt('o.actionid', $actionIds)
);
while ($group = DBfetch($dbGroups)) {
if (!isset($groups[$group['groupid']])) {
$groups[$group['groupid']] = [];
}
$groups[$group['groupid']][$group['actionid']] = $group['actionid'];
$groupIds[$group['groupid']] = $group['groupid'];
}
$allowedGroups = API::HostGroup()->get([
'groupids' => $groupIds,
'output' => ['groupid'],
'preservekeys' => true
]);
foreach ($groupIds as $groupId) {
if (isset($allowedGroups[$groupId])) {
continue;
}
foreach ($groups[$groupId] as $actionId) {
unset($result[$actionId], $actionIds[$actionId]);
}
}
unset($allowedGroups);
// check scripts
$scripts = [];
$scriptIds = [];
$dbScripts = DBselect(
'SELECT o.actionid,oc.scriptid'.
' FROM operations o,opcommand oc'.
' WHERE o.operationid=oc.operationid'.
' AND '.dbConditionInt('o.actionid', $actionIds)
);
while ($script = DBfetch($dbScripts)) {
if (!isset($scripts[$script['scriptid']])) {
$scripts[$script['scriptid']] = [];
}
$scripts[$script['scriptid']][$script['actionid']] = $script['actionid'];
$scriptIds[$script['scriptid']] = $script['scriptid'];
}
$allowedScripts = API::Script()->get([
'output' => ['scriptid'],
'scriptids' => $scriptIds,
'filter' => ['scope' => ZBX_SCRIPT_SCOPE_ACTION],
'preservekeys' => true
]);
foreach ($scriptIds as $scriptId) {
if (isset($allowedScripts[$scriptId])) {
continue;
}
foreach ($scripts[$scriptId] as $actionId) {
unset($result[$actionId], $actionIds[$actionId]);
}
}
unset($allowedScripts);
// check users
$users = [];
$userIds = [];
$dbUsers = DBselect(
'SELECT o.actionid,omu.userid'.
' FROM operations o,opmessage_usr omu'.
' WHERE o.operationid=omu.operationid'.
' AND '.dbConditionInt('o.actionid', $actionIds)
);
while ($user = DBfetch($dbUsers)) {
if (!isset($users[$user['userid']])) {
$users[$user['userid']] = [];
}
$users[$user['userid']][$user['actionid']] = $user['actionid'];
$userIds[$user['userid']] = $user['userid'];
}
$allowedUsers = API::User()->get([
'userids' => $userIds,
'output' => ['userid'],
'preservekeys' => true
]);
foreach ($userIds as $userId) {
if (isset($allowedUsers[$userId])) {
continue;
}
foreach ($users[$userId] as $actionId) {
unset($result[$actionId], $actionIds[$actionId]);
}
}
// check usergroups
$userGroups = [];
$userGroupIds = [];
$dbUserGroups = DBselect(
'SELECT o.actionid,omg.usrgrpid'.
' FROM operations o,opmessage_grp omg'.
' WHERE o.operationid=omg.operationid'.
' AND '.dbConditionInt('o.actionid', $actionIds)
);
while ($userGroup = DBfetch($dbUserGroups)) {
if (!isset($userGroups[$userGroup['usrgrpid']])) {
$userGroups[$userGroup['usrgrpid']] = [];
}
$userGroups[$userGroup['usrgrpid']][$userGroup['actionid']] = $userGroup['actionid'];
$userGroupIds[$userGroup['usrgrpid']] = $userGroup['usrgrpid'];
}
$allowedUserGroups = API::UserGroup()->get([
'usrgrpids' => $userGroupIds,
'output' => ['usrgrpid'],
'preservekeys' => true
]);
foreach ($userGroupIds as $userGroupId) {
if (isset($allowedUserGroups[$userGroupId])) {
continue;
}
foreach ($userGroups[$userGroupId] as $actionId) {
unset($result[$actionId], $actionIds[$actionId]);
}
}
}
if ($options['countOutput']) {
return $result;
}
if ($result) {
$result = $this->addRelatedObjects($options, $result);
foreach ($result as &$action) {
// unset the fields that are returned in the filter
unset($action['formula'], $action['evaltype']);
if ($options['selectFilter'] !== null) {
$filter = $this->unsetExtraFields(
[$action['filter']],
['conditions', 'formula', 'evaltype'],
$options['selectFilter']
);
$filter = reset($filter);
if (isset($filter['conditions'])) {
foreach ($filter['conditions'] as &$condition) {
unset($condition['actionid'], $condition['conditionid']);
}
unset($condition);
}
$action['filter'] = $filter;
}
}
unset($action);
}
// removing keys (hash -> array)
if (!$options['preservekeys']) {
$result = zbx_cleanHashes($result);
}
return $result;
}
/**
* @param array $actions
*
* @throws APIException
*
* @return array
*/
public function create(array $actions): array {
$this->validateCreate($actions);
$ins_actions = [];
foreach ($actions as $action) {
if (array_key_exists('filter', $action)) {
$action['evaltype'] = $action['filter']['evaltype'];
}
$ins_actions[] = $action;
}
$actionids = DB::insert('actions', $ins_actions);
foreach ($actions as $index => &$action) {
$action['actionid'] = $actionids[$index];
}
unset($action);
self::updateFilter($actions);
self::updateOperations($actions);
self::addAuditLog(CAudit::ACTION_ADD, CAudit::RESOURCE_ACTION, $actions);
return ['actionids' => $actionids];
}
/**
* @param array $actions
*
* @throws APIException
*
* @return array
*/
public function update(array $actions): array {
$this->validateUpdate($actions, $db_actions);
$upd_actions = [];
foreach ($actions as $action) {
$db_action = $db_actions[$action['actionid']];
if (array_key_exists('filter', $action)) {
$action['evaltype'] = $action['filter']['evaltype'];
$db_action['evaltype'] = $db_action['filter']['evaltype'];
}
$upd_action = DB::getUpdatedValues('actions', $action, $db_action);
if ($upd_action) {
$upd_actions[] = [
'values' => $upd_action,
'where' => ['actionid' => $action['actionid']]
];
}
}
if ($upd_actions) {
DB::update('actions', $upd_actions);
}
self::updateFilter($actions, $db_actions);
self::updateOperations($actions, $db_actions);
self::addAuditLog(CAudit::ACTION_UPDATE, CAudit::RESOURCE_ACTION, $actions, $db_actions);
return ['actionids' => array_column($actions, 'actionid')];
}
/**
* @param array $actions
* @param array|null $db_actions
*/
private static function updateFilter(array &$actions, array $db_actions = null): void {
$is_update = ($db_actions !== null);
$ins_conditions = [];
$upd_conditions = [];
$del_conditionids = [];
foreach ($actions as &$action) {
if (!array_key_exists('filter', $action) || !array_key_exists('conditions', $action['filter'])) {
continue;
}
$db_conditions = $is_update ? $db_actions[$action['actionid']]['filter']['conditions'] : [];
foreach ($action['filter']['conditions'] as &$condition) {
$db_condition = current(
array_filter($db_conditions, static function(array $db_condition) use ($condition): bool {
if ($condition['conditiontype'] == CONDITION_TYPE_SUPPRESSED) {
return $condition['conditiontype'] == $db_condition['conditiontype'];
}
if ($condition['conditiontype'] == CONDITION_TYPE_EVENT_TAG_VALUE) {
return $condition['conditiontype'] == $db_condition['conditiontype']
&& $condition['value2'] === $db_condition['value2'];
}
return $condition['conditiontype'] == $db_condition['conditiontype']
&& $condition['value'] == $db_condition['value'];
})
);
if ($db_condition) {
$condition['conditionid'] = $db_condition['conditionid'];
unset($db_conditions[$db_condition['conditionid']]);
$upd_condition = DB::getUpdatedValues('conditions', $condition, $db_condition);
if ($upd_condition) {
$upd_conditions[] = [
'values' => $upd_condition,
'where' => ['conditionid' => $db_condition['conditionid']]
];
}
}
else {
$ins_conditions[] = ['actionid' => $action['actionid']] + $condition;
}
}
unset($condition);
$del_conditionids = array_merge($del_conditionids, array_keys($db_conditions));
}
unset($action);
if ($del_conditionids) {
DB::delete('conditions', ['conditionid' => $del_conditionids]);
}
if ($upd_conditions) {
DB::update('conditions', $upd_conditions);
}
if ($ins_conditions) {
$conditionids = DB::insert('conditions', $ins_conditions);
}
foreach ($actions as &$action) {
if (!array_key_exists('filter', $action) || !array_key_exists('conditions', $action['filter'])) {
continue;
}
foreach ($action['filter']['conditions'] as &$condition) {
if (!array_key_exists('conditionid', $condition)) {
$condition['conditionid'] = array_shift($conditionids);
}
}
unset($condition);
}
unset($action);
// Update formula.
$upd_actions = [];
foreach ($actions as &$action) {
if (!array_key_exists('filter', $action)) {
continue;
}
$action['filter']['formula'] = ($action['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION)
? CConditionHelper::replaceLetterIds($action['filter']['formula'],
array_column($action['filter']['conditions'], 'conditionid', 'formulaid')
)
: '';
$db_formula = $is_update ? $db_actions[$action['actionid']]['filter']['formula'] : '';
if ($action['filter']['formula'] !== $db_formula) {
$upd_actions[] = [
'values' => ['formula' => $action['filter']['formula']],
'where' => ['actionid' => $action['actionid']]
];
}
}
unset($action);
if ($upd_actions) {
DB::update('actions', $upd_actions);
}
}
/**
* @param array $actions
* @param array|null $db_actions
*/
private static function updateOperations(array &$actions, array $db_actions = null): void {
$is_update = ($db_actions !== null);
$ins_operations = [];
$upd_operations = [];
$del_operationids = [];
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
$db_operations = $is_update ? $db_actions[$action['actionid']][$operation_group] : [];
foreach ($action[$operation_group] as &$operation) {
$db_operation = current(
array_filter($db_operations, static function (array $db_operation) use ($operation): bool {
return $operation['operationtype'] == $db_operation['operationtype']
&& $operation['recovery'] == $db_operation['recovery'];
})
);
if ($db_operation) {
$operation['operationid'] = $db_operation['operationid'];
unset($db_operations[$operation['operationid']]);
$upd_operation = DB::getUpdatedValues('operations', $operation, $db_operation);
if ($upd_operation) {
$upd_operations[] = [
'values' => $upd_operation,
'where' => ['operationid' => $db_operation['operationid']]
];
}
}
else {
$ins_operations[] = ['actionid' => $action['actionid']] + $operation;
}
}
unset($operation);
$del_operationids = array_merge($del_operationids, array_keys($db_operations));
}
}
unset($action);
if ($del_operationids) {
DB::delete('operations', ['operationid' => $del_operationids]);
}
if ($upd_operations) {
DB::update('operations', $upd_operations);
}
if ($ins_operations) {
$operationids = DB::insert('operations', $ins_operations);
}
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as &$operation) {
if (!array_key_exists('operationid', $operation)) {
$operation['operationid'] = array_shift($operationids);
}
}
unset($operation);
}
}
unset($action);
self::updateOperationConditions($actions, $db_actions);
self::updateOperationMessages($actions, $db_actions);
self::updateOperationCommands($actions, $db_actions);
self::updateOperationGroups($actions, $db_actions);
self::updateOperationTemplates($actions, $db_actions);
self::updateOperationInventories($actions, $db_actions);
self::updateOperationTags($actions, $db_actions);
}
/**
* @param array $actions
* @param array|null $db_actions
*/
private static function updateOperationConditions(array &$actions, array $db_actions = null): void {
$is_update = ($db_actions !== null);
$ins_opconditions = [];
$upd_opconditions = [];
$del_opconditionids = [];
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
$db_operations = $is_update ? $db_actions[$action['actionid']][$operation_group] : [];
foreach ($action[$operation_group] as &$operation) {
if (!array_key_exists('opconditions', $operation)) {
continue;
}
$db_operation = array_key_exists($operation['operationid'], $db_operations)
? $db_operations[$operation['operationid']]
: [];
$db_opconditions = array_key_exists('opconditions', $db_operation)
? array_column($db_operation['opconditions'], null, 'value')
: [];
foreach ($operation['opconditions'] as &$opcondition) {
if (array_key_exists($opcondition['value'], $db_opconditions)) {
$db_opcondition = $db_opconditions[$opcondition['value']];
$opcondition['opconditionid'] = $db_opcondition['opconditionid'];
unset($db_opconditions[$opcondition['value']]);
$upd_opcondition = DB::getUpdatedValues('opconditions', $opcondition, $db_opcondition);
if ($upd_opcondition) {
$upd_opconditions[] = [
'values' => $upd_opcondition,
'where' => ['operationid' => $operation['operationid']]
];
}
}
else {
$ins_opconditions[] = ['operationid' => $operation['operationid']] + $opcondition;
}
}
unset($opcondition);
$del_opconditionids = array_merge($del_opconditionids,
array_column($db_opconditions, 'opconditionid')
);
}
unset($operation);
}
}
unset($action);
if ($del_opconditionids) {
DB::delete('opconditions', ['opconditionid' => $del_opconditionids]);
}
if ($upd_opconditions) {
DB::update('opconditions', $upd_opconditions);
}
if ($ins_opconditions) {
$opconditionids = DB::insert('opconditions', $ins_opconditions);
}
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as &$operation) {
if (!array_key_exists('opconditions', $operation)) {
continue;
}
foreach ($operation['opconditions'] as &$opcondition) {
if (!array_key_exists('opconditionid', $opcondition)) {
$opcondition['opconditionid'] = array_shift($opconditionids);
}
}
unset($opcondition);
}
unset($operation);
}
}
unset($action);
}
/**
* @param array $actions
* @param array|null $db_actions
*/
private static function updateOperationMessages(array &$actions, array $db_actions = null): void {
$is_update = ($db_actions !== null);
$ins_opmessages = [];
$upd_opmessages = [];
$ins_opmessage_grps = [];
$del_opmessage_grpids = [];
$ins_opmessage_usrs = [];
$del_opmessage_usrids = [];
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
$db_operations = $is_update ? $db_actions[$action['actionid']][$operation_group] : [];
foreach ($action[$operation_group] as &$operation) {
$db_operation = array_key_exists($operation['operationid'], $db_operations)
? $db_operations[$operation['operationid']]
: [];
switch ($operation['operationtype']) {
case OPERATION_TYPE_MESSAGE:
if (array_key_exists('opmessage_grp', $operation)) {
$db_opmessage_grps = array_key_exists('opmessage_grp', $db_operation)
? array_column($db_operation['opmessage_grp'], null, 'usrgrpid')
: [];
foreach ($operation['opmessage_grp'] as &$opmessage_grp) {
if (array_key_exists($opmessage_grp['usrgrpid'], $db_opmessage_grps)) {
$db_opmessage_grp = $db_opmessage_grps[$opmessage_grp['usrgrpid']];
$opmessage_grp['opmessage_grpid'] = $db_opmessage_grp['opmessage_grpid'];
unset($db_opmessage_grps[$opmessage_grp['usrgrpid']]);
}
else {
$ins_opmessage_grps[] =
['operationid' => $operation['operationid']] + $opmessage_grp;
}
}
unset($opmessage_grp);
$del_opmessage_grpids = array_merge($del_opmessage_grpids,
array_column($db_opmessage_grps, 'opmessage_grpid')
);
}
if (array_key_exists('opmessage_usr', $operation)) {
$db_opmessage_usrs = array_key_exists('opmessage_usr', $db_operation)
? array_column($db_operation['opmessage_usr'], null, 'userid')
: [];
foreach ($operation['opmessage_usr'] as &$opmessage_usr) {
if (array_key_exists($opmessage_usr['userid'], $db_opmessage_usrs)) {
$db_opmessage_usr = $db_opmessage_usrs[$opmessage_usr['userid']];
$opmessage_usr['opmessage_usrid'] = $db_opmessage_usr['opmessage_usrid'];
unset($db_opmessage_usrs[$opmessage_usr['userid']]);
}
else {
$ins_opmessage_usrs[] =
['operationid' => $operation['operationid']] + $opmessage_usr;
}
}
unset($opmessage_usr);
$del_opmessage_usrids = array_merge($del_opmessage_usrids,
array_column($db_opmessage_usrs, 'opmessage_usrid')
);
}
// break; is not missing here
case OPERATION_TYPE_RECOVERY_MESSAGE:
case OPERATION_TYPE_UPDATE_MESSAGE:
if (array_key_exists('opmessage', $db_operation)) {
$upd_opmessage = DB::getUpdatedValues('opmessage', $operation['opmessage'],
$db_operation['opmessage']
);
if ($upd_opmessage) {
$upd_opmessages[] = [
'values' => $upd_opmessage,
'where' => ['operationid' => $operation['operationid']]
];
}
}
else {
$ins_opmessages[] =
['operationid' => $operation['operationid']] + $operation['opmessage'];
}
break;
}
}
unset($operation);
}
}
unset($action);
if ($upd_opmessages) {
DB::update('opmessage', $upd_opmessages);
}
if ($ins_opmessages) {
DB::insert('opmessage', $ins_opmessages, false);
}
if ($del_opmessage_grpids) {
DB::delete('opmessage_grp', ['opmessage_grpid' => $del_opmessage_grpids]);
}
if ($ins_opmessage_grps) {
$opmessage_grpids = DB::insert('opmessage_grp', $ins_opmessage_grps);
}
if ($del_opmessage_usrids) {
DB::delete('opmessage_usr', ['opmessage_usrid' => $del_opmessage_usrids]);
}
if ($ins_opmessage_usrs) {
$opmessage_usrids = DB::insert('opmessage_usr', $ins_opmessage_usrs);
}
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as &$operation) {
if (array_key_exists('opmessage_grp', $operation)) {
foreach ($operation['opmessage_grp'] as &$opmessage_grp) {
if (!array_key_exists('opmessage_grpid', $opmessage_grp)) {
$opmessage_grp['opmessage_grpid'] = array_shift($opmessage_grpids);
}
}
unset($opmessage_grp);
}
if (array_key_exists('opmessage_usr', $operation)) {
foreach ($operation['opmessage_usr'] as &$opmessage_usr) {
if (!array_key_exists('opmessage_usrid', $opmessage_usr)) {
$opmessage_usr['opmessage_usrid'] = array_shift($opmessage_usrids);
}
}
unset($opmessage_usr);
}
}
unset($operation);
}
}
unset($action);
}
/**
* @param array $actions
* @param array|null $db_actions
*/
private static function updateOperationCommands(array &$actions, array $db_actions = null): void {
$is_update = ($db_actions !== null);
$ins_opcommands = [];
$upd_opcommands = [];
$ins_opcommand_grps = [];
$del_opcommand_grpids = [];
$ins_opcommand_hsts = [];
$del_opcommand_hstids = [];
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
$db_operations = $is_update ? $db_actions[$action['actionid']][$operation_group] : [];
foreach ($action[$operation_group] as &$operation) {
if ($operation['operationtype'] != OPERATION_TYPE_COMMAND) {
continue;
}
$db_operation = array_key_exists($operation['operationid'], $db_operations)
? $db_operations[$operation['operationid']]
: [];
if (array_key_exists('opcommand', $db_operation)) {
$upd_opcommand = DB::getUpdatedValues('opcommand', $operation['opcommand'],
$db_operation['opcommand']
);
if ($upd_opcommand) {
$upd_opcommands[] = [
'values' => $upd_opcommand,
'where' => ['operationid' => $operation['operationid']]
];
}
}
else {
$ins_opcommands[] =
['operationid' => $operation['operationid']] + $operation['opcommand'];
}
if (array_key_exists('opcommand_grp', $operation)) {
$db_opcommand_grps = array_key_exists('opcommand_grp', $db_operation)
? array_column($db_operation['opcommand_grp'], null, 'groupid')
: [];
foreach ($operation['opcommand_grp'] as &$opcommand_grp) {
if (array_key_exists($opcommand_grp['groupid'], $db_opcommand_grps)) {
$db_opcommand_grp = $db_opcommand_grps[$opcommand_grp['groupid']];
$opcommand_grp['opcommand_grpid'] = $db_opcommand_grp['opcommand_grpid'];
unset($db_opcommand_grps[$opcommand_grp['groupid']]);
}
else {
$ins_opcommand_grps[] =
['operationid' => $operation['operationid']] + $opcommand_grp;
}
}
unset($opcommand_grp);
$del_opcommand_grpids = array_merge($del_opcommand_grpids,
array_column($db_opcommand_grps, 'opcommand_grpid')
);
}
if (array_key_exists('opcommand_hst', $operation)) {
$db_opcommand_hsts = array_key_exists('opcommand_hst', $db_operation)
? array_column($db_operation['opcommand_hst'], null, 'hostid')
: [];
foreach ($operation['opcommand_hst'] as &$opcommand_hst) {
if (array_key_exists($opcommand_hst['hostid'], $db_opcommand_hsts)) {
$db_opcommand_hst = $db_opcommand_hsts[$opcommand_hst['hostid']];
$opcommand_hst['opcommand_hstid'] = $db_opcommand_hst['opcommand_hstid'];
unset($db_opcommand_hsts[$opcommand_hst['hostid']]);
}
else {
$ins_opcommand_hsts[] =
['operationid' => $operation['operationid']] + $opcommand_hst;
}
}
unset($opcommand_hst);
$del_opcommand_hstids = array_merge($del_opcommand_hstids,
array_column($db_opcommand_hsts, 'opcommand_hstid')
);
}
}
unset($operation);
}
}
unset($action);
if ($del_opcommand_grpids) {
DB::delete('opcommand_grp', ['opcommand_grpid' => $del_opcommand_grpids]);
}
if ($del_opcommand_hstids) {
DB::delete('opcommand_hst', ['opcommand_hstid' => $del_opcommand_hstids]);
}
if ($upd_opcommands) {
DB::update('opcommand', $upd_opcommands);
}
if ($ins_opcommands) {
DB::insert('opcommand', $ins_opcommands, false);
}
if ($ins_opcommand_grps) {
$opcommand_grpids = DB::insert('opcommand_grp', $ins_opcommand_grps);
}
if ($ins_opcommand_hsts) {
$opcommand_hstids = DB::insert('opcommand_hst', $ins_opcommand_hsts);
}
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as &$operation) {
if (array_key_exists('opcommand_grp', $operation)) {
foreach ($operation['opcommand_grp'] as &$opcommand_grp) {
if (!array_key_exists('opcommand_grpid', $opcommand_grp)) {
$opcommand_grp['opcommand_grpid'] = array_shift($opcommand_grpids);
}
}
unset($opcommand_grp);
}
if (array_key_exists('opcommand_hst', $operation)) {
foreach ($operation['opcommand_hst'] as &$opcommand_hst) {
if (!array_key_exists('opcommand_hstid', $opcommand_hst)) {
$opcommand_hst['opcommand_hstid'] = array_shift($opcommand_hstids);
}
}
unset($opcommand_hst);
}
}
unset($operation);
}
}
unset($action);
}
/**
* @param array $actions
* @param array|null $db_actions
*/
private static function updateOperationGroups(array &$actions, array $db_actions = null): void {
$is_update = ($db_actions !== null);
$ins_opgroups = [];
$del_opgroupids = [];
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
$db_operations = $is_update ? $db_actions[$action['actionid']][$operation_group] : [];
foreach ($action[$operation_group] as &$operation) {
// Proceed only if operation type is OPERATION_TYPE_GROUP_ADD or OPERATION_TYPE_GROUP_REMOVE.
if (!array_key_exists('opgroup', $operation)) {
continue;
}
$db_operation = array_key_exists($operation['operationid'], $db_operations)
? $db_operations[$operation['operationid']]
: [];
$db_opgroups = array_key_exists('opgroup', $db_operation)
? array_column($db_operation['opgroup'], null, 'groupid')
: [];
foreach ($operation['opgroup'] as &$opgroup) {
if (array_key_exists($opgroup['groupid'], $db_opgroups)) {
$db_opgroup = $db_opgroups[$opgroup['groupid']];
$opgroup['opgroupid'] = $db_opgroup['opgroupid'];
unset($db_opgroups[$opgroup['groupid']]);
}
else {
$ins_opgroups[] = ['operationid' => $operation['operationid']] + $opgroup;
}
}
unset($opgroup);
$del_opgroupids = array_merge($del_opgroupids, array_column($db_opgroups, 'opgroupid'));
}
unset($operation);
}
}
unset($action);
if ($del_opgroupids) {
DB::delete('opgroup', ['opgroupid' => $del_opgroupids]);
}
if ($ins_opgroups) {
$opgroupids = DB::insert('opgroup', $ins_opgroups);
}
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as &$operation) {
if (!array_key_exists('opgroup', $operation)) {
continue;
}
foreach ($operation['opgroup'] as &$opgroup) {
if (!array_key_exists('opgroupid', $opgroup)) {
$opgroup['opgroupid'] = array_shift($opgroupids);
}
}
unset($opgroup);
}
unset($operation);
}
}
unset($action);
}
/**
* @param array $actions
* @param array|null $db_actions
*/
private static function updateOperationTemplates(array &$actions, array $db_actions = null): void {
$is_update = ($db_actions !== null);
$ins_optemplates = [];
$del_optemplateids = [];
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
$db_operations = $is_update ? $db_actions[$action['actionid']][$operation_group] : [];
foreach ($action[$operation_group] as &$operation) {
// Proceed only if operation type is OPERATION_TYPE_TEMPLATE_ADD or OPERATION_TYPE_TEMPLATE_REMOVE.
if (!array_key_exists('optemplate', $operation)) {
continue;
}
$db_operation = array_key_exists($operation['operationid'], $db_operations)
? $db_operations[$operation['operationid']]
: [];
$db_optemplates = array_key_exists('optemplate', $db_operation)
? array_column($db_operation['optemplate'], null, 'templateid')
: [];
foreach ($operation['optemplate'] as &$optemplate) {
if (array_key_exists($optemplate['templateid'], $db_optemplates)) {
$db_optemplate = $db_optemplates[$optemplate['templateid']];
$optemplate['optemplateid'] = $db_optemplate['optemplateid'];
unset($db_optemplates[$optemplate['templateid']]);
}
else {
$ins_optemplates[] = ['operationid' => $operation['operationid']] + $optemplate;
}
}
unset($optemplate);
$del_optemplateids = array_merge($del_optemplateids, array_column($db_optemplates, 'optemplateid'));
}
unset($operation);
}
}
unset($action);
if ($del_optemplateids) {
DB::delete('optemplate', ['optemplateid' => $del_optemplateids]);
}
if ($ins_optemplates) {
$optemplateids = DB::insert('optemplate', $ins_optemplates);
}
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as &$operation) {
if (!array_key_exists('optemplate', $operation)) {
continue;
}
foreach ($operation['optemplate'] as &$optemplate) {
if (!array_key_exists('optemplateid', $optemplate)) {
$optemplate['optemplateid'] = array_shift($optemplateids);
}
}
unset($optemplate);
}
unset($operation);
}
}
unset($action);
}
/**
* @param array $actions
* @param array|null $db_actions
*/
private static function updateOperationInventories(array $actions, array $db_actions = null): void {
$is_update = ($db_actions !== null);
$ins_opinventories = [];
$upd_opinventories = [];
foreach ($actions as $action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
$db_operations = $is_update ? $db_actions[$action['actionid']][$operation_group] : [];
foreach ($action[$operation_group] as $operation) {
if ($operation['operationtype'] != OPERATION_TYPE_HOST_INVENTORY) {
continue;
}
$db_operation = array_key_exists($operation['operationid'], $db_operations)
? $db_operations[$operation['operationid']]
: [];
if (array_key_exists('opinventory', $db_operation)) {
$upd_opinventory = DB::getUpdatedValues('opinventory', $operation['opinventory'],
$db_operation['opinventory']
);
if ($upd_opinventory) {
$upd_opinventories[] = [
'values' => $upd_opinventory,
'where' => ['operationid' => $operation['operationid']]
];
}
}
else {
$ins_opinventories[] =
['operationid' => $operation['operationid']] + $operation['opinventory'];
}
}
}
}
if ($upd_opinventories) {
DB::update('opinventory', $upd_opinventories);
}
if ($ins_opinventories) {
DB::insert('opinventory', $ins_opinventories, false);
}
}
/**
* Inserts and deletes operations with host tags.
*
* @param array $actions
* @param array|null $db_actions
*/
private static function updateOperationTags(array &$actions, array $db_actions = null): void {
$is_update = ($db_actions !== null);
$ins_optags = [];
$del_optagids = [];
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
$db_operations = $is_update ? $db_actions[$action['actionid']][$operation_group] : [];
foreach ($action[$operation_group] as &$operation) {
if (!array_key_exists('optag', $operation)) {
continue;
}
$db_operation = array_key_exists($operation['operationid'], $db_operations)
? $db_operations[$operation['operationid']]
: [];
$db_optags = array_key_exists('optag', $db_operation)
? $db_operation['optag']
: [];
foreach ($operation['optag'] as &$optag) {
if (!array_key_exists('value', $optag)) {
$optag['value'] = '';
}
$tag_exists = false;
foreach ($db_optags as $idx => $db_optag) {
if ($optag['tag'] === $db_optag['tag'] && $optag['value'] === $db_optag['value']) {
$optag['optagid'] = $db_optag['optagid'];
unset($db_optags[$idx]);
$tag_exists = true;
break;
}
}
if (!$tag_exists) {
$ins_optags[] = ['operationid' => $operation['operationid']] + $optag;
}
}
unset($optag);
$del_optagids = array_merge($del_optagids, array_column($db_optags, 'optagid'));
}
unset($operation);
}
}
unset($action);
if ($del_optagids) {
DB::delete('optag', ['optagid' => $del_optagids]);
}
if ($ins_optags) {
$optagids = DB::insert('optag', $ins_optags);
}
foreach ($actions as &$action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as &$operation) {
if (!array_key_exists('optag', $operation)) {
continue;
}
foreach ($operation['optag'] as &$optag) {
if (!array_key_exists('optagid', $optag)) {
$optag['optagid'] = array_shift($optagids);
}
}
unset($optag);
}
unset($operation);
}
}
unset($action);
}
/**
* @param array $actionids
*
* @throws APIException
*
* @return array
*/
public function delete(array $actionids): array {
$this->validateDelete($actionids, $db_actions);
$operationids = array_keys(DB::select('operations', [
'output' => ['operationid'],
'filter' => ['actionid' => $actionids],
'preservekeys' => true
]));
DB::delete('opcommand', ['operationid' => $operationids]);
DB::delete('opcommand_grp', ['operationid' => $operationids]);
DB::delete('opcommand_hst', ['operationid' => $operationids]);
DB::delete('opmessage', ['operationid' => $operationids]);
DB::delete('opmessage_grp', ['operationid' => $operationids]);
DB::delete('opmessage_usr', ['operationid' => $operationids]);
DB::delete('opgroup', ['operationid' => $operationids]);
DB::delete('optemplate', ['operationid' => $operationids]);
DB::delete('opinventory', ['operationid' => $operationids]);
DB::delete('optag', ['operationid' => $operationids]);
DB::delete('opconditions', ['operationid' => $operationids]);
DB::delete('operations', ['actionid' => $actionids]);
DB::delete('conditions', ['actionid' => $actionids]);
DB::delete('actions', ['actionid' => $actionids]);
self::addAuditLog(CAudit::ACTION_DELETE, CAudit::RESOURCE_ACTION, $db_actions);
return ['actionids' => $actionids];
}
/**
* @param array $actionids
* @param array|null $db_actions
*
* @throws APIException
*/
private function validateDelete(array &$actionids, ?array &$db_actions): void {
$api_input_rules = ['type' => API_IDS, 'flags' => API_NOT_EMPTY, 'uniq' => true];
if (!CApiInputValidator::validate($api_input_rules, $actionids, '/', $error)) {
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
}
$db_actions = $this->get([
'output' => ['actionid', 'name'],
'actionids' => $actionids
]);
if (count($db_actions) != count($actionids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!'));
}
}
protected function addRelatedObjects(array $options, array $result) {
$result = parent::addRelatedObjects($options, $result);
$actionIds = array_keys($result);
// adding formulas
if ($options['selectFilter'] !== null) {
$formulaRequested = $this->outputIsRequested('formula', $options['selectFilter']);
$evalFormulaRequested = $this->outputIsRequested('eval_formula', $options['selectFilter']);
$conditionsRequested = $this->outputIsRequested('conditions', $options['selectFilter']);
$filters = [];
foreach ($result as $action) {
$filters[$action['actionid']] = [
'evaltype' => $action['evaltype'],
'formula' => isset($action['formula']) ? $action['formula'] : ''
];
}
if ($formulaRequested || $evalFormulaRequested || $conditionsRequested) {
$conditions = API::getApiService()->select('conditions', [
'output' => ['actionid', 'conditionid', 'conditiontype', 'operator', 'value', 'value2'],
'filter' => ['actionid' => $actionIds],
'preservekeys' => true
]);
$relationMap = $this->createRelationMap($conditions, 'actionid', 'conditionid');
$filters = $relationMap->mapMany($filters, $conditions, 'conditions');
foreach ($filters as &$filter) {
// in case of a custom expression - use the given formula
if ($filter['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) {
$formula = $filter['formula'];
}
// in other cases - generate the formula automatically
else {
$conditions = $filter['conditions'];
// sort conditions
$sortFields = [
['field' => 'conditiontype', 'order' => ZBX_SORT_DOWN],
['field' => 'operator', 'order' => ZBX_SORT_DOWN],
['field' => 'value2', 'order' => ZBX_SORT_DOWN],
['field' => 'value', 'order' => ZBX_SORT_DOWN]
];
CArrayHelper::sort($conditions, $sortFields);
$conditionsForFormula = [];
foreach ($conditions as $condition) {
$conditionsForFormula[$condition['conditionid']] = $condition['conditiontype'];
}
$formula = CConditionHelper::getFormula($conditionsForFormula, $filter['evaltype']);
}
// generate formulaids from the effective formula
$formulaIds = CConditionHelper::getFormulaIds($formula);
foreach ($filter['conditions'] as &$condition) {
$condition['formulaid'] = $formulaIds[$condition['conditionid']];
}
unset($condition);
// generated a letter based formula only for actions with custom expressions
if ($formulaRequested && $filter['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) {
$filter['formula'] = CConditionHelper::replaceNumericIds($formula, $formulaIds);
}
if ($evalFormulaRequested) {
$filter['eval_formula'] = CConditionHelper::replaceNumericIds($formula, $formulaIds);
}
}
unset($filter);
}
// add filters to the result
foreach ($result as &$action) {
$action['filter'] = $filters[$action['actionid']];
}
unset($action);
}
// Adding operations.
if ($options['selectOperations'] !== null && $options['selectOperations'] != API_OUTPUT_COUNT) {
$operations = API::getApiService()->select('operations', [
'output' => $this->outputExtend($options['selectOperations'],
['operationid', 'actionid', 'operationtype']
),
'filter' => ['actionid' => $actionIds, 'recovery' => ACTION_OPERATION],
'preservekeys' => true
]);
$relationMap = $this->createRelationMap($operations, 'actionid', 'operationid');
$operationIds = $relationMap->getRelatedIds();
if ($this->outputIsRequested('opconditions', $options['selectOperations'])) {
foreach ($operations as &$operation) {
$operation['opconditions'] = [];
}
unset($operation);
$res = DBselect('SELECT op.* FROM opconditions op WHERE '.dbConditionInt('op.operationid', $operationIds));
while ($opcondition = DBfetch($res)) {
$operations[$opcondition['operationid']]['opconditions'][] = $opcondition;
}
}
$opmessage = [];
$opcommand = [];
$opgroup = [];
$optemplate = [];
$opinventory = [];
$optag = [];
foreach ($operations as $operationid => $operation) {
unset($operations[$operationid]['recovery']);
switch ($operation['operationtype']) {
case OPERATION_TYPE_MESSAGE:
$opmessage[] = $operationid;
break;
case OPERATION_TYPE_COMMAND:
$opcommand[] = $operationid;
break;
case OPERATION_TYPE_GROUP_ADD:
case OPERATION_TYPE_GROUP_REMOVE:
$opgroup[] = $operationid;
break;
case OPERATION_TYPE_TEMPLATE_ADD:
case OPERATION_TYPE_TEMPLATE_REMOVE:
$optemplate[] = $operationid;
break;
case OPERATION_TYPE_HOST_ADD:
case OPERATION_TYPE_HOST_REMOVE:
case OPERATION_TYPE_HOST_ENABLE:
case OPERATION_TYPE_HOST_DISABLE:
break;
case OPERATION_TYPE_HOST_INVENTORY:
$opinventory[] = $operationid;
break;
case OPERATION_TYPE_HOST_TAGS_ADD:
case OPERATION_TYPE_HOST_TAGS_REMOVE:
$optag[] = $operationid;
break;
}
}
// get OPERATION_TYPE_MESSAGE data
if ($opmessage) {
if ($this->outputIsRequested('opmessage', $options['selectOperations'])) {
foreach ($opmessage as $operationId) {
$operations[$operationId]['opmessage'] = [];
}
$db_opmessages = DBselect(
'SELECT o.operationid,o.default_msg,o.subject,o.message,o.mediatypeid'.
' FROM opmessage o'.
' WHERE '.dbConditionInt('o.operationid', $opmessage)
);
while ($db_opmessage = DBfetch($db_opmessages)) {
$operationid = $db_opmessage['operationid'];
unset($db_opmessage['operationid']);
$operations[$operationid]['opmessage'] = $db_opmessage;
}
}
if ($this->outputIsRequested('opmessage_grp', $options['selectOperations'])) {
foreach ($opmessage as $operationId) {
$operations[$operationId]['opmessage_grp'] = [];
}
$db_opmessages_grp = DBselect(
'SELECT og.operationid,og.usrgrpid'.
' FROM opmessage_grp og'.
' WHERE '.dbConditionInt('og.operationid', $opmessage)
);
while ($db_opmessage_grp = DBfetch($db_opmessages_grp)) {
$operationid = $db_opmessage_grp['operationid'];
unset($db_opmessage_grp['operationid']);
$operations[$operationid]['opmessage_grp'][] = $db_opmessage_grp;
}
}
if ($this->outputIsRequested('opmessage_usr', $options['selectOperations'])) {
foreach ($opmessage as $operationId) {
$operations[$operationId]['opmessage_usr'] = [];
}
$db_opmessages_usr = DBselect(
'SELECT ou.operationid,ou.userid'.
' FROM opmessage_usr ou'.
' WHERE '.dbConditionInt('ou.operationid', $opmessage)
);
while ($db_opmessage_usr = DBfetch($db_opmessages_usr)) {
$operationid = $db_opmessage_usr['operationid'];
unset($db_opmessage_usr['operationid']);
$operations[$operationid]['opmessage_usr'][] = $db_opmessage_usr;
}
}
}
// get OPERATION_TYPE_COMMAND data
if ($opcommand) {
if ($this->outputIsRequested('opcommand', $options['selectOperations'])) {
foreach ($opcommand as $operationId) {
$operations[$operationId]['opcommand'] = [];
}
$db_opcommands = DBselect(
'SELECT o.operationid,o.scriptid'.
' FROM opcommand o'.
' WHERE '.dbConditionInt('o.operationid', $opcommand)
);
while ($db_opcommand = DBfetch($db_opcommands)) {
$operationid = $db_opcommand['operationid'];
unset($db_opcommand['operationid']);
$operations[$operationid]['opcommand'] = $db_opcommand;
}
}
if ($this->outputIsRequested('opcommand_hst', $options['selectOperations'])) {
foreach ($opcommand as $operationId) {
$operations[$operationId]['opcommand_hst'] = [];
}
$db_opcommands_hst = DBselect(
'SELECT oh.opcommand_hstid,oh.operationid,oh.hostid'.
' FROM opcommand_hst oh'.
' WHERE '.dbConditionInt('oh.operationid', $opcommand)
);
while ($db_opcommand_hst = DBfetch($db_opcommands_hst)) {
$operationid = $db_opcommand_hst['operationid'];
unset($db_opcommand_hst['operationid']);
$operations[$operationid]['opcommand_hst'][] = $db_opcommand_hst;
}
}
if ($this->outputIsRequested('opcommand_grp', $options['selectOperations'])) {
foreach ($opcommand as $operationId) {
$operations[$operationId]['opcommand_grp'] = [];
}
$db_opcommands_grp = DBselect(
'SELECT og.opcommand_grpid,og.operationid,og.groupid'.
' FROM opcommand_grp og'.
' WHERE '.dbConditionInt('og.operationid', $opcommand)
);
while ($db_opcommand_grp = DBfetch($db_opcommands_grp)) {
$operationid = $db_opcommand_grp['operationid'];
unset($db_opcommand_grp['operationid']);
$operations[$operationid]['opcommand_grp'][] = $db_opcommand_grp;
}
}
}
// get OPERATION_TYPE_GROUP_ADD, OPERATION_TYPE_GROUP_REMOVE data
if ($opgroup) {
if ($this->outputIsRequested('opgroup', $options['selectOperations'])) {
foreach ($opgroup as $operationId) {
$operations[$operationId]['opgroup'] = [];
}
$db_opgroups = DBselect(
'SELECT o.operationid,o.groupid'.
' FROM opgroup o'.
' WHERE '.dbConditionInt('o.operationid', $opgroup)
);
while ($db_opgroup = DBfetch($db_opgroups)) {
$operationid = $db_opgroup['operationid'];
unset($db_opgroup['operationid']);
$operations[$operationid]['opgroup'][] = $db_opgroup;
}
}
}
// get OPERATION_TYPE_TEMPLATE_ADD, OPERATION_TYPE_TEMPLATE_REMOVE data
if ($optemplate) {
if ($this->outputIsRequested('optemplate', $options['selectOperations'])) {
foreach ($optemplate as $operationId) {
$operations[$operationId]['optemplate'] = [];
}
$db_optemplates = DBselect(
'SELECT o.operationid,o.templateid'.
' FROM optemplate o'.
' WHERE '.dbConditionInt('o.operationid', $optemplate)
);
while ($db_optemplate = DBfetch($db_optemplates)) {
$operationid = $db_optemplate['operationid'];
unset($db_optemplate['operationid']);
$operations[$operationid]['optemplate'][] = $db_optemplate;
}
}
}
// get OPERATION_TYPE_HOST_INVENTORY data
if ($opinventory) {
if ($this->outputIsRequested('opinventory', $options['selectOperations'])) {
foreach ($opinventory as $operationId) {
$operations[$operationId]['opinventory'] = [];
}
$db_opinventories = DBselect(
'SELECT o.operationid,o.inventory_mode'.
' FROM opinventory o'.
' WHERE '.dbConditionInt('o.operationid', $opinventory)
);
while ($db_opinventory = DBfetch($db_opinventories)) {
$operationid = $db_opinventory['operationid'];
unset($db_opinventory['operationid']);
$operations[$operationid]['opinventory'] = $db_opinventory;
}
}
}
// get OPERATION_TYPE_HOST_TAGS_ADD, OPERATION_TYPE_HOST_TAGS_REMOVE data
if ($optag) {
if ($this->outputIsRequested('optag', $options['selectOperations'])) {
foreach ($optag as $operationid) {
$operations[$operationid]['optag'] = [];
}
$db_optags = DBselect(
'SELECT o.operationid,o.tag,o.value'.
' FROM optag o'.
' WHERE '.dbConditionInt('o.operationid', $optag)
);
while ($db_optag = DBfetch($db_optags)) {
$operationid = $db_optag['operationid'];
unset($db_optag['operationid']);
$operations[$operationid]['optag'][] = $db_optag;
}
}
}
$operations = $this->unsetExtraFields($operations, ['operationid', 'actionid', 'operationtype'],
$options['selectOperations']
);
$result = $relationMap->mapMany($result, $operations, 'operations');
}
// Adding recovery operations.
if ($options['selectRecoveryOperations'] !== null && $options['selectRecoveryOperations'] != API_OUTPUT_COUNT) {
$recovery_operations = API::getApiService()->select('operations', [
'output' => $this->outputExtend($options['selectRecoveryOperations'],
['operationid', 'actionid', 'operationtype']
),
'filter' => ['actionid' => $actionIds, 'recovery' => ACTION_RECOVERY_OPERATION],
'preservekeys' => true
]);
$relationMap = $this->createRelationMap($recovery_operations, 'actionid', 'operationid');
$recovery_operationids = $relationMap->getRelatedIds();
if ($this->outputIsRequested('opconditions', $options['selectRecoveryOperations'])) {
foreach ($recovery_operations as &$recovery_operation) {
unset($recovery_operation['esc_period'], $recovery_operation['esc_step_from'],
$recovery_operation['esc_step_to']
);
$recovery_operation['opconditions'] = [];
}
unset($recovery_operation);
$res = DBselect('SELECT op.* FROM opconditions op WHERE '.
dbConditionInt('op.operationid', $recovery_operationids)
);
while ($opcondition = DBfetch($res)) {
$recovery_operations[$opcondition['operationid']]['opconditions'][] = $opcondition;
}
}
$opmessage = [];
$opcommand = [];
$op_recovery_message = [];
foreach ($recovery_operations as $recovery_operationid => $recovery_operation) {
unset($recovery_operations[$recovery_operationid]['recovery']);
switch ($recovery_operation['operationtype']) {
case OPERATION_TYPE_MESSAGE:
$opmessage[] = $recovery_operationid;
break;
case OPERATION_TYPE_COMMAND:
$opcommand[] = $recovery_operationid;
break;
case OPERATION_TYPE_RECOVERY_MESSAGE:
$op_recovery_message[] = $recovery_operationid;
break;
}
}
// Get OPERATION_TYPE_MESSAGE data.
if ($opmessage) {
if ($this->outputIsRequested('opmessage', $options['selectRecoveryOperations'])) {
foreach ($opmessage as $recovery_operationid) {
$recovery_operations[$recovery_operationid]['opmessage'] = [];
}
$db_opmessages = DBselect(
'SELECT o.operationid,o.default_msg,o.subject,o.message,o.mediatypeid'.
' FROM opmessage o'.
' WHERE '.dbConditionInt('o.operationid', $opmessage)
);
while ($db_opmessage = DBfetch($db_opmessages)) {
$operationid = $db_opmessage['operationid'];
unset($db_opmessage['operationid']);
$recovery_operations[$operationid]['opmessage'] = $db_opmessage;
}
}
if ($this->outputIsRequested('opmessage_grp', $options['selectRecoveryOperations'])) {
foreach ($opmessage as $recovery_operationid) {
$recovery_operations[$recovery_operationid]['opmessage_grp'] = [];
}
$db_opmessages_grp = DBselect(
'SELECT og.operationid,og.usrgrpid'.
' FROM opmessage_grp og'.
' WHERE '.dbConditionInt('og.operationid', $opmessage)
);
while ($db_opmessage_grp = DBfetch($db_opmessages_grp)) {
$operationid = $db_opmessage_grp['operationid'];
unset($db_opmessage_grp['operationid']);
$recovery_operations[$operationid]['opmessage_grp'][] = $db_opmessage_grp;
}
}
if ($this->outputIsRequested('opmessage_usr', $options['selectRecoveryOperations'])) {
foreach ($opmessage as $recovery_operationid) {
$recovery_operations[$recovery_operationid]['opmessage_usr'] = [];
}
$db_opmessages_usr = DBselect(
'SELECT ou.operationid,ou.userid'.
' FROM opmessage_usr ou'.
' WHERE '.dbConditionInt('ou.operationid', $opmessage)
);
while ($db_opmessage_usr = DBfetch($db_opmessages_usr)) {
$operationid = $db_opmessage_usr['operationid'];
unset($db_opmessage_usr['operationid']);
$recovery_operations[$operationid]['opmessage_usr'][] = $db_opmessage_usr;
}
}
}
// Get OPERATION_TYPE_COMMAND data.
if ($opcommand) {
if ($this->outputIsRequested('opcommand', $options['selectRecoveryOperations'])) {
foreach ($opcommand as $recovery_operationid) {
$recovery_operations[$recovery_operationid]['opcommand'] = [];
}
$db_opcommands = DBselect(
'SELECT o.operationid,o.scriptid'.
' FROM opcommand o'.
' WHERE '.dbConditionInt('o.operationid', $opcommand)
);
while ($db_opcommand = DBfetch($db_opcommands)) {
$operationid = $db_opcommand['operationid'];
unset($db_opcommand['operationid']);
$recovery_operations[$operationid]['opcommand'] = $db_opcommand;
}
}
if ($this->outputIsRequested('opcommand_hst', $options['selectRecoveryOperations'])) {
foreach ($opcommand as $recovery_operationid) {
$recovery_operations[$recovery_operationid]['opcommand_hst'] = [];
}
$db_opcommands_hst = DBselect(
'SELECT oh.opcommand_hstid,oh.operationid,oh.hostid'.
' FROM opcommand_hst oh'.
' WHERE '.dbConditionInt('oh.operationid', $opcommand)
);
while ($db_opcommand_hst = DBfetch($db_opcommands_hst)) {
$operationid = $db_opcommand_hst['operationid'];
unset($db_opcommand_hst['operationid']);
$recovery_operations[$operationid]['opcommand_hst'][] = $db_opcommand_hst;
}
}
if ($this->outputIsRequested('opcommand_grp', $options['selectRecoveryOperations'])) {
foreach ($opcommand as $recovery_operationid) {
$recovery_operations[$recovery_operationid]['opcommand_grp'] = [];
}
$db_opcommands_grp = DBselect(
'SELECT og.opcommand_grpid,og.operationid,og.groupid'.
' FROM opcommand_grp og'.
' WHERE '.dbConditionInt('og.operationid', $opcommand)
);
while ($db_opcommand_grp = DBfetch($db_opcommands_grp)) {
$operationid = $db_opcommand_grp['operationid'];
unset($db_opcommand_grp['operationid']);
$recovery_operations[$operationid]['opcommand_grp'][] = $db_opcommand_grp;
}
}
}
// get OPERATION_TYPE_RECOVERY_MESSAGE data
if ($op_recovery_message) {
if ($this->outputIsRequested('opmessage', $options['selectRecoveryOperations'])) {
foreach ($op_recovery_message as $operationid) {
$recovery_operations[$operationid]['opmessage'] = [];
}
$db_opmessages = DBselect(
'SELECT o.operationid,o.default_msg,o.subject,o.message,o.mediatypeid'.
' FROM opmessage o'.
' WHERE '.dbConditionInt('o.operationid', $op_recovery_message)
);
while ($db_opmessage = DBfetch($db_opmessages)) {
$operationid = $db_opmessage['operationid'];
unset($db_opmessage['operationid']);
$recovery_operations[$operationid]['opmessage'] = $db_opmessage;
}
}
}
$recovery_operations = $this->unsetExtraFields($recovery_operations,
['operationid', 'actionid', 'operationtype'], $options['selectRecoveryOperations']
);
$result = $relationMap->mapMany($result, $recovery_operations, 'recovery_operations');
}
// Adding update operations.
if ($options['selectUpdateOperations'] !== null && $options['selectUpdateOperations'] != API_OUTPUT_COUNT) {
$update_operations = API::getApiService()->select('operations', [
'output' => $this->outputExtend($options['selectUpdateOperations'],
['operationid', 'actionid', 'operationtype']
),
'filter' => ['actionid' => $actionIds, 'recovery' => ACTION_UPDATE_OPERATION],
'preservekeys' => true
]);
foreach ($result as &$action) {
$action['update_operations'] = [];
}
unset($action);
$update_operations = $this->getUpdateOperations($update_operations, $options['selectUpdateOperations']);
foreach ($update_operations as $update_operation) {
$actionid = $update_operation['actionid'];
unset($update_operation['actionid'], $update_operation['recovery']);
$result[$actionid]['update_operations'][] = $update_operation;
}
}
return $result;
}
/**
* Returns an array of update operations according to requested options.
*
* @param array $update_operations An array of update operations.
* @param string $update_operations[<operationid>] Operation ID.
* @param array|string $update_options An array of output options from request, or "extend".
*
* @return array
*/
protected function getUpdateOperations(array $update_operations, $update_options): array {
$opmessages = [];
$nonack_messages = [];
$opcommands = [];
foreach ($update_operations as $operationid => &$update_operation) {
unset($update_operation['esc_period'], $update_operation['esc_step_from'],
$update_operation['esc_step_to']
);
switch ($update_operation['operationtype']) {
case OPERATION_TYPE_UPDATE_MESSAGE:
$opmessages[] = $operationid;
break;
case OPERATION_TYPE_MESSAGE:
$opmessages[] = $operationid;
$nonack_messages[] = $operationid;
break;
case OPERATION_TYPE_COMMAND:
$opcommands[] = $operationid;
break;
}
}
unset($update_operation);
if ($opmessages) {
if ($this->outputIsRequested('opmessage', $update_options)) {
foreach ($opmessages as $operationid) {
$update_operations[$operationid]['opmessage'] = [];
}
$db_opmessages = DBselect(
'SELECT o.operationid,o.default_msg,o.subject,o.message,o.mediatypeid'.
' FROM opmessage o'.
' WHERE '.dbConditionInt('o.operationid', $opmessages)
);
while ($db_opmessage = DBfetch($db_opmessages)) {
$operationid = $db_opmessage['operationid'];
unset($db_opmessage['operationid']);
$update_operations[$operationid]['opmessage'] = $db_opmessage;
}
}
if ($nonack_messages && $this->outputIsRequested('opmessage_grp', $update_options)) {
foreach ($nonack_messages as $operationid) {
$update_operations[$operationid]['opmessage_grp'] = [];
}
$db_opmessage_grp = DBselect(
'SELECT og.operationid,og.usrgrpid'.
' FROM opmessage_grp og'.
' WHERE '.dbConditionInt('og.operationid', $nonack_messages)
);
while ($opmessage_grp = DBfetch($db_opmessage_grp)) {
$operationid = $opmessage_grp['operationid'];
unset($opmessage_grp['operationid']);
$update_operations[$operationid]['opmessage_grp'][] = $opmessage_grp;
}
}
if ($nonack_messages && $this->outputIsRequested('opmessage_usr', $update_options)) {
foreach ($nonack_messages as $operationid) {
$update_operations[$operationid]['opmessage_usr'] = [];
}
$db_opmessage_usr = DBselect(
'SELECT ou.operationid,ou.userid'.
' FROM opmessage_usr ou'.
' WHERE '.dbConditionInt('ou.operationid', $nonack_messages)
);
while ($opmessage_usr = DBfetch($db_opmessage_usr)) {
$operationid = $opmessage_usr['operationid'];
unset($opmessage_usr['operationid']);
$update_operations[$operationid]['opmessage_usr'][] = $opmessage_usr;
}
}
}
if ($opcommands) {
if ($this->outputIsRequested('opcommand', $update_options)) {
foreach ($opcommands as $operationid) {
$update_operations[$operationid]['opcommand'] = [];
}
$db_opcommands = DBselect(
'SELECT o.operationid,o.scriptid'.
' FROM opcommand o'.
' WHERE '.dbConditionInt('o.operationid', $opcommands)
);
while ($db_opcommand = DBfetch($db_opcommands)) {
$operationid = $db_opcommand['operationid'];
unset($db_opcommand['operationid']);
$update_operations[$operationid]['opcommand'] = $db_opcommand;
}
}
if ($this->outputIsRequested('opcommand_hst', $update_options)) {
foreach ($opcommands as $operationid) {
$update_operations[$operationid]['opcommand_hst'] = [];
}
$db_opcommand_hst = DBselect(
'SELECT oh.opcommand_hstid,oh.operationid,oh.hostid'.
' FROM opcommand_hst oh'.
' WHERE '.dbConditionInt('oh.operationid', $opcommands)
);
while ($opcommand_hst = DBfetch($db_opcommand_hst)) {
$operationid = $opcommand_hst['operationid'];
unset($opcommand_hst['operationid']);
$update_operations[$operationid]['opcommand_hst'][] = $opcommand_hst;
}
}
if ($this->outputIsRequested('opcommand_grp', $update_options)) {
foreach ($opcommands as $operationid) {
$update_operations[$operationid]['opcommand_grp'] = [];
}
$db_opcommand_grp = DBselect(
'SELECT og.opcommand_grpid,og.operationid,og.groupid'.
' FROM opcommand_grp og'.
' WHERE '.dbConditionInt('og.operationid', $opcommands)
);
while ($opcommand_grp = DBfetch($db_opcommand_grp)) {
$operationid = $opcommand_grp['operationid'];
unset($opcommand_grp['operationid']);
$update_operations[$operationid]['opcommand_grp'][] = $opcommand_grp;
}
}
}
return $this->unsetExtraFields($update_operations, ['operationid', 'operationtype'], $update_options);
}
protected function applyQueryOutputOptions($tableName, $tableAlias, array $options, array $sqlParts) {
$sqlParts = parent::applyQueryOutputOptions($tableName, $tableAlias, $options, $sqlParts);
if (!$options['countOutput']) {
// add filter fields
if ($this->outputIsRequested('formula', $options['selectFilter'])
|| $this->outputIsRequested('eval_formula', $options['selectFilter'])
|| $this->outputIsRequested('conditions', $options['selectFilter'])) {
$sqlParts = $this->addQuerySelect('a.formula', $sqlParts);
$sqlParts = $this->addQuerySelect('a.evaltype', $sqlParts);
}
if ($this->outputIsRequested('evaltype', $options['selectFilter'])) {
$sqlParts = $this->addQuerySelect('a.evaltype', $sqlParts);
}
}
return $sqlParts;
}
/**
* Returns validation rules for the filter object.
*
* @param int $eventsource Action event source. Possible values:
* EVENT_SOURCE_TRIGGERS, EVENT_SOURCE_DISCOVERY, EVENT_SOURCE_AUTOREGISTRATION,
* EVENT_SOURCE_INTERNAL, EVENT_SOURCE_SERVICE
*
* @return array
*/
private static function getFilterValidationRules(int $eventsource): array {
switch ($eventsource) {
case EVENT_SOURCE_TRIGGERS:
$value_rules = [
['if' => ['field' => 'conditiontype', 'in' => implode(',', [CONDITION_TYPE_HOST_GROUP, CONDITION_TYPE_HOST, CONDITION_TYPE_TRIGGER, CONDITION_TYPE_TEMPLATE])], 'type' => API_ID, 'flags' => API_REQUIRED],
['if' => ['field' => 'conditiontype', 'in' => implode(',', [CONDITION_TYPE_TRIGGER_NAME, CONDITION_TYPE_EVENT_TAG])], 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('conditions', 'value')],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_TRIGGER_SEVERITY], 'type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', range(TRIGGER_SEVERITY_NOT_CLASSIFIED, TRIGGER_SEVERITY_COUNT - 1))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_TIME_PERIOD], 'type' => API_TIME_PERIOD, 'flags' => API_REQUIRED | API_NOT_EMPTY | API_ALLOW_USER_MACRO, 'length' => DB::getFieldLength('conditions', 'value')],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TAG_VALUE], 'type' => API_STRING_UTF8, 'length' => DB::getFieldLength('conditions', 'value')],
['else' => true, 'type' => API_UNEXPECTED]
];
$operator_rules = [
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_HOST_GROUP], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_HOST_GROUP))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_HOST], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_HOST))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_TRIGGER], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_TRIGGER))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_TEMPLATE], 'type' => API_INT32,'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_TEMPLATE))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_TRIGGER_NAME], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_TRIGGER_NAME))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_TRIGGER_SEVERITY], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_TRIGGER_SEVERITY))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_TIME_PERIOD], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_TIME_PERIOD))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_SUPPRESSED], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_SUPPRESSED))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TAG], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_EVENT_TAG))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TAG_VALUE], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_EVENT_TAG_VALUE))]
];
break;
case EVENT_SOURCE_DISCOVERY:
$value_rules = [
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DHOST_IP], 'type' => API_IP_RANGES, 'flags' => API_REQUIRED | API_NOT_EMPTY | API_ALLOW_RANGE, 'length' => DB::getFieldLength('conditions', 'value')],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DSERVICE_TYPE], 'type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [SVC_SSH, SVC_LDAP, SVC_SMTP, SVC_FTP, SVC_HTTP, SVC_POP, SVC_NNTP, SVC_IMAP, SVC_TCP, SVC_AGENT, SVC_SNMPv1, SVC_SNMPv2c, SVC_ICMPPING, SVC_SNMPv3, SVC_HTTPS, SVC_TELNET])],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DSERVICE_PORT], 'type' => API_INT32_RANGES, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('conditions', 'value'), 'in' => ZBX_MIN_PORT_NUMBER.':'.ZBX_MAX_PORT_NUMBER],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DSTATUS], 'type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [DOBJECT_STATUS_UP, DOBJECT_STATUS_DOWN, DOBJECT_STATUS_DISCOVER, DOBJECT_STATUS_LOST])],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DUPTIME], 'type' => API_INT32, 'flags' => API_REQUIRED, 'in' => '0:'.SEC_PER_MONTH],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DVALUE], 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('conditions', 'value')],
['if' => ['field' => 'conditiontype', 'in' => implode(',', [CONDITION_TYPE_DRULE, CONDITION_TYPE_DCHECK, CONDITION_TYPE_PROXY])], 'type' => API_ID, 'flags' => API_REQUIRED],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DOBJECT], 'type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [EVENT_OBJECT_DHOST, EVENT_OBJECT_DSERVICE])]
];
$operator_rules = [
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DHOST_IP], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_DHOST_IP))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DSERVICE_TYPE], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_DSERVICE_TYPE))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DSERVICE_PORT], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_DSERVICE_PORT))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DSTATUS], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_DSTATUS))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DUPTIME], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_DUPTIME))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DVALUE], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_DVALUE))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DRULE], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_DRULE))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DCHECK], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_DCHECK))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_PROXY], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_PROXY))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_DOBJECT], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_DOBJECT))]
];
break;
case EVENT_SOURCE_AUTOREGISTRATION:
$value_rules = [
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_PROXY], 'type' => API_ID, 'flags' => API_REQUIRED],
['if' => ['field' => 'conditiontype', 'in' => implode(',', [CONDITION_TYPE_HOST_NAME, CONDITION_TYPE_HOST_METADATA])], 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('conditions', 'value')]
];
$operator_rules = [
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_PROXY], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_PROXY))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_HOST_NAME], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_HOST_NAME))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_HOST_METADATA], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_HOST_METADATA))]
];
break;
case EVENT_SOURCE_INTERNAL:
$value_rules = [
['if' => ['field' => 'conditiontype', 'in' => implode(',', [CONDITION_TYPE_HOST_GROUP, CONDITION_TYPE_HOST, CONDITION_TYPE_TEMPLATE])], 'type' => API_ID, 'flags' => API_REQUIRED],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TYPE], 'type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [EVENT_TYPE_ITEM_NOTSUPPORTED, EVENT_TYPE_LLDRULE_NOTSUPPORTED, EVENT_TYPE_TRIGGER_UNKNOWN])],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TAG], 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('conditions', 'value')],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TAG_VALUE], 'type' => API_STRING_UTF8, 'length' => DB::getFieldLength('conditions', 'value')]
];
$operator_rules = [
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_HOST_GROUP], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_HOST_GROUP))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_HOST], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_HOST))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_TEMPLATE], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_TEMPLATE))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TYPE], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_EVENT_TYPE))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TAG], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_EVENT_TAG))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TAG_VALUE], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_EVENT_TAG_VALUE))]
];
break;
case EVENT_SOURCE_SERVICE:
$value_rules = [
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_SERVICE], 'type' => API_ID, 'flags' => API_REQUIRED],
['if' => ['field' => 'conditiontype', 'in' => implode(',', [CONDITION_TYPE_SERVICE_NAME, CONDITION_TYPE_EVENT_TAG])], 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('conditions', 'value')],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TAG_VALUE], 'type' => API_STRING_UTF8, 'length' => DB::getFieldLength('conditions', 'value')]
];
$operator_rules = [
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_SERVICE], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_SERVICE))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_SERVICE_NAME], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_SERVICE_NAME))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TAG], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_EVENT_TAG))],
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TAG_VALUE], 'type' => API_INT32, 'in' => implode(',', get_operators_by_conditiontype(CONDITION_TYPE_EVENT_TAG_VALUE))]
];
break;
}
$condition_fields = [
'conditiontype' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', self::VALID_CONDITION_TYPES[$eventsource])],
'operator' => ['type' => API_MULTIPLE, 'flags' => API_REQUIRED, 'rules' => $operator_rules],
'value' => ['type' => API_MULTIPLE, 'rules' => $value_rules],
'value2' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'conditiontype', 'in' => CONDITION_TYPE_EVENT_TAG_VALUE], 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('conditions', 'value2')],
['else' => true, 'type' => API_UNEXPECTED]
]]
];
return [
'evaltype' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [CONDITION_EVAL_TYPE_AND_OR, CONDITION_EVAL_TYPE_AND, CONDITION_EVAL_TYPE_OR, CONDITION_EVAL_TYPE_EXPRESSION])],
'formula' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'evaltype', 'in' => CONDITION_EVAL_TYPE_EXPRESSION], 'type' => API_COND_FORMULA, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('actions', 'formula')],
['else' => true, 'type' => API_UNEXPECTED]
]],
'conditions' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'evaltype', 'in' => CONDITION_EVAL_TYPE_EXPRESSION], 'type' => API_OBJECTS, 'flags' => API_REQUIRED, 'uniq' => [['formulaid']], 'fields' => [
'formulaid' => ['type' => API_COND_FORMULAID, 'flags' => API_REQUIRED]
] + $condition_fields],
['else' => true, 'type' => API_OBJECTS, 'fields' => $condition_fields]
]]
];
}
/**
* Returns validation rules for objects of normal, recovery and update operations.
*
* @param int $recovery Action operation mode. Possible values:
* ACTION_OPERATION, ACTION_RECOVERY_OPERATION, ACTION_UPDATE_OPERATION
* @param int $eventsource Action event source. Possible values:
* EVENT_SOURCE_TRIGGERS, EVENT_SOURCE_DISCOVERY, EVENT_SOURCE_AUTOREGISTRATION,
* EVENT_SOURCE_INTERNAL, EVENT_SOURCE_SERVICE
*
* @return array
*/
private static function getOperationValidationRules(int $recovery, int $eventsource): array {
$escalation_fields = [
'esc_period' => ['type' => API_TIME_UNIT, 'flags' => API_ALLOW_USER_MACRO, 'in' => '0,'.SEC_PER_MIN.':'.SEC_PER_WEEK, 'length' => DB::getFieldLength('operations', 'esc_period')],
'esc_step_from' => ['type' => API_INT32, 'in' => '1:99999'],
'esc_step_to' => ['type' => API_INT32, 'in' => '0:99999']
];
$opmessage_fields = [
'default_msg' => ['type' => API_INT32, 'in' => implode(',', [0, 1]), 'default' => DB::getDefault('opmessage', 'default_msg')],
'subject' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'default_msg', 'in' => 0], 'type' => API_STRING_UTF8, 'length' => DB::getFieldLength('opmessage', 'subject')],
['else' => true, 'type' => API_UNEXPECTED]
]],
'message' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'default_msg', 'in' => 0], 'type' => API_STRING_UTF8, 'length' => DB::getFieldLength('opmessage', 'message')],
['else' => true, 'type' => API_UNEXPECTED]
]]
];
$all_opmessage_fields = [
'opmessage' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'operationtype', 'in' => implode(',', [OPERATION_TYPE_MESSAGE, OPERATION_TYPE_UPDATE_MESSAGE])], 'type' => API_OBJECT, 'flags' => API_REQUIRED, 'fields' => $opmessage_fields + [
'mediatypeid' => ['type' => API_ID]
]],
['if' => ['field' => 'operationtype', 'in' => OPERATION_TYPE_RECOVERY_MESSAGE], 'type' => API_OBJECT, 'flags' => API_REQUIRED, 'fields' => $opmessage_fields],
['else' => true, 'type' => API_UNEXPECTED]
]],
'opmessage_grp' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'operationtype', 'in' => OPERATION_TYPE_MESSAGE], 'type' => API_OBJECTS, 'uniq' => [['usrgrpid']], 'fields' => [
'usrgrpid' => ['type' => API_ID, 'flags' => API_REQUIRED]
]],
['else' => true, 'type' => API_UNEXPECTED]
]],
'opmessage_usr' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'operationtype', 'in' => OPERATION_TYPE_MESSAGE], 'type' => API_OBJECTS, 'uniq' => [['userid']], 'fields' => [
'userid' => ['type' => API_ID, 'flags' => API_REQUIRED]
]],
['else' => true, 'type' => API_UNEXPECTED]
]]
];
$opcommand_fields = [
'opcommand' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'operationtype', 'in' => OPERATION_TYPE_COMMAND], 'type' => API_OBJECT, 'flags' => API_REQUIRED, 'fields' => [
'scriptid' => ['type' => API_ID, 'flags' => API_REQUIRED]
]],
['else' => true, 'type' => API_UNEXPECTED]
]]
];
$common_fields = $all_opmessage_fields + $opcommand_fields + [
'opcommand_grp' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'operationtype', 'in' => OPERATION_TYPE_COMMAND], 'type' => API_OBJECTS, 'uniq' => [['groupid']], 'fields' => [
'groupid' => ['type' => API_ID, 'flags' => API_REQUIRED]
]],
['else' => true, 'type' => API_UNEXPECTED]
]],
'opcommand_hst' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'operationtype', 'in' => OPERATION_TYPE_COMMAND], 'type' => API_OBJECTS, 'uniq' => [['hostid']], 'fields' => [
'hostid' => ['type' => API_ID, 'flags' => API_REQUIRED]
]],
['else' => true, 'type' => API_UNEXPECTED]
]]
];
$operations = getAllowedOperations($eventsource)[$recovery];
sort($operations);
$operationtype_field = [
'operationtype' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', $operations)]
];
switch ($recovery) {
case ACTION_OPERATION:
switch ($eventsource) {
case EVENT_SOURCE_TRIGGERS:
return $operationtype_field + $escalation_fields + [
'evaltype' => ['type' => API_INT32, 'in' => implode(',', [CONDITION_EVAL_TYPE_AND_OR, CONDITION_EVAL_TYPE_AND, CONDITION_EVAL_TYPE_OR])],
'opconditions' => ['type' => API_OBJECTS, 'uniq' => [['value']], 'fields' => [
'conditiontype' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => CONDITION_TYPE_EVENT_ACKNOWLEDGED],
'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'in' => implode(',', [EVENT_NOT_ACKNOWLEDGED, EVENT_ACKNOWLEDGED]), 'length' => DB::getFieldLength('opconditions', 'value')],
'operator' => ['type' => API_INT32, 'in' => CONDITION_OPERATOR_EQUAL]
]]
] + $common_fields;
case EVENT_SOURCE_DISCOVERY:
case EVENT_SOURCE_AUTOREGISTRATION:
return $operationtype_field + $common_fields + [
'opgroup' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'operationtype', 'in' => implode(',', [OPERATION_TYPE_GROUP_ADD, OPERATION_TYPE_GROUP_REMOVE])], 'type' => API_OBJECTS, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'uniq' => [['groupid']], 'fields' => [
'groupid' => ['type' => API_ID, 'flags' => API_REQUIRED]
]],
['else' => true, 'type' => API_UNEXPECTED]
]],
'optemplate' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'operationtype', 'in' => implode(',', [OPERATION_TYPE_TEMPLATE_ADD, OPERATION_TYPE_TEMPLATE_REMOVE])], 'type' => API_OBJECTS, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'uniq' => [['templateid']], 'fields' => [
'templateid' => ['type' => API_ID, 'flags' => API_REQUIRED]
]],
['else' => true, 'type' => API_UNEXPECTED]
]],
'opinventory' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'operationtype', 'in' => OPERATION_TYPE_HOST_INVENTORY], 'type' => API_OBJECT, 'flags' => API_REQUIRED, 'fields' => [
'inventory_mode' => ['type' => API_INT32, 'in' => implode(',', [HOST_INVENTORY_MANUAL, HOST_INVENTORY_AUTOMATIC])]
]],
['else' => true, 'type' => API_UNEXPECTED]
]],
'optag' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'operationtype', 'in' => implode(',', [OPERATION_TYPE_HOST_TAGS_ADD, OPERATION_TYPE_HOST_TAGS_REMOVE])], 'type' => API_OBJECTS, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'uniq' => [['tag', 'value']], 'fields' => [
'tag' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('optag', 'tag')],
'value' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('optag', 'value')]
]],
['else' => true, 'type' => API_UNEXPECTED]
]]
];
case EVENT_SOURCE_INTERNAL:
return $operationtype_field + $escalation_fields + $all_opmessage_fields;
case EVENT_SOURCE_SERVICE:
return $operationtype_field + $escalation_fields + $all_opmessage_fields + $opcommand_fields;
}
break;
case ACTION_RECOVERY_OPERATION:
switch ($eventsource) {
case EVENT_SOURCE_TRIGGERS:
return $operationtype_field + $common_fields;
case EVENT_SOURCE_INTERNAL:
return $operationtype_field + $all_opmessage_fields;
case EVENT_SOURCE_SERVICE:
return $operationtype_field + $all_opmessage_fields + $opcommand_fields;
}
break;
case ACTION_UPDATE_OPERATION:
switch ($eventsource) {
case EVENT_SOURCE_TRIGGERS:
return $operationtype_field + $common_fields;
case EVENT_SOURCE_SERVICE:
return $operationtype_field + $all_opmessage_fields + $opcommand_fields;
}
break;
}
}
/**
* @param array $actions
*
* @throws APIException
*/
private function validateCreate(array &$actions): void {
$api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE, 'uniq' => [['name']], 'fields' => [
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('actions', 'name')],
'eventsource' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [EVENT_SOURCE_TRIGGERS, EVENT_SOURCE_DISCOVERY, EVENT_SOURCE_AUTOREGISTRATION, EVENT_SOURCE_INTERNAL, EVENT_SOURCE_SERVICE])],
'status' => ['type' => API_INT32, 'in' => implode(',', [ACTION_STATUS_ENABLED, ACTION_STATUS_DISABLED])],
'esc_period' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => implode(',', [EVENT_SOURCE_TRIGGERS, EVENT_SOURCE_INTERNAL, EVENT_SOURCE_SERVICE])], 'type' => API_TIME_UNIT, 'flags' => API_ALLOW_USER_MACRO, 'in' => SEC_PER_MIN.':'.SEC_PER_WEEK, 'length' => DB::getFieldLength('actions', 'esc_period')],
['else' => true, 'type' => API_UNEXPECTED]
]],
'pause_symptoms' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_INT32, 'in' => implode(',', [ACTION_PAUSE_SYMPTOMS_FALSE, ACTION_PAUSE_SYMPTOMS_TRUE])],
['else' => true, 'type' => API_UNEXPECTED]
]],
'pause_suppressed' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_INT32, 'in' => implode(',', [ACTION_PAUSE_SUPPRESSED_FALSE, ACTION_PAUSE_SUPPRESSED_TRUE])],
['else' => true, 'type' => API_UNEXPECTED]
]],
'filter' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_OBJECT, 'fields' => self::getFilterValidationRules(EVENT_SOURCE_TRIGGERS)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_DISCOVERY], 'type' => API_OBJECT, 'fields' => self::getFilterValidationRules(EVENT_SOURCE_DISCOVERY)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_AUTOREGISTRATION], 'type' => API_OBJECT, 'fields' => self::getFilterValidationRules(EVENT_SOURCE_AUTOREGISTRATION)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_INTERNAL], 'type' => API_OBJECT, 'fields' => self::getFilterValidationRules(EVENT_SOURCE_INTERNAL)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_SERVICE], 'type' => API_OBJECT, 'fields' => self::getFilterValidationRules(EVENT_SOURCE_SERVICE)]
]],
'operations' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_OPERATION, EVENT_SOURCE_TRIGGERS)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_DISCOVERY], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_OPERATION, EVENT_SOURCE_DISCOVERY)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_AUTOREGISTRATION], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_OPERATION, EVENT_SOURCE_AUTOREGISTRATION)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_INTERNAL], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_OPERATION, EVENT_SOURCE_INTERNAL)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_SERVICE], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_OPERATION, EVENT_SOURCE_SERVICE)]
]],
'recovery_operations' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_RECOVERY_OPERATION, EVENT_SOURCE_TRIGGERS)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_INTERNAL], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_RECOVERY_OPERATION, EVENT_SOURCE_INTERNAL)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_SERVICE], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_RECOVERY_OPERATION, EVENT_SOURCE_SERVICE)],
['else' => true, 'type' => API_UNEXPECTED]
]],
'update_operations' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_UPDATE_OPERATION, EVENT_SOURCE_TRIGGERS)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_SERVICE], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_UPDATE_OPERATION, EVENT_SOURCE_SERVICE)],
['else' => true, 'type' => API_UNEXPECTED]
]],
'notify_if_canceled' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_INT32, 'in' => implode(',', [ACTION_NOTIFY_IF_CANCELED_FALSE, ACTION_NOTIFY_IF_CANCELED_TRUE])],
['else' => true, 'type' => API_UNEXPECTED]
]]
]];
if (!CApiInputValidator::validate($api_input_rules, $actions, '/', $error)) {
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
}
self::checkDuplicates($actions);
self::checkFilter($actions);
self::checkOperations($actions);
self::checkMediatypesPermissions($actions);
self::checkScriptsPermissions($actions);
self::checkHostGroupsPermissions($actions);
self::checkHostsPermissions($actions);
self::checkTemplatesPermissions($actions);
self::checkUsersPermissions($actions);
self::checkUserGroupsPermissions($actions);
self::checkTriggersPermissions($actions);
self::checkDRulesPermissions($actions);
self::checkDChecksPermissions($actions);
self::checkProxiesPermissions($actions);
self::checkServicesPermissions($actions);
}
/**
* @param array $actions
* @param array|null $db_actions
*
* @throws APIException
*/
private function validateUpdate(array &$actions, ?array &$db_actions): void {
$api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE | API_ALLOW_UNEXPECTED, 'uniq' => [['actionid']], 'fields' => [
'actionid' => ['type' => API_ID, 'flags' => API_REQUIRED]
]];
if (!CApiInputValidator::validate($api_input_rules, $actions, '/', $error)) {
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
}
$db_actions = $this->get([
'output' => ['actionid', 'name', 'eventsource', 'status', 'esc_period', 'pause_suppressed',
'notify_if_canceled', 'pause_symptoms'
],
'actionids' => array_column($actions, 'actionid'),
'preservekeys' => true
]);
if (count($actions) != count($db_actions)) {
self::exception(ZBX_API_ERROR_PARAMETERS, _('No permissions to referred object or it does not exist!'));
}
// If not specified, copy original "name" and "eventsource" values for further validation and error reporting.
$actions = $this->extendObjectsByKey($actions, $db_actions, 'actionid', ['name', 'eventsource']);
$api_input_rules = ['type' => API_OBJECTS, 'uniq' => [['name']], 'fields' => [
'actionid' => ['type' => API_ID],
'name' => ['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('actions', 'name')],
'eventsource' => ['type' => API_INT32, 'in' => implode(',', [EVENT_SOURCE_TRIGGERS, EVENT_SOURCE_DISCOVERY, EVENT_SOURCE_AUTOREGISTRATION, EVENT_SOURCE_INTERNAL, EVENT_SOURCE_SERVICE])],
'status' => ['type' => API_INT32, 'in' => implode(',', [ACTION_STATUS_ENABLED, ACTION_STATUS_DISABLED])],
'esc_period' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => implode(',', [EVENT_SOURCE_TRIGGERS, EVENT_SOURCE_INTERNAL, EVENT_SOURCE_SERVICE])], 'type' => API_TIME_UNIT, 'flags' => API_ALLOW_USER_MACRO, 'in' => SEC_PER_MIN.':'.SEC_PER_WEEK, 'length' => DB::getFieldLength('actions', 'esc_period')],
['else' => true, 'type' => API_UNEXPECTED]
]],
'pause_symptoms' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_INT32, 'in' => implode(',', [ACTION_PAUSE_SYMPTOMS_FALSE, ACTION_PAUSE_SYMPTOMS_TRUE])],
['else' => true, 'type' => API_UNEXPECTED]
]],
'pause_suppressed' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_INT32, 'in' => implode(',', [ACTION_PAUSE_SUPPRESSED_FALSE, ACTION_PAUSE_SUPPRESSED_TRUE])],
['else' => true, 'type' => API_UNEXPECTED]
]],
'filter' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_OBJECT, 'fields' => self::getFilterValidationRules(EVENT_SOURCE_TRIGGERS)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_DISCOVERY], 'type' => API_OBJECT, 'fields' => self::getFilterValidationRules(EVENT_SOURCE_DISCOVERY)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_AUTOREGISTRATION], 'type' => API_OBJECT, 'fields' => self::getFilterValidationRules(EVENT_SOURCE_AUTOREGISTRATION)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_INTERNAL], 'type' => API_OBJECT, 'fields' => self::getFilterValidationRules(EVENT_SOURCE_INTERNAL)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_SERVICE], 'type' => API_OBJECT, 'fields' => self::getFilterValidationRules(EVENT_SOURCE_SERVICE)]
]],
'operations' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_OPERATION, EVENT_SOURCE_TRIGGERS)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_DISCOVERY], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_OPERATION, EVENT_SOURCE_DISCOVERY)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_AUTOREGISTRATION], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_OPERATION, EVENT_SOURCE_AUTOREGISTRATION)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_INTERNAL], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_OPERATION, EVENT_SOURCE_INTERNAL)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_SERVICE], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_OPERATION, EVENT_SOURCE_SERVICE)]
]],
'recovery_operations' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_RECOVERY_OPERATION, EVENT_SOURCE_TRIGGERS)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_INTERNAL], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_RECOVERY_OPERATION, EVENT_SOURCE_INTERNAL)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_SERVICE], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_RECOVERY_OPERATION, EVENT_SOURCE_SERVICE)],
['else' => true, 'type' => API_UNEXPECTED]
]],
'update_operations' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_UPDATE_OPERATION, EVENT_SOURCE_TRIGGERS)],
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_SERVICE], 'type' => API_OBJECTS, 'fields' => self::getOperationValidationRules(ACTION_UPDATE_OPERATION, EVENT_SOURCE_SERVICE)],
['else' => true, 'type' => API_UNEXPECTED]
]],
'notify_if_canceled' => ['type' => API_MULTIPLE, 'rules' => [
['if' => ['field' => 'eventsource', 'in' => EVENT_SOURCE_TRIGGERS], 'type' => API_INT32, 'in' => implode(',', [ACTION_NOTIFY_IF_CANCELED_FALSE, ACTION_NOTIFY_IF_CANCELED_TRUE])],
['else' => true, 'type' => API_UNEXPECTED]
]]
]];
if (!CApiInputValidator::validate($api_input_rules, $actions, '/', $error)) {
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
}
self::checkDuplicates($actions, $db_actions);
foreach ($actions as $action) {
if ($action['eventsource'] != $db_actions[$action['actionid']]['eventsource']) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Cannot update "%1$s" for action "%2$s".', 'eventsource', $action['name'])
);
}
}
self::addAffectedObjects($actions, $db_actions);
self::checkFilter($actions);
self::checkOperations($actions, $db_actions);
self::checkMediatypesPermissions($actions);
self::checkScriptsPermissions($actions);
self::checkHostGroupsPermissions($actions);
self::checkHostsPermissions($actions);
self::checkTemplatesPermissions($actions);
self::checkUsersPermissions($actions);
self::checkUserGroupsPermissions($actions);
self::checkTriggersPermissions($actions);
self::checkDRulesPermissions($actions);
self::checkDChecksPermissions($actions);
self::checkProxiesPermissions($actions);
self::checkServicesPermissions($actions);
}
/**
* Check for unique action names.
*
* @param array $actions
* @param array|null $db_actions
*
* @throws APIException if action name is not unique.
*/
private static function checkDuplicates(array $actions, array $db_actions = null): void {
$names = [];
foreach ($actions as $action) {
if ($db_actions === null || $action['name'] !== $db_actions[$action['actionid']]['name']) {
$names[] = $action['name'];
}
}
if (!$names) {
return;
}
$duplicates = DB::select('actions', [
'output' => ['name'],
'filter' => ['name' => $names],
'limit' => 1
]);
if ($duplicates) {
self::exception(ZBX_API_ERROR_PARAMETERS, _s('Action "%1$s" already exists.', $duplicates[0]['name']));
}
}
/**
* @param array $actions
*
* @throws APIException
*/
private static function checkFilter(array $actions): void {
$condition_formula_parser = new CConditionFormula();
$ip_range_parser = new CIPRangeParser(['v6' => ZBX_HAVE_IPV6, 'dns' => false, 'max_ipv4_cidr' => 30]);
foreach ($actions as $i => $action) {
if (!array_key_exists('filter', $action)) {
continue;
}
$path = '/'.($i + 1).'/filter';
if ($action['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) {
$condition_formula_parser->parse($action['filter']['formula']);
$constants = array_column($condition_formula_parser->constants, 'value', 'value');
if (count($action['filter']['conditions']) != count($constants)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Invalid parameter "%1$s": %2$s.', $path.'/conditions', _('incorrect number of conditions'))
);
}
foreach ($action['filter']['conditions'] as $j => $condition) {
if (!array_key_exists($condition['formulaid'], $constants)) {
self::exception(ZBX_API_ERROR_PARAMETERS, _s('Invalid parameter "%1$s": %2$s.',
$path.'/conditions/'.($j + 1).'/formulaid', _('an identifier is not defined in the formula')
));
}
}
}
if (array_key_exists('conditions', $action['filter'])) {
foreach ($action['filter']['conditions'] as $j => $condition) {
if ($condition['conditiontype'] == CONDITION_TYPE_DHOST_IP) {
if (!$ip_range_parser->parse($condition['value'])) {
self::exception(ZBX_API_ERROR_PARAMETERS, _s('Invalid parameter "%1$s": %2$s.',
$path.'/conditions/'.($j + 1).'/value', $ip_range_parser->getError()
));
}
}
elseif ($condition['conditiontype'] == CONDITION_TYPE_DVALUE) {
if ($condition['operator'] == CONDITION_OPERATOR_EQUAL
|| $condition['operator'] == CONDITION_OPERATOR_NOT_EQUAL) {
continue;
}
if ($condition['value'] === '') {
self::exception(ZBX_API_ERROR_PARAMETERS, _s('Invalid parameter "%1$s": %2$s.',
$path.'/conditions/'.($j + 1).'/value', _('cannot be empty')
));
}
}
}
}
}
}
/**
* @param array $actions
* @param array|null $db_actions
*
* @throws APIException
*/
private static function checkOperations(array &$actions, array $db_actions = null): void {
$is_update = ($db_actions !== null);
foreach ($actions as &$action) {
if ($is_update) {
if (!array_intersect_key(array_flip(self::OPERATION_GROUPS), $action)) {
continue;
}
$db_action = $db_actions[$action['actionid']];
}
else {
$db_action = [];
}
$operations = array_intersect_key($action + $db_action, array_flip(self::OPERATION_GROUPS));
if (!array_filter($operations, 'boolval')) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('No operations defined for action "%1$s".', $action['name'])
);
}
$unique_operations = [
OPERATION_TYPE_HOST_ADD => 0,
OPERATION_TYPE_HOST_REMOVE => 0,
OPERATION_TYPE_HOST_ENABLE => 0,
OPERATION_TYPE_HOST_DISABLE => 0,
OPERATION_TYPE_HOST_INVENTORY => 0
];
foreach (self::OPERATION_GROUPS as $recovery => $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as &$operation) {
$operation['recovery'] = $recovery;
if ($recovery == ACTION_OPERATION) {
if (array_key_exists($operation['operationtype'], $unique_operations)) {
$unique_operations[$operation['operationtype']]++;
if ($unique_operations[$operation['operationtype']] > 1) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Operation "%1$s" already exists for action "%2$s".',
operation_type2str($operation['operationtype']), $action['name']
)
);
}
}
if (array_key_exists('esc_step_from', $operation)
|| array_key_exists('esc_step_to', $operation)) {
if (!array_key_exists('esc_step_from', $operation)
|| !array_key_exists('esc_step_to', $operation)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_('Parameters "esc_step_from" and "esc_step_to" must be set together.')
);
}
if ($operation['esc_step_from'] > $operation['esc_step_to']
&& $operation['esc_step_to'] != 0) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_('Incorrect action operation escalation step values.')
);
}
}
}
if ($operation['operationtype'] == OPERATION_TYPE_MESSAGE) {
$has_groups = array_key_exists('opmessage_grp', $operation) && $operation['opmessage_grp'];
$has_users = array_key_exists('opmessage_usr', $operation) && $operation['opmessage_usr'];
if (!$has_groups && !$has_users) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_('No recipients specified for action operation message.')
);
}
}
elseif ($operation['operationtype'] == OPERATION_TYPE_COMMAND
&& $action['eventsource'] != EVENT_SOURCE_SERVICE) {
$has_groups = array_key_exists('opcommand_grp', $operation) && $operation['opcommand_grp'];
$has_hosts = array_key_exists('opcommand_hst', $operation) && $operation['opcommand_hst'];
if (!$has_groups && !$has_hosts) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_('No targets specified for action operation global script.')
);
}
}
}
unset($operation);
}
}
unset($action);
}
/**
* Checks if all the given media types are valid.
*
* @param array $actions
*
* @throws APIException if invalid media types given.
*/
private static function checkMediatypesPermissions(array $actions): void {
$mediatypeids = [];
foreach ($actions as $action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as $operation) {
if ($operation['operationtype'] == OPERATION_TYPE_MESSAGE
|| $operation['operationtype'] == OPERATION_TYPE_UPDATE_MESSAGE) {
if (array_key_exists('mediatypeid', $operation)
&& $operation['opmessage']['mediatypeid'] != 0) {
$mediatypeids[$operation['opmessage']['mediatypeid']] = true;
}
}
}
}
}
if (!$mediatypeids) {
return;
}
$mediatypeids = array_keys($mediatypeids);
$count = API::MediaType()->get([
'countOutput' => true,
'mediatypeids' => $mediatypeids
]);
if ($count != count($mediatypeids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('Incorrect action operation media type. Media type does not exist or you have no access to it.')
);
}
}
/**
* Checks if all the given global scripts are valid.
*
* @param array $actions
*
* @throws APIException if invalid global scripts given.
*/
private static function checkScriptsPermissions(array $actions): void {
$scriptids = [];
foreach ($actions as $action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as $operation) {
if ($operation['operationtype'] == OPERATION_TYPE_COMMAND) {
$scriptids[$operation['opcommand']['scriptid']] = true;
}
}
}
}
if (!$scriptids) {
return;
}
$scriptids = array_keys($scriptids);
$count = API::Script()->get([
'countOutput' => true,
'scriptids' => $scriptids,
'filter' => ['scope' => ZBX_SCRIPT_SCOPE_ACTION]
]);
if ($count != count($scriptids)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_('Specified script does not exist or you do not have rights on it for action operation command.')
);
}
}
/**
* Checks if the current user has access to the given host groups.
*
* @param array $actions
*
* @throws APIException if the user doesn't have write permissions for the given host groups.
*/
private static function checkHostGroupsPermissions(array $actions): void {
$groupids = [];
foreach ($actions as $action) {
if (array_key_exists('filter', $action) && array_key_exists('conditions', $action['filter'])) {
foreach ($action['filter']['conditions'] as $condition) {
if ($condition['conditiontype'] == CONDITION_TYPE_HOST_GROUP) {
$groupids[] = $condition['value'];
}
}
}
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as $operation) {
if ($operation['operationtype'] == OPERATION_TYPE_COMMAND
// Service actions do not support "opcommand_grp".
&& array_key_exists('opcommand_grp', $operation)) {
$groupids = array_merge($groupids, array_column($operation['opcommand_grp'], 'groupid'));
}
elseif ($operation['operationtype'] == OPERATION_TYPE_GROUP_ADD
|| $operation['operationtype'] == OPERATION_TYPE_GROUP_REMOVE) {
$groupids = array_merge($groupids, array_column($operation['opgroup'], 'groupid'));
}
}
}
}
if (!$groupids) {
return;
}
$groupids = array_keys(array_flip($groupids));
$count = API::HostGroup()->get([
'countOutput' => true,
'groupids' => $groupids
]);
if ($count != count($groupids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('Incorrect action condition or operation host group. Host group does not exist or you have no access to it.')
);
}
}
/**
* Checks if the current user has access to the given hosts.
*
* @param array $actions
*
* @throws APIException if the user doesn't have write permissions for the given hosts.
*/
private static function checkHostsPermissions(array $actions): void {
$hostids = [];
foreach ($actions as $action) {
if (array_key_exists('filter', $action) && array_key_exists('conditions', $action['filter'])) {
foreach ($action['filter']['conditions'] as $condition) {
if ($condition['conditiontype'] == CONDITION_TYPE_HOST) {
$hostids[] = $condition['value'];
}
}
}
if ($action['eventsource'] == EVENT_SOURCE_SERVICE) {
continue;
}
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as $operation) {
if ($operation['operationtype'] == OPERATION_TYPE_COMMAND
&& array_key_exists('opcommand_hst', $operation)) {
foreach ($operation['opcommand_hst'] as $opcommand_hst) {
if ($opcommand_hst['hostid'] != 0) {
$hostids[] = $opcommand_hst['hostid'];
}
}
}
}
}
}
if (!$hostids) {
return;
}
$hostids = array_keys(array_flip($hostids));
$count = API::Host()->get([
'countOutput' => true,
'hostids' => $hostids
]);
if ($count != count($hostids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('Incorrect action condition or operation host. Host does not exist or you have no access to it.')
);
}
}
/**
* Checks if the current user has access to the given users.
*
* @param array $actions
*
* @throws APIException if the user doesn't have write permissions for the given users.
*/
private static function checkUsersPermissions(array $actions): void {
$userids = [];
foreach ($actions as $action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as $operation) {
if ($operation['operationtype'] == OPERATION_TYPE_MESSAGE
&& array_key_exists('opmessage_usr', $operation)) {
$userids = array_merge($userids, array_column($operation['opmessage_usr'], 'userid'));
}
}
}
}
if (!$userids) {
return;
}
$userids = array_keys(array_flip($userids));
$count = API::User()->get([
'countOutput' => true,
'userids' => $userids
]);
if ($count != count($userids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('Incorrect action operation user. User does not exist or you have no access to it.')
);
}
}
/**
* Checks if the current user has access to the given user groups.
*
* @param array $actions
*
* @throws APIException if the user doesn't have write permissions for the given user groups.
*/
private static function checkUserGroupsPermissions(array $actions): void {
$usrgrpids = [];
foreach ($actions as $action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as $operation) {
if ($operation['operationtype'] == OPERATION_TYPE_MESSAGE
&& array_key_exists('opmessage_grp', $operation)) {
$usrgrpids = array_merge($usrgrpids, array_column($operation['opmessage_grp'], 'usrgrpid'));
}
}
}
}
if (!$usrgrpids) {
return;
}
$usrgrpids = array_keys(array_flip($usrgrpids));
$count = API::UserGroup()->get([
'countOutput' => true,
'usrgrpids' => $usrgrpids
]);
if ($count != count($usrgrpids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('Incorrect action operation user group. User group does not exist or you have no access to it.')
);
}
}
/**
* Checks if the current user has access to the given templates.
*
* @param array $actions
*
* @throws APIException if the user doesn't have write permissions for the given templates.
*/
private static function checkTemplatesPermissions(array $actions): void {
$templateids = [];
foreach ($actions as $action) {
if (array_key_exists('filter', $action) && array_key_exists('conditions', $action['filter'])) {
foreach ($action['filter']['conditions'] as $condition) {
if ($condition['conditiontype'] == CONDITION_TYPE_TEMPLATE) {
$templateids[] = $condition['value'];
}
}
}
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $action)) {
continue;
}
foreach ($action[$operation_group] as $operation) {
if ($operation['operationtype'] == OPERATION_TYPE_TEMPLATE_ADD
|| $operation['operationtype'] == OPERATION_TYPE_TEMPLATE_REMOVE) {
$templateids = array_merge($templateids, array_column($operation['optemplate'], 'templateid'));
}
}
}
}
if (!$templateids) {
return;
}
$templateids = array_keys(array_flip($templateids));
$count = API::Template()->get([
'countOutput' => true,
'templateids' => $templateids
]);
if ($count != count($templateids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('Incorrect action condition or operation template. Template does not exist or you have no access to it.')
);
}
}
/**
* Checks if the current user has access to the given triggers.
*
* @param array $actions
*
* @throws APIException if the user doesn't have write permissions for the given triggers.
*/
private static function checkTriggersPermissions(array $actions): void {
$triggerids = [];
foreach ($actions as $action) {
if (!array_key_exists('filter', $action) || !array_key_exists('conditions', $action['filter'])) {
continue;
}
foreach ($action['filter']['conditions'] as $condition) {
if ($condition['conditiontype'] == CONDITION_TYPE_TRIGGER) {
$triggerids[$condition['value']] = true;
}
}
}
if (!$triggerids) {
return;
}
$triggerids = array_keys($triggerids);
$count = API::Trigger()->get([
'countOutput' => true,
'triggerids' => $triggerids
]);
if ($count != count($triggerids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('Incorrect action condition trigger. Trigger does not exist or you have no access to it.')
);
}
}
/**
* Checks if the current user has access to the given discovery rules.
*
* @param array $actions
*
* @throws APIException if the user doesn't have write permissions for the given discovery rules.
*/
private static function checkDRulesPermissions(array $actions): void {
$druleids = [];
foreach ($actions as $action) {
if (!array_key_exists('filter', $action) || !array_key_exists('conditions', $action['filter'])) {
continue;
}
foreach ($action['filter']['conditions'] as $condition) {
if ($condition['conditiontype'] == CONDITION_TYPE_DRULE) {
$druleids[$condition['value']] = true;
}
}
}
if (!$druleids) {
return;
}
$druleids = array_keys($druleids);
$count = API::DRule()->get([
'countOutput' => true,
'druleids' => $druleids
]);
if ($count != count($druleids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('Incorrect action condition discovery rule. Discovery rule does not exist or you have no access to it.')
);
}
}
/**
* Checks if the current user has access to the given discovery checks.
*
* @param array $actions
*
* @throws APIException if the user doesn't have write permissions for the given discovery checks.
*/
private static function checkDChecksPermissions(array $actions): void {
$dcheckids = [];
foreach ($actions as $action) {
if (!array_key_exists('filter', $action) || !array_key_exists('conditions', $action['filter'])) {
continue;
}
foreach ($action['filter']['conditions'] as $condition) {
if ($condition['conditiontype'] == CONDITION_TYPE_DCHECK) {
$druleids[$condition['value']] = true;
}
}
}
if (!$dcheckids) {
return;
}
$dcheckids = array_keys($dcheckids);
$count = API::DCheck()->get([
'countOutput' => true,
'dcheckids' => $dcheckids
]);
if ($count != count($dcheckids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('Incorrect action condition discovery check. Discovery check does not exist or you have no access to it.')
);
}
}
/**
* Checks if the current user has access to the given proxies.
*
* @param array $actions
*
* @throws APIException if the user doesn't have write permissions for the given proxies.
*/
private static function checkProxiesPermissions(array $actions): void {
$proxyids = [];
foreach ($actions as $action) {
if (!array_key_exists('filter', $action) || !array_key_exists('conditions', $action['filter'])) {
continue;
}
foreach ($action['filter']['conditions'] as $condition) {
if ($condition['conditiontype'] == CONDITION_TYPE_PROXY) {
$proxyids[$condition['value']] = true;
}
}
}
if (!$proxyids) {
return;
}
$proxyids = array_keys($proxyids);
$count = API::Proxy()->get([
'countOutput' => true,
'proxyids' => $proxyids
]);
if ($count != count($proxyids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('Incorrect action condition proxy. Proxy does not exist or you have no access to it.')
);
}
}
/**
* Checks if the current user has access to the given services.
*
* @param array $actions
*
* @throws APIException if the user doesn't have write permissions for the given services.
*/
private static function checkServicesPermissions(array $actions): void {
$serviceids = [];
foreach ($actions as $action) {
if (!array_key_exists('filter', $action) || !array_key_exists('conditions', $action['filter'])) {
continue;
}
foreach ($action['filter']['conditions'] as $condition) {
if ($condition['conditiontype'] == CONDITION_TYPE_SERVICE) {
$serviceids[$condition['value']] = true;
}
}
}
if ($serviceids) {
return;
}
$serviceids = array_keys($serviceids);
$count = API::Service()->get([
'countOutput' => true,
'serviceids' => $serviceids
]);
if ($count != count($serviceids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_('Incorrect action condition service. Service does not exist or you have no access to it.')
);
}
}
/**
* Add existing filter with conditions and operations to $db_actions if they are affected by the update.
*
* @param array $actions
* @param array|null $db_actions
*/
private static function addAffectedObjects(array $actions, array &$db_actions = null): void {
$actionids = ['filter' => [], 'operations' => []];
foreach ($actions as $action) {
if (array_key_exists('filter', $action)) {
$actionids['filter'][] = $action['actionid'];
$db_actions[$action['actionid']]['filter'] = [];
$db_actions[$action['actionid']]['filter']['conditions'] = [];
}
if (!array_intersect_key(array_flip(self::OPERATION_GROUPS), $action)) {
continue;
}
$actionids['operations'][] = $action['actionid'];
foreach (self::OPERATION_GROUPS as $operation_group) {
$db_actions[$action['actionid']][$operation_group] = [];
}
}
if ($actionids['filter']) {
$options = [
'output' => ['actionid', 'evaltype', 'formula'],
'filter' => ['actionid' => $actionids['filter']]
];
$db_filters = DBselect(DB::makeSql('actions', $options));
while ($db_filter = DBfetch($db_filters)) {
$db_actions[$db_filter['actionid']]['filter'] += array_diff_key($db_filter, array_flip(['actionid']));
}
$options = [
'output' => ['conditionid', 'actionid', 'conditiontype', 'operator', 'value', 'value2'],
'filter' => ['actionid' => $actionids['filter']]
];
$db_conditions = DBselect(DB::makeSql('conditions', $options));
while ($db_condition = DBfetch($db_conditions)) {
$db_actions[$db_condition['actionid']]['filter']['conditions'][$db_condition['conditionid']] =
array_diff_key($db_condition, array_flip(['actionid']));
}
foreach ($db_actions as &$db_action) {
if ($db_action['filter']['evaltype'] == CONDITION_EVAL_TYPE_EXPRESSION) {
$formula = $db_action['filter']['formula'];
$formulaids = CConditionHelper::getFormulaIds($formula);
foreach ($db_action['filter']['conditions'] as &$db_condition) {
$db_condition['formulaid'] = $formulaids[$db_condition['conditionid']];
}
unset($db_condition);
}
}
unset($db_action);
}
if (!$actionids['operations']) {
return;
}
$operationids = array_fill_keys([
'opconditions', 'opmessage_grp', 'opmessage_usr', 'opcommand_grp', 'opcommand_hst', 'opgroup', 'optemplate',
'optag'
], []);
$db_operations = DBselect(
'SELECT o.operationid,o.actionid,o.operationtype,o.esc_period,o.esc_step_from,o.esc_step_to,o.evaltype,'.
'o.recovery,m.default_msg,m.subject,m.message,m.mediatypeid,c.scriptid,i.inventory_mode'.
' FROM operations o'.
' LEFT JOIN opmessage m ON m.operationid=o.operationid'.
' LEFT JOIN opcommand c ON c.operationid=o.operationid'.
' LEFT JOIN opinventory i ON i.operationid=o.operationid'.
' WHERE '.dbConditionId('o.actionid', $actionids['operations'])
);
while ($db_operation = DBfetch($db_operations)) {
$operation = [
'operationid' => $db_operation['operationid'],
'operationtype' => $db_operation['operationtype'],
'evaltype' => $db_operation['evaltype'],
'recovery' => $db_operation['recovery']
];
$eventsource = $db_actions[$db_operation['actionid']]['eventsource'];
if ($db_operation['recovery'] == ACTION_OPERATION
&& in_array($eventsource, [EVENT_SOURCE_TRIGGERS, EVENT_SOURCE_INTERNAL, EVENT_SOURCE_SERVICE])) {
$operation['esc_period'] = $db_operation['esc_period'];
$operation['esc_step_from'] = $db_operation['esc_step_from'];
$operation['esc_step_to'] = $db_operation['esc_step_to'];
if ($eventsource == EVENT_SOURCE_TRIGGERS) {
$operation['opconditions'] = [];
$operationids['opconditions'][$db_operation['operationid']] = true;
}
}
switch ($db_operation['operationtype']) {
case OPERATION_TYPE_MESSAGE:
case OPERATION_TYPE_RECOVERY_MESSAGE:
case OPERATION_TYPE_UPDATE_MESSAGE:
$operation['opmessage'] = [
'default_msg' => $db_operation['default_msg'],
'subject' => $db_operation['subject'],
'message' => $db_operation['message'],
'mediatypeid' => $db_operation['mediatypeid']
];
if ($db_operation['operationtype'] == OPERATION_TYPE_MESSAGE) {
$operation['opmessage_grp'] = [];
$operation['opmessage_usr'] = [];
$operationids['opmessage_grp'][$db_operation['operationid']] = true;
$operationids['opmessage_usr'][$db_operation['operationid']] = true;
}
break;
case OPERATION_TYPE_COMMAND:
$operation['opcommand']['scriptid'] = $db_operation['scriptid'];
if ($eventsource != EVENT_SOURCE_SERVICE) {
$operation['opcommand_grp'] = [];
$operation['opcommand_hst'] = [];
$operationids['opcommand_grp'][$db_operation['operationid']] = true;
$operationids['opcommand_hst'][$db_operation['operationid']] = true;
}
break;
case OPERATION_TYPE_GROUP_ADD:
case OPERATION_TYPE_GROUP_REMOVE:
$operationids['opgroup'][$db_operation['operationid']] = true;
break;
case OPERATION_TYPE_TEMPLATE_ADD:
case OPERATION_TYPE_TEMPLATE_REMOVE:
$operationids['optemplate'][$db_operation['operationid']] = true;
break;
case OPERATION_TYPE_HOST_INVENTORY:
$operation['opinventory']['inventory_mode'] = $db_operation['inventory_mode'];
break;
case OPERATION_TYPE_HOST_TAGS_ADD:
case OPERATION_TYPE_HOST_TAGS_REMOVE:
$operationids['optag'][$db_operation['operationid']] = true;
break;
}
$operation_group = self::OPERATION_GROUPS[$db_operation['recovery']];
$db_actions[$db_operation['actionid']][$operation_group][$db_operation['operationid']] = $operation;
}
$db_opdata = [];
if ($operationids['opconditions']) {
$options = [
'output' => ['opconditionid', 'operationid', 'conditiontype', 'operator', 'value'],
'filter' => ['operationid' => array_keys($operationids['opconditions'])]
];
$db_opconditions = DBselect(DB::makeSql('opconditions', $options));
while ($db_opcondition = DBfetch($db_opconditions)) {
$db_opdata[$db_opcondition['operationid']]['opconditions'][$db_opcondition['opconditionid']] =
array_diff_key($db_opcondition, array_flip(['operationid']));
}
}
if ($operationids['opmessage_grp']) {
$options = [
'output' => ['opmessage_grpid', 'operationid', 'usrgrpid'],
'filter' => ['operationid' => array_keys($operationids['opmessage_grp'])]
];
$db_opmessage_grps = DBselect(DB::makeSql('opmessage_grp', $options));
while ($db_opmessage_grp = DBfetch($db_opmessage_grps)) {
$db_opdata[$db_opmessage_grp['operationid']]['opmessage_grp'][$db_opmessage_grp['opmessage_grpid']] =
array_diff_key($db_opmessage_grp, array_flip(['operationid']));
}
}
if ($operationids['opmessage_usr']) {
$options = [
'output' => ['opmessage_usrid', 'operationid', 'userid'],
'filter' => ['operationid' => array_keys($operationids['opmessage_usr'])]
];
$db_opmessage_usrs = DBselect(DB::makeSql('opmessage_usr', $options));
while ($db_opmessage_usr = DBfetch($db_opmessage_usrs)) {
$db_opdata[$db_opmessage_usr['operationid']]['opmessage_usr'][$db_opmessage_usr['opmessage_usrid']] =
array_diff_key($db_opmessage_usr, array_flip(['operationid']));
}
}
if ($operationids['opcommand_grp']) {
$options = [
'output' => ['opcommand_grpid', 'operationid', 'groupid'],
'filter' => ['operationid' => array_keys($operationids['opcommand_grp'])]
];
$db_opcommand_grps = DBselect(DB::makeSql('opcommand_grp', $options));
while ($db_opcommand_grp = DBfetch($db_opcommand_grps)) {
$db_opdata[$db_opcommand_grp['operationid']]['opcommand_grp'][$db_opcommand_grp['opcommand_grpid']] =
array_diff_key($db_opcommand_grp, array_flip(['operationid']));
}
}
if ($operationids['opcommand_hst']) {
$options = [
'output' => ['opcommand_hstid', 'operationid', 'hostid'],
'filter' => ['operationid' => array_keys($operationids['opcommand_hst'])]
];
$db_opcommand_hsts = DBselect(DB::makeSql('opcommand_hst', $options));
while ($db_opcommand_hst = DBfetch($db_opcommand_hsts)) {
$db_opdata[$db_opcommand_hst['operationid']]['opcommand_hst'][$db_opcommand_hst['opcommand_hstid']] =
array_diff_key($db_opcommand_hst, array_flip(['operationid']));
}
}
if ($operationids['opgroup']) {
$options = [
'output' => ['opgroupid', 'operationid', 'groupid'],
'filter' => ['operationid' => array_keys($operationids['opgroup'])]
];
$db_opgroups = DBselect(DB::makeSql('opgroup', $options));
while ($db_opgroup = DBfetch($db_opgroups)) {
$db_opdata[$db_opgroup['operationid']]['opgroup'][$db_opgroup['opgroupid']] =
array_diff_key($db_opgroup, array_flip(['operationid']));
}
}
if ($operationids['optemplate']) {
$options = [
'output' => ['optemplateid', 'operationid', 'templateid'],
'filter' => ['operationid' => array_keys($operationids['optemplate'])]
];
$db_optemplates = DBselect(DB::makeSql('optemplate', $options));
while ($db_optemplate = DBfetch($db_optemplates)) {
$db_opdata[$db_optemplate['operationid']]['optemplate'][$db_optemplate['optemplateid']] =
array_diff_key($db_optemplate, array_flip(['operationid']));
}
}
if ($operationids['optag']) {
$options = [
'output' => ['optagid', 'operationid', 'tag', 'value'],
'filter' => ['operationid' => array_keys($operationids['optag'])]
];
$db_optags = DBselect(DB::makeSql('optag', $options));
while ($db_optag = DBfetch($db_optags)) {
$db_opdata[$db_optag['operationid']]['optag'][$db_optag['optagid']] =
array_diff_key($db_optag, array_flip(['operationid']));
}
}
foreach ($db_actions as &$db_action) {
foreach (self::OPERATION_GROUPS as $operation_group) {
if (!array_key_exists($operation_group, $db_action)) {
continue;
}
foreach ($db_action[$operation_group] as &$db_operation) {
if (array_key_exists($db_operation['operationid'], $db_opdata)) {
$db_operation = array_merge($db_operation, $db_opdata[$db_operation['operationid']]);
}
}
unset($db_operation);
}
}
unset($db_action);
}
}