2003 lines
59 KiB
Perl
2003 lines
59 KiB
Perl
# --
|
|
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
|
# --
|
|
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
|
# the enclosed file COPYING for license information (GPL). If you
|
|
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
|
# --
|
|
|
|
package Kernel::System::ITSMConfigItem;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
## nofilter(TidyAll::Plugin::OTRS::Migrations::OTRS6::SysConfig)
|
|
|
|
use Kernel::System::EventHandler;
|
|
use Kernel::System::ITSMConfigItem::Definition;
|
|
use Kernel::System::ITSMConfigItem::History;
|
|
use Kernel::System::ITSMConfigItem::Number;
|
|
use Kernel::System::ITSMConfigItem::Permission;
|
|
use Kernel::System::ITSMConfigItem::Version;
|
|
use Kernel::System::ITSMConfigItem::XML;
|
|
use Kernel::System::VariableCheck qw(:all);
|
|
|
|
use Storable;
|
|
|
|
use vars qw(@ISA);
|
|
|
|
our @ObjectDependencies = (
|
|
'Kernel::Config',
|
|
'Kernel::System::DB',
|
|
'Kernel::System::Cache',
|
|
'Kernel::System::GeneralCatalog',
|
|
'Kernel::System::LinkObject',
|
|
'Kernel::System::Log',
|
|
'Kernel::System::Main',
|
|
'Kernel::System::Service',
|
|
'Kernel::System::User',
|
|
'Kernel::System::VirtualFS',
|
|
'Kernel::System::XML',
|
|
);
|
|
|
|
=head1 NAME
|
|
|
|
Kernel::System::ITSMConfigItem - config item lib
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
All config item functions.
|
|
|
|
=head1 PUBLIC INTERFACE
|
|
|
|
=head2 new()
|
|
|
|
create an object
|
|
|
|
use Kernel::System::ObjectManager;
|
|
local $Kernel::OM = Kernel::System::ObjectManager->new();
|
|
my $ConfigItemObject = $Kernel::OM->Get('Kernel::System::ITSMConfigItem');
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my ( $Type, %Param ) = @_;
|
|
|
|
# allocate new hash for object
|
|
my $Self = {};
|
|
bless( $Self, $Type );
|
|
|
|
$Self->{CacheType} = 'ITSMConfigurationManagement';
|
|
$Self->{CacheTTL} = 60 * 60 * 24 * 20;
|
|
|
|
@ISA = qw(
|
|
Kernel::System::ITSMConfigItem::Definition
|
|
Kernel::System::ITSMConfigItem::History
|
|
Kernel::System::ITSMConfigItem::Number
|
|
Kernel::System::ITSMConfigItem::Permission
|
|
Kernel::System::ITSMConfigItem::Version
|
|
Kernel::System::ITSMConfigItem::XML
|
|
Kernel::System::EventHandler
|
|
);
|
|
|
|
# init of event handler
|
|
$Self->EventHandlerInit(
|
|
Config => 'ITSMConfigItem::EventModulePost',
|
|
);
|
|
|
|
return $Self;
|
|
}
|
|
|
|
=head2 ConfigItemCount()
|
|
|
|
count all records of a config item class
|
|
|
|
my $Count = $ConfigItemObject->ConfigItemCount(
|
|
ClassID => 123,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ConfigItemCount {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{ClassID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need ClassID!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get state list
|
|
my $StateList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
|
Class => 'ITSM::ConfigItem::DeploymentState',
|
|
Preferences => {
|
|
Functionality => [ 'preproductive', 'productive' ],
|
|
},
|
|
);
|
|
|
|
return 0 if !%{$StateList};
|
|
|
|
# create state string
|
|
my $DeplStateString = join q{, }, keys %{$StateList};
|
|
|
|
# ask database
|
|
$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => "SELECT COUNT(id) FROM configitem WHERE class_id = ? AND "
|
|
. "cur_depl_state_id IN ( $DeplStateString )",
|
|
Bind => [ \$Param{ClassID} ],
|
|
Limit => 1,
|
|
);
|
|
|
|
# fetch the result
|
|
my $Count = 0;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
$Count = $Row[0];
|
|
}
|
|
|
|
return $Count;
|
|
}
|
|
|
|
=head2 ConfigItemResultList()
|
|
|
|
return a config item list as array hash reference
|
|
|
|
my $ConfigItemListRef = $ConfigItemObject->ConfigItemResultList(
|
|
ClassID => 123,
|
|
Start => 100,
|
|
Limit => 50,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ConfigItemResultList {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{ClassID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need ClassID!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get state list
|
|
my $StateList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
|
Class => 'ITSM::ConfigItem::DeploymentState',
|
|
Preferences => {
|
|
Functionality => [ 'preproductive', 'productive' ],
|
|
},
|
|
);
|
|
|
|
# create state string
|
|
my $DeplStateString = join q{, }, keys %{$StateList};
|
|
|
|
# ask database
|
|
$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => "SELECT id FROM configitem "
|
|
. "WHERE class_id = ? AND cur_depl_state_id IN ( $DeplStateString ) "
|
|
. "ORDER BY change_time DESC",
|
|
Bind => [ \$Param{ClassID} ],
|
|
Start => $Param{Start},
|
|
Limit => $Param{Limit},
|
|
);
|
|
|
|
# fetch the result
|
|
my @ConfigItemIDList;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
push @ConfigItemIDList, $Row[0];
|
|
}
|
|
|
|
# get last versions data
|
|
my @ConfigItemList;
|
|
for my $ConfigItemID (@ConfigItemIDList) {
|
|
|
|
# get version data
|
|
my $LastVersion = $Self->VersionGet(
|
|
ConfigItemID => $ConfigItemID,
|
|
XMLDataGet => 0,
|
|
);
|
|
|
|
push @ConfigItemList, $LastVersion;
|
|
}
|
|
|
|
return \@ConfigItemList;
|
|
}
|
|
|
|
=head2 ConfigItemGet()
|
|
|
|
return a config item as hash reference
|
|
|
|
my $ConfigItem = $ConfigItemObject->ConfigItemGet(
|
|
ConfigItemID => 123,
|
|
Cache => 0, # (optional) default 1 (0|1)
|
|
);
|
|
|
|
A hashref with the following keys is returned:
|
|
|
|
$ConfigItem{ConfigItemID}
|
|
$ConfigItem{Number}
|
|
$ConfigItem{ClassID}
|
|
$ConfigItem{Class}
|
|
$ConfigItem{LastVersionID}
|
|
$ConfigItem{CurDeplStateID}
|
|
$ConfigItem{CurDeplState}
|
|
$ConfigItem{CurDeplStateType}
|
|
$ConfigItem{CurInciStateID}
|
|
$ConfigItem{CurInciState}
|
|
$ConfigItem{CurInciStateType}
|
|
$ConfigItem{CreateTime}
|
|
$ConfigItem{CreateBy}
|
|
$ConfigItem{ChangeTime}
|
|
$ConfigItem{ChangeBy}
|
|
|
|
=cut
|
|
|
|
sub ConfigItemGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{ConfigItemID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need ConfigItemID!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# enable cache per default
|
|
if ( !defined $Param{Cache} ) {
|
|
$Param{Cache} = 1;
|
|
}
|
|
|
|
# check if result is already cached
|
|
my $CacheKey = 'ConfigItemGet::ConfigItemID::' . $Param{ConfigItemID};
|
|
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
|
|
my $Cache = $CacheObject->Get(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey,
|
|
);
|
|
return Storable::dclone($Cache) if $Cache;
|
|
|
|
# ask database
|
|
$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => 'SELECT id, configitem_number, class_id, last_version_id, '
|
|
. 'cur_depl_state_id, cur_inci_state_id, '
|
|
. 'create_time, create_by, change_time, change_by '
|
|
. 'FROM configitem WHERE id = ?',
|
|
Bind => [ \$Param{ConfigItemID} ],
|
|
Limit => 1,
|
|
);
|
|
|
|
# fetch the result
|
|
my %ConfigItem;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
$ConfigItem{ConfigItemID} = $Row[0];
|
|
$ConfigItem{Number} = $Row[1];
|
|
$ConfigItem{ClassID} = $Row[2];
|
|
$ConfigItem{LastVersionID} = $Row[3];
|
|
$ConfigItem{CurDeplStateID} = $Row[4];
|
|
$ConfigItem{CurInciStateID} = $Row[5];
|
|
$ConfigItem{CreateTime} = $Row[6];
|
|
$ConfigItem{CreateBy} = $Row[7];
|
|
$ConfigItem{ChangeTime} = $Row[8];
|
|
$ConfigItem{ChangeBy} = $Row[9];
|
|
}
|
|
|
|
# check config item
|
|
if ( !$ConfigItem{ConfigItemID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "No such ConfigItemID ($Param{ConfigItemID})!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get class list
|
|
my $ClassList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
|
Class => 'ITSM::ConfigItem::Class',
|
|
);
|
|
|
|
$ConfigItem{Class} = $ClassList->{ $ConfigItem{ClassID} };
|
|
|
|
return \%ConfigItem if !$ConfigItem{CurDeplStateID} || !$ConfigItem{CurInciStateID};
|
|
|
|
# get deployment state functionality
|
|
my $DeplState = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemGet(
|
|
ItemID => $ConfigItem{CurDeplStateID},
|
|
);
|
|
|
|
$ConfigItem{CurDeplState} = $DeplState->{Name};
|
|
$ConfigItem{CurDeplStateType} = $DeplState->{Functionality};
|
|
|
|
# get incident state functionality
|
|
my $InciState = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemGet(
|
|
ItemID => $ConfigItem{CurInciStateID},
|
|
);
|
|
|
|
$ConfigItem{CurInciState} = $InciState->{Name};
|
|
$ConfigItem{CurInciStateType} = $InciState->{Functionality};
|
|
|
|
# cache the result
|
|
$CacheObject->Set(
|
|
Type => $Self->{CacheType},
|
|
TTL => $Self->{CacheTTL},
|
|
Key => $CacheKey,
|
|
Value => Storable::dclone( \%ConfigItem ),
|
|
);
|
|
|
|
return \%ConfigItem;
|
|
}
|
|
|
|
=head2 ConfigItemAdd()
|
|
|
|
add a new config item
|
|
|
|
my $ConfigItemID = $ConfigItemObject->ConfigItemAdd(
|
|
Number => '111', # (optional)
|
|
ClassID => 123,
|
|
UserID => 1,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ConfigItemAdd {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Argument (qw(ClassID UserID)) {
|
|
if ( !$Param{$Argument} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Argument!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# get class list
|
|
my $ClassList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
|
Class => 'ITSM::ConfigItem::Class',
|
|
);
|
|
|
|
return if !$ClassList;
|
|
return if ref $ClassList ne 'HASH';
|
|
|
|
# check the class id
|
|
if ( !$ClassList->{ $Param{ClassID} } ) {
|
|
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'No valid class id given!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# create config item number
|
|
if ( $Param{Number} ) {
|
|
|
|
# find existing config item number
|
|
my $Exists = $Self->ConfigItemNumberLookup(
|
|
ConfigItemNumber => $Param{Number},
|
|
);
|
|
|
|
if ($Exists) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Config item number already exists!',
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
|
|
# create config item number
|
|
$Param{Number} = $Self->ConfigItemNumberCreate(
|
|
Type => $Kernel::OM->Get('Kernel::Config')->Get('ITSMConfigItem::NumberGenerator'),
|
|
ClassID => $Param{ClassID},
|
|
);
|
|
}
|
|
|
|
# insert new config item
|
|
my $Success = $Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'INSERT INTO configitem '
|
|
. '(configitem_number, class_id, create_time, create_by, change_time, change_by) '
|
|
. 'VALUES (?, ?, current_timestamp, ?, current_timestamp, ?)',
|
|
Bind => [ \$Param{Number}, \$Param{ClassID}, \$Param{UserID}, \$Param{UserID} ],
|
|
);
|
|
|
|
return if !$Success;
|
|
|
|
# find id of new item
|
|
$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => 'SELECT id FROM configitem WHERE '
|
|
. 'configitem_number = ? AND class_id = ? ORDER BY id DESC',
|
|
Bind => [ \$Param{Number}, \$Param{ClassID} ],
|
|
Limit => 1,
|
|
);
|
|
|
|
# fetch the result
|
|
my $ConfigItemID;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
$ConfigItemID = $Row[0];
|
|
}
|
|
|
|
# trigger ConfigItemCreate
|
|
$Self->EventHandler(
|
|
Event => 'ConfigItemCreate',
|
|
Data => {
|
|
ConfigItemID => $ConfigItemID,
|
|
Comment => $ConfigItemID . '%%' . $Param{Number},
|
|
},
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
return $ConfigItemID;
|
|
}
|
|
|
|
=head2 ConfigItemDelete()
|
|
|
|
delete an existing config item
|
|
|
|
my $True = $ConfigItemObject->ConfigItemDelete(
|
|
ConfigItemID => 123,
|
|
UserID => 1,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ConfigItemDelete {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Argument (qw(ConfigItemID UserID)) {
|
|
if ( !$Param{$Argument} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Argument!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# remember config item data before delete
|
|
my $ConfigItemData = $Self->ConfigItemGet(
|
|
ConfigItemID => $Param{ConfigItemID},
|
|
);
|
|
|
|
# delete all links to this config item first, before deleting the versions
|
|
return if !$Kernel::OM->Get('Kernel::System::LinkObject')->LinkDeleteAll(
|
|
Object => 'ITSMConfigItem',
|
|
Key => $Param{ConfigItemID},
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
# delete existing versions
|
|
$Self->VersionDelete(
|
|
ConfigItemID => $Param{ConfigItemID},
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
# get a list of all attachments
|
|
my @ExistingAttachments = $Self->ConfigItemAttachmentList(
|
|
ConfigItemID => $Param{ConfigItemID},
|
|
);
|
|
|
|
# delete all attachments of this config item
|
|
FILENAME:
|
|
for my $Filename (@ExistingAttachments) {
|
|
|
|
# delete the attachment
|
|
my $DeletionSuccess = $Self->ConfigItemAttachmentDelete(
|
|
ConfigItemID => $Param{ConfigItemID},
|
|
Filename => $Filename,
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
if ( !$DeletionSuccess ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Unknown problem when deleting attachment $Filename of ConfigItem "
|
|
. "$Param{ConfigItemID}. Please check the VirtualFS backend for stale "
|
|
. "files!",
|
|
);
|
|
}
|
|
}
|
|
|
|
# trigger ConfigItemDelete event
|
|
# this must be done before deleting the config item from the database,
|
|
# because of a foreign key constraint in the configitem_history table
|
|
$Self->EventHandler(
|
|
Event => 'ConfigItemDelete',
|
|
Data => {
|
|
ConfigItemID => $Param{ConfigItemID},
|
|
Comment => $Param{ConfigItemID},
|
|
Number => $ConfigItemData->{Number},
|
|
Class => $ConfigItemData->{Class},
|
|
},
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
# delete config item
|
|
my $Success = $Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'DELETE FROM configitem WHERE id = ?',
|
|
Bind => [ \$Param{ConfigItemID} ],
|
|
);
|
|
|
|
# delete the cache
|
|
my $CacheKey = 'ConfigItemGet::ConfigItemID::' . $Param{ConfigItemID};
|
|
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey,
|
|
);
|
|
|
|
return $Success;
|
|
}
|
|
|
|
=head2 ConfigItemAttachmentAdd()
|
|
|
|
adds an attachment to a config item
|
|
|
|
my $Success = $ConfigItemObject->ConfigItemAttachmentAdd(
|
|
ConfigItemID => 1,
|
|
Filename => 'filename',
|
|
Content => 'content',
|
|
ContentType => 'text/plain',
|
|
UserID => 1,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ConfigItemAttachmentAdd {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Needed (qw(ConfigItemID Filename Content ContentType UserID)) {
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Needed!",
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
# write to virtual fs
|
|
my $Success = $Kernel::OM->Get('Kernel::System::VirtualFS')->Write(
|
|
Filename => "ConfigItem/$Param{ConfigItemID}/$Param{Filename}",
|
|
Mode => 'binary',
|
|
Content => \$Param{Content},
|
|
Preferences => {
|
|
ContentID => $Param{ContentID},
|
|
ContentType => $Param{ContentType},
|
|
ConfigItemID => $Param{ConfigItemID},
|
|
UserID => $Param{UserID},
|
|
},
|
|
);
|
|
|
|
# check for error
|
|
if ($Success) {
|
|
|
|
# trigger AttachmentAdd-Event
|
|
$Self->EventHandler(
|
|
Event => 'AttachmentAddPost',
|
|
Data => {
|
|
%Param,
|
|
ConfigItemID => $Param{ConfigItemID},
|
|
Comment => $Param{Filename},
|
|
HistoryType => 'AttachmentAdd',
|
|
},
|
|
UserID => $Param{UserID},
|
|
);
|
|
}
|
|
else {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Cannot add attachment for config item $Param{ConfigItemID}",
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 ConfigItemAttachmentDelete()
|
|
|
|
Delete the given file from the virtual filesystem.
|
|
|
|
my $Success = $ConfigItemObject->ConfigItemAttachmentDelete(
|
|
ConfigItemID => 123, # used in event handling, e.g. for logging the history
|
|
Filename => 'Projectplan.pdf', # identifies the attachment (together with the ConfigItemID)
|
|
UserID => 1,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ConfigItemAttachmentDelete {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Needed (qw(ConfigItemID Filename UserID)) {
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Needed!",
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
# add prefix
|
|
my $Filename = 'ConfigItem/' . $Param{ConfigItemID} . '/' . $Param{Filename};
|
|
|
|
# delete file
|
|
my $Success = $Kernel::OM->Get('Kernel::System::VirtualFS')->Delete(
|
|
Filename => $Filename,
|
|
);
|
|
|
|
# check for error
|
|
if ($Success) {
|
|
|
|
# trigger AttachmentDeletePost-Event
|
|
$Self->EventHandler(
|
|
Event => 'AttachmentDeletePost',
|
|
Data => {
|
|
%Param,
|
|
ConfigItemID => $Param{ConfigItemID},
|
|
Comment => $Param{Filename},
|
|
HistoryType => 'AttachmentDelete',
|
|
},
|
|
UserID => $Param{UserID},
|
|
);
|
|
}
|
|
else {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Cannot delete attachment $Filename!",
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
return $Success;
|
|
}
|
|
|
|
=head2 ConfigItemAttachmentGet()
|
|
|
|
This method returns information about one specific attachment.
|
|
|
|
my $Attachment = $ConfigItemObject->ConfigItemAttachmentGet(
|
|
ConfigItemID => 4,
|
|
Filename => 'test.txt',
|
|
);
|
|
|
|
returns
|
|
|
|
{
|
|
Preferences => {
|
|
AllPreferences => 'test',
|
|
},
|
|
Filename => 'test.txt',
|
|
Content => 'content',
|
|
ContentType => 'text/plain',
|
|
Filesize => 12348409,
|
|
Type => 'attachment',
|
|
}
|
|
|
|
=cut
|
|
|
|
sub ConfigItemAttachmentGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Argument (qw(ConfigItemID Filename)) {
|
|
if ( !$Param{$Argument} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Argument!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# add prefix
|
|
my $Filename = 'ConfigItem/' . $Param{ConfigItemID} . '/' . $Param{Filename};
|
|
|
|
# find all attachments of this config item
|
|
my @Attachments = $Kernel::OM->Get('Kernel::System::VirtualFS')->Find(
|
|
Filename => $Filename,
|
|
Preferences => {
|
|
ConfigItemID => $Param{ConfigItemID},
|
|
},
|
|
);
|
|
|
|
# return error if file does not exist
|
|
if ( !@Attachments ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Message => "No such attachment ($Filename)!",
|
|
Priority => 'error',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get data for attachment
|
|
my %AttachmentData = $Kernel::OM->Get('Kernel::System::VirtualFS')->Read(
|
|
Filename => $Filename,
|
|
Mode => 'binary',
|
|
);
|
|
|
|
my $AttachmentInfo = {
|
|
%AttachmentData,
|
|
Filename => $Param{Filename},
|
|
Content => ${ $AttachmentData{Content} },
|
|
ContentType => $AttachmentData{Preferences}->{ContentType},
|
|
Type => 'attachment',
|
|
Filesize => $AttachmentData{Preferences}->{FilesizeRaw},
|
|
};
|
|
|
|
return $AttachmentInfo;
|
|
}
|
|
|
|
=head2 ConfigItemAttachmentList()
|
|
|
|
Returns an array with all attachments of the given config item.
|
|
|
|
my @Attachments = $ConfigItemObject->ConfigItemAttachmentList(
|
|
ConfigItemID => 123,
|
|
);
|
|
|
|
returns
|
|
|
|
@Attachments = (
|
|
'filename.txt',
|
|
'other_file.pdf',
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ConfigItemAttachmentList {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{ConfigItemID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need ConfigItemID!',
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
# find all attachments of this config item
|
|
my @Attachments = $Kernel::OM->Get('Kernel::System::VirtualFS')->Find(
|
|
Preferences => {
|
|
ConfigItemID => $Param{ConfigItemID},
|
|
},
|
|
);
|
|
|
|
for my $Filename (@Attachments) {
|
|
|
|
# remove extra information from filename
|
|
$Filename =~ s{ \A ConfigItem / \d+ / }{}xms;
|
|
}
|
|
|
|
return @Attachments;
|
|
}
|
|
|
|
=head2 ConfigItemAttachmentExists()
|
|
|
|
Checks if a file with a given filename exists.
|
|
|
|
my $Exists = $ConfigItemObject->ConfigItemAttachmentExists(
|
|
Filename => 'test.txt',
|
|
ConfigItemID => 123,
|
|
UserID => 1,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ConfigItemAttachmentExists {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Needed (qw(Filename ConfigItemID UserID)) {
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Needed!",
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
return if !$Kernel::OM->Get('Kernel::System::VirtualFS')->Find(
|
|
Filename => 'ConfigItem/' . $Param{ConfigItemID} . '/' . $Param{Filename},
|
|
);
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 ConfigItemSearchExtended()
|
|
|
|
return a config item list as an array reference
|
|
|
|
my $ConfigItemIDs = $ConfigItemObject->ConfigItemSearchExtended(
|
|
Number => 'The ConfigItem Number', # (optional)
|
|
Name => 'The Name', # (optional)
|
|
ClassIDs => [9, 8, 7, 6], # (optional)
|
|
DeplStateIDs => [1, 2, 3, 4], # (optional)
|
|
InciStateIDs => [1, 2, 3, 4], # (optional)
|
|
|
|
# config items with created time after ...
|
|
ConfigItemCreateTimeNewerDate => '2006-01-09 00:00:01', # (optional)
|
|
# config items with created time before then ....
|
|
ConfigItemCreateTimeOlderDate => '2006-01-19 23:59:59', # (optional)
|
|
|
|
# config items with changed time after ...
|
|
ConfigItemChangeTimeNewerDate => '2006-01-09 00:00:01', # (optional)
|
|
# config items with changed time before then ....
|
|
ConfigItemChangeTimeOlderDate => '2006-01-19 23:59:59', # (optional)
|
|
|
|
What => [ # (optional)
|
|
# each array element is a and condition
|
|
{
|
|
# or condition in hash
|
|
"[%]{'ElementA'}[%]{'ElementB'}[%]{'Content'}" => '%contentA%',
|
|
"[%]{'ElementA'}[%]{'ElementC'}[%]{'Content'}" => '%contentA%',
|
|
},
|
|
{
|
|
"[%]{'ElementA'}[%]{'ElementB'}[%]{'Content'}" => '%contentB%',
|
|
"[%]{'ElementA'}[%]{'ElementC'}[%]{'Content'}" => '%contentB%',
|
|
},
|
|
{
|
|
# use array reference if different content with same key was searched
|
|
"[%]{'ElementA'}[%]{'ElementB'}[%]{'Content'}" => ['%contentC%', '%contentD%', '%contentE%'],
|
|
"[%]{'ElementA'}[%]{'ElementC'}[%]{'Content'}" => ['%contentC%', '%contentD%', '%contentE%'],
|
|
},
|
|
],
|
|
|
|
PreviousVersionSearch => 1, # (optional) default 0 (0|1)
|
|
|
|
OrderBy => [ 'ConfigItemID', 'Number' ], # (optional)
|
|
# default: [ 'ConfigItemID' ]
|
|
# (ConfigItemID, Number, Name, ClassID, DeplStateID, InciStateID,
|
|
# CreateTime, CreateBy, ChangeTime, ChangeBy)
|
|
|
|
# Additional information for OrderBy:
|
|
# The OrderByDirection can be specified for each OrderBy attribute.
|
|
# The pairing is made by the array indices.
|
|
|
|
OrderByDirection => [ 'Down', 'Up' ], # (optional)
|
|
# default: [ 'Down' ]
|
|
# (Down | Up)
|
|
|
|
Limit => 122, # (optional)
|
|
UsingWildcards => 0, # (optional) default 1
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ConfigItemSearchExtended {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# set limit
|
|
my $Limit = $Param{Limit};
|
|
$Param{Limit} = undef;
|
|
|
|
# config item search is required if one of these params is given
|
|
my @ConfigItemSearchParams = (
|
|
'ConfigItemCreateTimeNewerDate',
|
|
'ConfigItemCreateTimeOlderDate',
|
|
'ConfigItemChangeTimeNewerDate',
|
|
'ConfigItemChangeTimeOlderDate',
|
|
);
|
|
|
|
# check, if config item search is required
|
|
my %RequiredSearch;
|
|
CONFIGITEMPARAM:
|
|
for my $ConfigItemParam (@ConfigItemSearchParams) {
|
|
next CONFIGITEMPARAM if !$Param{$ConfigItemParam};
|
|
|
|
$RequiredSearch{ConfigItem} = 1;
|
|
last CONFIGITEMPARAM;
|
|
}
|
|
|
|
# special handling for config item number
|
|
# number 0 is allowed but not the empty string
|
|
if ( defined $Param{Number} && $Param{Number} ne '' ) {
|
|
$RequiredSearch{ConfigItem} = 1;
|
|
}
|
|
|
|
# version search is required if Name, What or PreviousVersionSearch is given
|
|
if (
|
|
IsStringWithData( $Param{Name} )
|
|
|| IsArrayRefWithData( $Param{What} )
|
|
|| $Param{PreviousVersionSearch}
|
|
)
|
|
{
|
|
$RequiredSearch{Version} = 1;
|
|
}
|
|
|
|
# version search is also required if sorting by name (fix for bug #7072)
|
|
ORDERBY:
|
|
for my $OrderBy ( @{ $Param{OrderBy} } ) {
|
|
if ( $OrderBy eq 'Name' ) {
|
|
$RequiredSearch{Version} = 1;
|
|
last ORDERBY;
|
|
}
|
|
}
|
|
|
|
# xml version search is required if What is given
|
|
if ( IsArrayRefWithData( $Param{What} ) ) {
|
|
$RequiredSearch{XMLVersion} = 1;
|
|
}
|
|
|
|
# use config item search as fallback
|
|
if ( !%RequiredSearch ) {
|
|
$RequiredSearch{ConfigItem} = 1;
|
|
}
|
|
|
|
# start config item search
|
|
my %ConfigItemLists;
|
|
if ( $RequiredSearch{ConfigItem} ) {
|
|
|
|
# search config items
|
|
$ConfigItemLists{ConfigItem} = $Self->ConfigItemSearch(%Param);
|
|
|
|
return if !$ConfigItemLists{ConfigItem};
|
|
return if ref $ConfigItemLists{ConfigItem} ne 'ARRAY';
|
|
return [] if !@{ $ConfigItemLists{ConfigItem} };
|
|
}
|
|
|
|
# start version search
|
|
if ( $RequiredSearch{Version} ) {
|
|
|
|
# search versions
|
|
$ConfigItemLists{Version} = $Self->VersionSearch(%Param);
|
|
|
|
return if !$ConfigItemLists{Version};
|
|
return if ref $ConfigItemLists{Version} ne 'ARRAY';
|
|
return [] if !@{ $ConfigItemLists{Version} };
|
|
}
|
|
|
|
# start xml version search
|
|
if ( $RequiredSearch{XMLVersion} ) {
|
|
|
|
# search xml versions
|
|
my $XMLVersionList = $Self->_XMLVersionSearch(%Param);
|
|
|
|
return if !$XMLVersionList;
|
|
return if ref $XMLVersionList ne 'HASH';
|
|
return [] if !%{$XMLVersionList};
|
|
|
|
# get config item ids
|
|
my %ConfigItemListTmp;
|
|
VERSIONID:
|
|
for my $VersionID ( sort keys %{$XMLVersionList} ) {
|
|
my $ConfigItemID = $Self->VersionConfigItemIDGet(
|
|
VersionID => $VersionID,
|
|
);
|
|
|
|
next VERSIONID if !$ConfigItemID;
|
|
|
|
$ConfigItemListTmp{$ConfigItemID} = 1;
|
|
}
|
|
|
|
# add ids to config item list
|
|
$ConfigItemLists{XMLVersion} = \%ConfigItemListTmp;
|
|
}
|
|
|
|
# create the result list
|
|
my @ResultList;
|
|
if ( $RequiredSearch{ConfigItem} && $RequiredSearch{Version} ) {
|
|
|
|
# build a lookup hash of all found configitem ids in $ConfigItemLists{ConfigItem}
|
|
my %ConfigItemSeen = map { $_ => 1 } @{ $ConfigItemLists{ConfigItem} };
|
|
|
|
# check all config item ids, we need to keep the sorting
|
|
CONFIGITEMID:
|
|
for my $ConfigItemID ( @{ $ConfigItemLists{Version} } ) {
|
|
next CONFIGITEMID if !$ConfigItemSeen{$ConfigItemID};
|
|
push @ResultList, $ConfigItemID;
|
|
}
|
|
}
|
|
elsif ( $RequiredSearch{ConfigItem} ) {
|
|
@ResultList = @{ $ConfigItemLists{ConfigItem} };
|
|
}
|
|
elsif ( $RequiredSearch{Version} ) {
|
|
@ResultList = @{ $ConfigItemLists{Version} };
|
|
}
|
|
|
|
# consider the XML result
|
|
if ( $RequiredSearch{XMLVersion} ) {
|
|
@ResultList = grep { $ConfigItemLists{XMLVersion}->{$_} } @ResultList;
|
|
}
|
|
|
|
# consider limit
|
|
if ( $Limit && $Limit < scalar @ResultList ) {
|
|
|
|
# extract the limited ids
|
|
$Limit--;
|
|
@ResultList = @ResultList[ 0 .. $Limit ];
|
|
}
|
|
|
|
return \@ResultList;
|
|
}
|
|
|
|
=head2 ConfigItemSearch()
|
|
|
|
return a config item list as an array reference
|
|
|
|
my $ConfigItemIDs = $ConfigItemObject->ConfigItemSearch(
|
|
Number => 'The ConfigItem Number', # (optional)
|
|
ClassIDs => [9, 8, 7, 6], # (optional)
|
|
DeplStateIDs => [1, 2, 3, 4], # (optional)
|
|
InciStateIDs => [1, 2, 3, 4], # (optional)
|
|
CreateBy => [1, 2, 3], # (optional)
|
|
ChangeBy => [3, 2, 1], # (optional)
|
|
|
|
# config items with created time after ...
|
|
ConfigItemCreateTimeNewerDate => '2006-01-09 00:00:01', # (optional)
|
|
# config items with created time before then ....
|
|
ConfigItemCreateTimeOlderDate => '2006-01-19 23:59:59', # (optional)
|
|
|
|
# config items with changed time after ...
|
|
ConfigItemChangeTimeNewerDate => '2006-01-09 00:00:01', # (optional)
|
|
# config items with changed time before then ....
|
|
ConfigItemChangeTimeOlderDate => '2006-01-19 23:59:59', # (optional)
|
|
|
|
OrderBy => [ 'ConfigItemID', 'Number' ], # (optional)
|
|
# default: [ 'ConfigItemID' ]
|
|
# (ConfigItemID, Number, ClassID, DeplStateID, InciStateID,
|
|
# CreateTime, CreateBy, ChangeTime, ChangeBy)
|
|
|
|
# Additional information for OrderBy:
|
|
# The OrderByDirection can be specified for each OrderBy attribute.
|
|
# The pairing is made by the array indices.
|
|
|
|
OrderByDirection => [ 'Down', 'Up' ], # (optional)
|
|
# default: [ 'Down' ]
|
|
# (Down | Up)
|
|
|
|
Limit => 122, # (optional)
|
|
UsingWildcards => 0, # (optional) default 1
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ConfigItemSearch {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# verify that all passed array parameters contain an arrayref
|
|
ARGUMENT:
|
|
for my $Argument (
|
|
qw(
|
|
OrderBy
|
|
OrderByDirection
|
|
)
|
|
)
|
|
{
|
|
if ( !defined $Param{$Argument} ) {
|
|
$Param{$Argument} ||= [];
|
|
|
|
next ARGUMENT;
|
|
}
|
|
|
|
if ( ref $Param{$Argument} ne 'ARRAY' ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "$Argument must be an array reference!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# define order table
|
|
my %OrderByTable = (
|
|
ConfigItemID => 'id',
|
|
Number => 'configitem_number',
|
|
ClassID => 'class_id',
|
|
DeplStateID => 'cur_depl_state_id',
|
|
InciStateID => 'cur_inci_state_id',
|
|
CreateTime => 'create_time',
|
|
CreateBy => 'create_by',
|
|
ChangeTime => 'change_time',
|
|
ChangeBy => 'change_by',
|
|
);
|
|
|
|
# check if OrderBy contains only unique valid values
|
|
my %OrderBySeen;
|
|
ORDERBY:
|
|
for my $OrderBy ( @{ $Param{OrderBy} } ) {
|
|
|
|
next ORDERBY if $OrderBy eq 'Name';
|
|
|
|
if ( !$OrderBy || !$OrderByTable{$OrderBy} || $OrderBySeen{$OrderBy} ) {
|
|
|
|
# found an error
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "OrderBy contains invalid value '$OrderBy' "
|
|
. 'or the value is used more than once!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# remember the value to check if it appears more than once
|
|
$OrderBySeen{$OrderBy} = 1;
|
|
}
|
|
|
|
# check if OrderByDirection array contains only 'Up' or 'Down'
|
|
DIRECTION:
|
|
for my $Direction ( @{ $Param{OrderByDirection} } ) {
|
|
|
|
# only 'Up' or 'Down' allowed
|
|
next DIRECTION if $Direction eq 'Up';
|
|
next DIRECTION if $Direction eq 'Down';
|
|
|
|
# found an error
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "OrderByDirection can only contain 'Up' or 'Down'!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# set default values
|
|
if ( !defined $Param{UsingWildcards} ) {
|
|
$Param{UsingWildcards} = 1;
|
|
}
|
|
|
|
# get like escape string needed for some databases (e.g. oracle)
|
|
my $LikeEscapeString = $Kernel::OM->Get('Kernel::System::DB')->GetDatabaseFunction('LikeEscapeString');
|
|
|
|
# assemble the ORDER BY clause
|
|
my @SQLOrderBy;
|
|
my $Count = 0;
|
|
ORDERBY:
|
|
for my $OrderBy ( @{ $Param{OrderBy} } ) {
|
|
|
|
next ORDERBY if $OrderBy eq 'Name';
|
|
|
|
# set the default order direction
|
|
my $Direction = 'DESC';
|
|
|
|
# add the given order direction
|
|
if ( $Param{OrderByDirection}->[$Count] ) {
|
|
if ( $Param{OrderByDirection}->[$Count] eq 'Up' ) {
|
|
$Direction = 'ASC';
|
|
}
|
|
elsif ( $Param{OrderByDirection}->[$Count] eq 'Down' ) {
|
|
$Direction = 'DESC';
|
|
}
|
|
}
|
|
|
|
# add SQL
|
|
push @SQLOrderBy, "$OrderByTable{$OrderBy} $Direction";
|
|
|
|
}
|
|
continue {
|
|
$Count++;
|
|
}
|
|
|
|
# if there is a possibility that the ordering is not determined
|
|
# we add an ascending ordering by id
|
|
if ( !grep { $_ eq 'ConfigItemID' } ( @{ $Param{OrderBy} } ) ) {
|
|
push @SQLOrderBy, "$OrderByTable{ConfigItemID} ASC";
|
|
}
|
|
|
|
# add number to sql where array
|
|
my @SQLWhere;
|
|
if ( defined $Param{Number} && $Param{Number} ne '' && ref $Param{Number} ne 'ARRAY' ) {
|
|
|
|
# quote
|
|
$Param{Number} = $Kernel::OM->Get('Kernel::System::DB')->Quote( $Param{Number} );
|
|
|
|
if ( $Param{UsingWildcards} ) {
|
|
|
|
# prepare like string
|
|
$Self->_PrepareLikeString( \$Param{Number} );
|
|
|
|
push @SQLWhere,
|
|
"LOWER(configitem_number) LIKE LOWER('$Param{Number}') $LikeEscapeString";
|
|
}
|
|
else {
|
|
push @SQLWhere, "LOWER(configitem_number) = LOWER('$Param{Number}')";
|
|
}
|
|
}
|
|
elsif ( defined $Param{Number} && $Param{Number} ne '' && ref $Param{Number} eq 'ARRAY' ) {
|
|
|
|
# Create string.
|
|
my $InString = join q{, }, @{ $Param{Number} };
|
|
|
|
push @SQLWhere, "LOWER(configitem_number) IN ($InString)";
|
|
}
|
|
|
|
# set array params
|
|
my %ArrayParams = (
|
|
ConfigItemIDs => 'id',
|
|
ClassIDs => 'class_id',
|
|
DeplStateIDs => 'cur_depl_state_id',
|
|
InciStateIDs => 'cur_inci_state_id',
|
|
CreateBy => 'create_by',
|
|
ChangeBy => 'change_by',
|
|
);
|
|
|
|
ARRAYPARAM:
|
|
for my $ArrayParam ( sort keys %ArrayParams ) {
|
|
|
|
next ARRAYPARAM if !$Param{$ArrayParam};
|
|
|
|
if ( ref $Param{$ArrayParam} ne 'ARRAY' ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "$ArrayParam must be an array reference!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
next ARRAYPARAM if !@{ $Param{$ArrayParam} };
|
|
|
|
# quote as integer
|
|
for my $OneParam ( @{ $Param{$ArrayParam} } ) {
|
|
$OneParam = $Kernel::OM->Get('Kernel::System::DB')->Quote( $OneParam, 'Integer' );
|
|
}
|
|
|
|
# create string
|
|
my $InString = join q{, }, @{ $Param{$ArrayParam} };
|
|
|
|
next ARRAYPARAM if !$InString;
|
|
|
|
push @SQLWhere, "$ArrayParams{ $ArrayParam } IN ($InString)";
|
|
}
|
|
|
|
# set time params
|
|
my %TimeParams = (
|
|
ConfigItemCreateTimeNewerDate => 'create_time >=',
|
|
ConfigItemCreateTimeOlderDate => 'create_time <=',
|
|
ConfigItemChangeTimeNewerDate => 'change_time >=',
|
|
ConfigItemChangeTimeOlderDate => 'change_time <=',
|
|
);
|
|
|
|
TIMEPARAM:
|
|
for my $TimeParam ( sort keys %TimeParams ) {
|
|
|
|
next TIMEPARAM if !$Param{$TimeParam};
|
|
|
|
if ( $Param{$TimeParam} !~ m{ \A \d\d\d\d-\d\d-\d\d \s \d\d:\d\d:\d\d \z }xms ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Invalid date format found!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# quote
|
|
$Param{$TimeParam} = $Kernel::OM->Get('Kernel::System::DB')->Quote( $Param{$TimeParam} );
|
|
|
|
push @SQLWhere, "$TimeParams{ $TimeParam } '$Param{ $TimeParam }'";
|
|
}
|
|
|
|
# create where string
|
|
my $WhereString = @SQLWhere ? ' WHERE ' . join q{ AND }, @SQLWhere : '';
|
|
|
|
# set limit
|
|
if ( $Param{Limit} ) {
|
|
$Param{Limit} = $Kernel::OM->Get('Kernel::System::DB')->Quote( $Param{Limit}, 'Integer' );
|
|
}
|
|
|
|
my $SQL = "SELECT id FROM configitem $WhereString ";
|
|
|
|
# add the ORDER BY clause
|
|
if (@SQLOrderBy) {
|
|
$SQL .= 'ORDER BY ';
|
|
$SQL .= join ', ', @SQLOrderBy;
|
|
$SQL .= ' ';
|
|
}
|
|
|
|
# ask database
|
|
$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => $SQL,
|
|
Limit => $Param{Limit},
|
|
);
|
|
|
|
# fetch the result
|
|
my @ConfigItemList;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
push @ConfigItemList, $Row[0];
|
|
}
|
|
|
|
return \@ConfigItemList;
|
|
}
|
|
|
|
=head2 ConfigItemLookup()
|
|
|
|
This method does a lookup for a config-item. If a config-item id is given,
|
|
it returns the number of the config-item. If a config-item number is given,
|
|
the appropriate id is returned.
|
|
|
|
my $Number = $ConfigItemObject->ConfigItemLookup(
|
|
ConfigItemID => 1234,
|
|
);
|
|
|
|
my $ID = $ConfigItemObject->ConfigItemLookup(
|
|
ConfigItemNumber => 1000001,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub ConfigItemLookup {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my ($Key) = grep { $Param{$_} } qw(ConfigItemID ConfigItemNumber);
|
|
|
|
# check for needed stuff
|
|
if ( !$Key ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need ConfigItemID or ConfigItemNumber!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# if result is cached return that result
|
|
return $Self->{Cache}->{ConfigItemLookup}->{$Key}->{ $Param{$Key} }
|
|
if $Self->{Cache}->{ConfigItemLookup}->{$Key}->{ $Param{$Key} };
|
|
|
|
# set the appropriate SQL statement
|
|
my $SQL = 'SELECT configitem_number FROM configitem WHERE id = ?';
|
|
|
|
if ( $Key eq 'ConfigItemNumber' ) {
|
|
$SQL = 'SELECT id FROM configitem WHERE configitem_number = ?';
|
|
}
|
|
|
|
# fetch the requested value
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => $SQL,
|
|
Bind => [ \$Param{$Key} ],
|
|
Limit => 1,
|
|
);
|
|
|
|
my $Value;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
$Value = $Row[0];
|
|
}
|
|
|
|
$Self->{Cache}->{ConfigItemLookup}->{$Key}->{ $Param{$Key} } = $Value;
|
|
|
|
return $Value;
|
|
}
|
|
|
|
=head2 UniqueNameCheck()
|
|
|
|
This method checks all already existing config items, whether the given name does already exist
|
|
within the same config item class or among all classes, depending on the SysConfig value of
|
|
UniqueCIName::UniquenessCheckScope (Class or Global).
|
|
|
|
This method requires 3 parameters: ConfigItemID, Name and Class
|
|
"ConfigItemID" is the ID of the ConfigItem, which is to be checked for uniqueness
|
|
"Name" is the config item name to be checked for uniqueness
|
|
"ClassID" is the ID of the config item's class
|
|
|
|
All parameters are mandatory.
|
|
|
|
my $DuplicateNames = $ConfigItemObject->UniqueNameCheck(
|
|
ConfigItemID => '73'
|
|
Name => 'PC#005',
|
|
ClassID => '32',
|
|
);
|
|
|
|
The given name is not unique
|
|
my $NameDuplicates = [ 5, 35, 48, ]; # IDs of ConfigItems with the same name
|
|
|
|
The given name is unique
|
|
my $NameDuplicates = [];
|
|
|
|
=cut
|
|
|
|
sub UniqueNameCheck {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check for needed stuff
|
|
for my $Needed (qw(ConfigItemID Name ClassID)) {
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Missing parameter $Needed!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# check ConfigItemID param for valid format
|
|
if (
|
|
!IsInteger( $Param{ConfigItemID} )
|
|
&& ( IsStringWithData( $Param{ConfigItemID} ) && $Param{ConfigItemID} ne 'NEW' )
|
|
)
|
|
{
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "The ConfigItemID parameter needs to be an integer or 'NEW'",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check Name param for valid format
|
|
if ( !IsStringWithData( $Param{Name} ) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "The Name parameter needs to be a string!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check ClassID param for valid format
|
|
if ( !IsInteger( $Param{ClassID} ) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "The ClassID parameter needs to be an integer",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get class list
|
|
my $ClassList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
|
Class => 'ITSM::ConfigItem::Class',
|
|
);
|
|
|
|
# check class list for validity
|
|
if ( !IsHashRefWithData($ClassList) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Unable to retrieve a valid class list!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get the class name from the class list
|
|
my $Class = $ClassList->{ $Param{ClassID} };
|
|
|
|
# check class for validity
|
|
if ( !IsStringWithData($Class) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Unable to determine a config item class using the given ClassID!",
|
|
);
|
|
return;
|
|
}
|
|
elsif ( $Kernel::OM->Get('Kernel::Config')->{Debug} > 0 ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'debug',
|
|
Message => "Resolved ClassID $Param{ClassID} to class $Class",
|
|
);
|
|
}
|
|
|
|
# get the uniqueness scope from SysConfig
|
|
my $Scope = $Kernel::OM->Get('Kernel::Config')->Get('UniqueCIName::UniquenessCheckScope');
|
|
|
|
# check scope for validity
|
|
if ( !IsStringWithData($Scope) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "The configuration of UniqueCIName::UniquenessCheckScope is invalid!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
if ( $Scope ne 'global' && $Scope ne 'class' ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "UniqueCIName::UniquenessCheckScope is $Scope, but must be either "
|
|
. "'global' or 'class'!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
if ( $Kernel::OM->Get('Kernel::Config')->{Debug} > 0 ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'debug',
|
|
Message => "The scope for checking the uniqueness is $Scope",
|
|
);
|
|
}
|
|
|
|
my %SearchCriteria;
|
|
|
|
# add the config item class to the search criteria if the uniqueness scope is not global
|
|
if ( $Scope ne 'global' ) {
|
|
$SearchCriteria{ClassIDs} = [ $Param{ClassID} ];
|
|
}
|
|
|
|
$SearchCriteria{Name} = $Param{Name};
|
|
|
|
# search for a config item matching the given name
|
|
my $ConfigItem = $Self->ConfigItemSearchExtended(%SearchCriteria);
|
|
|
|
# remove the provided ConfigItemID from the results, otherwise the duplicate check would fail
|
|
# because the ConfigItem itself is found as duplicate
|
|
my @Duplicates = map {$_} grep { $_ ne $Param{ConfigItemID} } @{$ConfigItem};
|
|
|
|
# if a config item was found, the given name is not unique
|
|
# if no config item was found, the given name is unique
|
|
|
|
# return the result of the config item search for duplicates
|
|
return \@Duplicates;
|
|
}
|
|
|
|
=head2 CurInciStateRecalc()
|
|
|
|
recalculates the current incident state of this config item and all linked config items
|
|
|
|
my $Success = $ConfigItemObject->CurInciStateRecalc(
|
|
ConfigItemID => 123,
|
|
NewConfigItemIncidentState => $NewConfigItemIncidentState, # optional, incident states of already checked CIs
|
|
ScannedConfigItemIDs => $ScannedConfigItemIDs, # optional, IDs of already checked CIs
|
|
);
|
|
|
|
=cut
|
|
|
|
sub CurInciStateRecalc {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{ConfigItemID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need ConfigItemID!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get incident link types and directions from config
|
|
my $IncidentLinkTypeDirection = $Kernel::OM->Get('Kernel::Config')->Get('ITSM::Core::IncidentLinkTypeDirection');
|
|
|
|
# to store the new incident state for CIs
|
|
# calculated from all incident link types
|
|
# Incorporate data from previous run(s) and remember known data.
|
|
$Param{NewConfigItemIncidentState} //= {};
|
|
my $KnownNewConfigItemIncidentState = Storable::dclone( $Param{NewConfigItemIncidentState} );
|
|
|
|
# to store the relation between services and linked CIs
|
|
my %ServiceCIRelation;
|
|
|
|
# remember the scanned config items
|
|
# Incorporate data from previous run(s) and remember known data.
|
|
$Param{ScannedConfigItemIDs} //= {};
|
|
my $KnownScannedConfigItemIDs = Storable::dclone( $Param{ScannedConfigItemIDs} );
|
|
|
|
# find all config items with an incident state
|
|
$Self->_FindInciConfigItems(
|
|
ConfigItemID => $Param{ConfigItemID},
|
|
IncidentLinkTypeDirection => $IncidentLinkTypeDirection,
|
|
ScannedConfigItemIDs => $Param{ScannedConfigItemIDs},
|
|
);
|
|
|
|
# calculate the new CI incident state for each configured linktype
|
|
LINKTYPE:
|
|
for my $LinkType ( sort keys %{$IncidentLinkTypeDirection} ) {
|
|
|
|
# get the direction
|
|
my $LinkDirection = $IncidentLinkTypeDirection->{$LinkType};
|
|
|
|
# investigate all config items with a warning state
|
|
CONFIGITEMID:
|
|
for my $ConfigItemID ( sort keys %{ $Param{ScannedConfigItemIDs} } ) {
|
|
|
|
# Skip config items known from previous execution(s).
|
|
if (
|
|
IsStringWithData( $KnownScannedConfigItemIDs->{$ConfigItemID}->{Type} )
|
|
&& $KnownScannedConfigItemIDs->{$ConfigItemID}->{Type} eq
|
|
$Param{ScannedConfigItemIDs}->{$ConfigItemID}->{Type}
|
|
)
|
|
{
|
|
next CONFIGITEMID;
|
|
}
|
|
|
|
# investigate only config items with an incident state
|
|
next CONFIGITEMID if $Param{ScannedConfigItemIDs}->{$ConfigItemID}->{Type} ne 'incident';
|
|
|
|
$Self->_FindWarnConfigItems(
|
|
ConfigItemID => $ConfigItemID,
|
|
LinkType => $LinkType,
|
|
Direction => $LinkDirection,
|
|
NumberOfLinkTypes => scalar keys %{$IncidentLinkTypeDirection},
|
|
ScannedConfigItemIDs => $Param{ScannedConfigItemIDs},
|
|
);
|
|
}
|
|
|
|
CONFIGITEMID:
|
|
for my $ConfigItemID ( sort keys %{ $Param{ScannedConfigItemIDs} } ) {
|
|
|
|
# Skip config items known from previous execution(s).
|
|
if (
|
|
IsStringWithData( $KnownScannedConfigItemIDs->{$ConfigItemID}->{Type} )
|
|
&& $KnownScannedConfigItemIDs->{$ConfigItemID}->{Type} eq
|
|
$Param{ScannedConfigItemIDs}->{$ConfigItemID}->{Type}
|
|
)
|
|
{
|
|
next CONFIGITEMID;
|
|
}
|
|
|
|
# extract incident state type
|
|
my $InciStateType = $Param{ScannedConfigItemIDs}->{$ConfigItemID}->{Type};
|
|
|
|
# find all linked services of this CI
|
|
my %LinkedServiceIDs = $Kernel::OM->Get('Kernel::System::LinkObject')->LinkKeyList(
|
|
Object1 => 'ITSMConfigItem',
|
|
Key1 => $ConfigItemID,
|
|
Object2 => 'Service',
|
|
State => 'Valid',
|
|
Type => $LinkType,
|
|
Direction => $LinkDirection,
|
|
UserID => 1,
|
|
);
|
|
|
|
SERVICEID:
|
|
for my $ServiceID ( sort keys %LinkedServiceIDs ) {
|
|
|
|
# remember the CIs that are linked with this service
|
|
push @{ $ServiceCIRelation{$ServiceID} }, $ConfigItemID;
|
|
}
|
|
|
|
next CONFIGITEMID if $InciStateType eq 'incident';
|
|
|
|
$Param{NewConfigItemIncidentState}->{$ConfigItemID} = $InciStateType;
|
|
}
|
|
}
|
|
|
|
# get the incident state list of warnings
|
|
my $WarnStateList = $Kernel::OM->Get('Kernel::System::GeneralCatalog')->ItemList(
|
|
Class => 'ITSM::Core::IncidentState',
|
|
Preferences => {
|
|
Functionality => 'warning',
|
|
},
|
|
);
|
|
|
|
if ( !defined $WarnStateList ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "ITSM::Core::IncidentState Warning cannot be invalid.",
|
|
);
|
|
}
|
|
|
|
my %ReverseWarnStateList = reverse %{$WarnStateList};
|
|
my @SortedWarnList = sort keys %ReverseWarnStateList;
|
|
my $WarningStateID = $ReverseWarnStateList{Warning} || $ReverseWarnStateList{ $SortedWarnList[0] };
|
|
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
|
|
|
|
# set the new current incident state for CIs
|
|
CONFIGITEMID:
|
|
for my $ConfigItemID ( sort keys %{ $Param{NewConfigItemIncidentState} } ) {
|
|
|
|
# Skip config items known from previous execution(s).
|
|
if (
|
|
IsStringWithData( $KnownNewConfigItemIncidentState->{$ConfigItemID} )
|
|
&& $KnownNewConfigItemIncidentState->{$ConfigItemID} eq $Param{NewConfigItemIncidentState}->{$ConfigItemID}
|
|
)
|
|
{
|
|
next CONFIGITEMID;
|
|
}
|
|
|
|
# get new incident state type (can only be 'operational' or 'warning')
|
|
my $InciStateType = $Param{NewConfigItemIncidentState}->{$ConfigItemID};
|
|
|
|
# get last version
|
|
my $LastVersion = $Self->VersionGet(
|
|
ConfigItemID => $ConfigItemID,
|
|
XMLDataGet => 0,
|
|
);
|
|
|
|
my $CurInciStateID;
|
|
if ( $InciStateType eq 'warning' ) {
|
|
|
|
# check the current incident state type is in 'incident'
|
|
# then we do not want to change it to warning
|
|
next CONFIGITEMID if $LastVersion->{InciStateType} eq 'incident';
|
|
|
|
$CurInciStateID = $WarningStateID;
|
|
}
|
|
elsif ( $InciStateType eq 'operational' ) {
|
|
$CurInciStateID = $LastVersion->{InciStateID};
|
|
}
|
|
|
|
# No update necessary if incident state id of version and config item match.
|
|
next CONFIGITEMID if $LastVersion->{CurInciStateID} eq $CurInciStateID;
|
|
|
|
# update current incident state
|
|
$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'UPDATE configitem SET cur_inci_state_id = ? WHERE id = ?',
|
|
Bind => [ \$CurInciStateID, \$ConfigItemID ],
|
|
);
|
|
|
|
# delete the cache
|
|
my $CacheKey = 'ConfigItemGet::ConfigItemID::' . $ConfigItemID;
|
|
$CacheObject->Delete(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey,
|
|
);
|
|
|
|
# delete affected caches for ConfigItemID
|
|
$CacheKey = 'VersionGet::ConfigItemID::' . $ConfigItemID . '::XMLData::';
|
|
for my $XMLData (qw(0 1)) {
|
|
$CacheObject->Delete(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey . $XMLData,
|
|
);
|
|
}
|
|
$CacheObject->Delete(
|
|
Type => $Self->{CacheType},
|
|
Key => 'VersionNameGet::ConfigItemID::' . $ConfigItemID,
|
|
);
|
|
|
|
# delete affected caches for last version
|
|
my $VersionList = $Self->VersionList(
|
|
ConfigItemID => $ConfigItemID,
|
|
);
|
|
my $VersionID = $VersionList->[-1];
|
|
$CacheKey = 'VersionGet::VersionID::' . $VersionID . '::XMLData::';
|
|
for my $XMLData (qw(0 1)) {
|
|
$CacheObject->Delete(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey . $XMLData,
|
|
);
|
|
}
|
|
$CacheObject->Delete(
|
|
Type => $Self->{CacheType},
|
|
Key => 'VersionNameGet::VersionID::' . $VersionID,
|
|
);
|
|
}
|
|
|
|
# set the current incident state type for each service (influenced by linked CIs)
|
|
SERVICEID:
|
|
for my $ServiceID ( sort keys %ServiceCIRelation ) {
|
|
|
|
# set default incident state type
|
|
my $CurInciStateTypeFromCIs = 'operational';
|
|
|
|
# get the unique config item ids which are direcly linked to this service
|
|
my %UniqueConfigItemIDs = map { $_ => 1 } @{ $ServiceCIRelation{$ServiceID} };
|
|
|
|
# investigate the current incident state of each config item
|
|
CONFIGITEMID:
|
|
for my $ConfigItemID ( sort keys %UniqueConfigItemIDs ) {
|
|
|
|
# get config item data
|
|
my $ConfigItemData = $Self->ConfigItemGet(
|
|
ConfigItemID => $ConfigItemID,
|
|
Cache => 0,
|
|
);
|
|
|
|
next CONFIGITEMID if $ConfigItemData->{CurDeplStateType} ne 'productive';
|
|
next CONFIGITEMID if $ConfigItemData->{CurInciStateType} eq 'operational';
|
|
|
|
# check if service must be set to 'warning'
|
|
if ( $ConfigItemData->{CurInciStateType} eq 'warning' ) {
|
|
$CurInciStateTypeFromCIs = 'warning';
|
|
next CONFIGITEMID;
|
|
}
|
|
|
|
# check if service must be set to 'incident'
|
|
if ( $ConfigItemData->{CurInciStateType} eq 'incident' ) {
|
|
$CurInciStateTypeFromCIs = 'incident';
|
|
last CONFIGITEMID;
|
|
}
|
|
}
|
|
|
|
# update the current incident state type from CIs of the service
|
|
$Kernel::OM->Get('Kernel::System::Service')->ServicePreferencesSet(
|
|
ServiceID => $ServiceID,
|
|
Key => 'CurInciStateTypeFromCIs',
|
|
Value => $CurInciStateTypeFromCIs,
|
|
UserID => 1,
|
|
);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head1 INTERNAL INTERFACE
|
|
|
|
=head2 _FindInciConfigItems()
|
|
|
|
find all config items with an incident state
|
|
|
|
$ConfigItemObject->_FindInciConfigItems(
|
|
ConfigItemID => $ConfigItemID,
|
|
IncidentLinkTypeDirection => $IncidentLinkTypeDirection,
|
|
ScannedConfigItemIDs => \%ScannedConfigItemIDs,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub _FindInciConfigItems {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
return if !$Param{ConfigItemID};
|
|
|
|
# ignore already scanned ids (infinite loop protection)
|
|
return if $Param{ScannedConfigItemIDs}->{ $Param{ConfigItemID} };
|
|
|
|
$Param{ScannedConfigItemIDs}->{ $Param{ConfigItemID} }->{Type} = 'operational';
|
|
|
|
# add own config item id to list of linked config items
|
|
my %ConfigItemIDs = (
|
|
$Param{ConfigItemID} => 1,
|
|
);
|
|
|
|
LINKTYPE:
|
|
for my $LinkType ( sort keys %{ $Param{IncidentLinkTypeDirection} } ) {
|
|
|
|
# find all linked config items (childs)
|
|
my %LinkedConfigItemIDs = $Kernel::OM->Get('Kernel::System::LinkObject')->LinkKeyList(
|
|
Object1 => 'ITSMConfigItem',
|
|
Key1 => $Param{ConfigItemID},
|
|
Object2 => 'ITSMConfigItem',
|
|
State => 'Valid',
|
|
Type => $LinkType,
|
|
|
|
# Direction must ALWAYS be 'Both' here as we need to include
|
|
# all linked CIs that could influence this one!
|
|
Direction => 'Both',
|
|
|
|
UserID => 1,
|
|
);
|
|
|
|
# remember the config item ids
|
|
%ConfigItemIDs = ( %ConfigItemIDs, %LinkedConfigItemIDs );
|
|
}
|
|
|
|
CONFIGITEMID:
|
|
for my $ConfigItemID ( sort keys %ConfigItemIDs ) {
|
|
|
|
# get config item data
|
|
my $ConfigItem = $Self->ConfigItemGet(
|
|
ConfigItemID => $ConfigItemID,
|
|
Cache => 0,
|
|
);
|
|
|
|
# set incident state
|
|
if ( $ConfigItem->{CurInciStateType} eq 'incident' ) {
|
|
$Param{ScannedConfigItemIDs}->{$ConfigItemID}->{Type} = 'incident';
|
|
next CONFIGITEMID;
|
|
}
|
|
|
|
# start recursion
|
|
$Self->_FindInciConfigItems(
|
|
ConfigItemID => $ConfigItemID,
|
|
IncidentLinkTypeDirection => $Param{IncidentLinkTypeDirection},
|
|
ScannedConfigItemIDs => $Param{ScannedConfigItemIDs},
|
|
);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 _FindWarnConfigItems()
|
|
|
|
find all config items with a warning
|
|
|
|
$ConfigItemObject->_FindWarnConfigItems(
|
|
ConfigItemID => $ConfigItemID,
|
|
LinkType => $LinkType,
|
|
Direction => $LinkDirection,
|
|
NumberOfLinkTypes => 2,
|
|
ScannedConfigItemIDs => $ScannedConfigItemIDs,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub _FindWarnConfigItems {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
return if !$Param{ConfigItemID};
|
|
|
|
my $IncidentCount = 0;
|
|
for my $ConfigItemID ( sort keys %{ $Param{ScannedConfigItemIDs} } ) {
|
|
if (
|
|
$Param{ScannedConfigItemIDs}->{$ConfigItemID}->{Type}
|
|
&& $Param{ScannedConfigItemIDs}->{$ConfigItemID}->{Type} eq 'incident'
|
|
)
|
|
{
|
|
$IncidentCount++;
|
|
}
|
|
}
|
|
|
|
# ignore already scanned ids (infinite loop protection)
|
|
# it is ok that a config item is investigated as many times as there are configured link types * number of incident config iteems
|
|
if (
|
|
$Param{ScannedConfigItemIDs}->{ $Param{ConfigItemID} }->{FindWarn}
|
|
&& $Param{ScannedConfigItemIDs}->{ $Param{ConfigItemID} }->{FindWarn}
|
|
>= ( $Param{NumberOfLinkTypes} * $IncidentCount )
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
# increase the visit counter
|
|
$Param{ScannedConfigItemIDs}->{ $Param{ConfigItemID} }->{FindWarn}++;
|
|
|
|
# find all linked config items
|
|
my %LinkedConfigItemIDs = $Kernel::OM->Get('Kernel::System::LinkObject')->LinkKeyList(
|
|
Object1 => 'ITSMConfigItem',
|
|
Key1 => $Param{ConfigItemID},
|
|
Object2 => 'ITSMConfigItem',
|
|
State => 'Valid',
|
|
Type => $Param{LinkType},
|
|
Direction => $Param{Direction},
|
|
UserID => 1,
|
|
);
|
|
|
|
CONFIGITEMID:
|
|
for my $ConfigItemID ( sort keys %LinkedConfigItemIDs ) {
|
|
|
|
# start recursion
|
|
$Self->_FindWarnConfigItems(
|
|
ConfigItemID => $ConfigItemID,
|
|
LinkType => $Param{LinkType},
|
|
Direction => $Param{Direction},
|
|
NumberOfLinkTypes => $Param{NumberOfLinkTypes},
|
|
ScannedConfigItemIDs => $Param{ScannedConfigItemIDs},
|
|
);
|
|
|
|
next CONFIGITEMID
|
|
if $Param{ScannedConfigItemIDs}->{$ConfigItemID}->{Type}
|
|
&& $Param{ScannedConfigItemIDs}->{$ConfigItemID}->{Type} eq 'incident';
|
|
|
|
# set warning state
|
|
$Param{ScannedConfigItemIDs}->{$ConfigItemID}->{Type} = 'warning';
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 _PrepareLikeString()
|
|
|
|
internal function to prepare like strings
|
|
|
|
$ConfigItemObject->_PrepareLikeString( $StringRef );
|
|
|
|
=cut
|
|
|
|
sub _PrepareLikeString {
|
|
my ( $Self, $Value ) = @_;
|
|
|
|
return if !$Value;
|
|
return if ref $Value ne 'SCALAR';
|
|
|
|
# Quote
|
|
${$Value} = $Kernel::OM->Get('Kernel::System::DB')->Quote( ${$Value}, 'Like' );
|
|
|
|
# replace * with %
|
|
${$Value} =~ s{ \*+ }{%}xmsg;
|
|
|
|
return;
|
|
}
|
|
|
|
1;
|
|
|
|
=head1 ITSM Config Item events:
|
|
|
|
ConfigItemCreate, VersionCreate, DeploymentStateUpdate, IncidentStateUpdate,
|
|
ConfigItemDelete, LinkAdd, LinkDelete, DefinitionUpdate, NameUpdate, ValueUpdate
|
|
DefinitionCreate, VersionDelete
|
|
|
|
=cut
|
|
|
|
=head1 TERMS AND CONDITIONS
|
|
|
|
This software is part of the OTRS project (L<https://otrs.org/>).
|
|
|
|
This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
|
the enclosed file COPYING for license information (GPL). If you
|
|
did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
|
|
|
|
=cut
|