# -- # 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::GenericInterface::Operation::ConfigItem::ConfigItemSearch; use strict; use warnings; use Kernel::System::VariableCheck qw(:all); use parent qw( Kernel::GenericInterface::Operation::Common Kernel::GenericInterface::Operation::ConfigItem::Common ); our $ObjectManagerDisabled = 1; =head1 NAME Kernel::GenericInterface::Operation::ConfigItem::ConfigItemSearch - GenericInterface ConfigItem ConfigItemSearch Operation backend =head1 PUBLIC INTERFACE =head2 new() usually, you want to create an instance of this by using Kernel::GenericInterface::Operation->new(); =cut sub new { my ( $Type, %Param ) = @_; my $Self = {}; bless( $Self, $Type ); # check needed objects for my $Needed (qw( DebuggerObject WebserviceID )) { if ( !$Param{$Needed} ) { return { Success => 0, ErrorMessage => "Got no $Needed!", }; } $Self->{$Needed} = $Param{$Needed}; } $Self->{OperationName} = 'ConfigItemSearch'; $Self->{Config} = $Kernel::OM->Get('Kernel::Config')->Get('GenericInterface::Operation::ConfigItemSearch'); $Self->{Config}->{DefaultValue} = 'Not Defined'; my $GeneralCatalogObject = $Kernel::OM->Get('Kernel::System::GeneralCatalog'); # get a list of all config item classes $Self->{ClassList} = $GeneralCatalogObject->ItemList( Class => 'ITSM::ConfigItem::Class', ); if ( !IsHashRefWithData( $Self->{ClassList} ) ) { return $Self->{DebuggerObject}->Error( Summary => 'Error when trying to get class listing of ITSM::ConfigItem::Class', ); } # get a list of all incistates $Self->{InciStateList} = $GeneralCatalogObject->ItemList( Class => 'ITSM::Core::IncidentState', ); if ( !IsHashRefWithData( $Self->{InciStateList} ) ) { return $Self->{DebuggerObject}->Error( Summary => 'Error when trying to get incident state listing of' . ' ITSM::Core::IncidentState', ); } # get a list of all deplstates $Self->{DeplStateList} = $GeneralCatalogObject->ItemList( Class => 'ITSM::ConfigItem::DeploymentState', ); if ( !IsHashRefWithData( $Self->{DeplStateList} ) ) { return $Self->{DebuggerObject}->Error( Summary => 'Error when trying to get incident state listing of' . ' ITSM::ConfigItem::DeploymentState', ); } # also provide the classlist in reversed form for easier reverse lookups my %ReverseClassList = reverse %{ $Self->{ClassList} }; $Self->{ReverseClassList} = \%ReverseClassList; # also provide the incistatelist in reversed form for easier reverse lookups my %ReverseInciStateList = reverse %{ $Self->{InciStateList} }; $Self->{ReverseInciStateList} = \%ReverseInciStateList; # also provide the deplstatelist in reversed form for easier reverse lookups my %ReverseDeplStateList = reverse %{ $Self->{DeplStateList} }; $Self->{ReverseDeplStateList} = \%ReverseDeplStateList; return $Self; } =head2 Run() perform ConfigItemCreate Operation. This will return the created config item number. my $Result = $OperationObject->Run( Data => { UserLogin => 'some agent login', # UserLogin or SessionID is SessionID => 123, # required Password => 'some password', # if UserLogin is sent then # Password is required ConfigItem => { Class => 'The ConfigItem Class', # (optional) Number => 'The ConfigItem Number', # (optional) Name => 'The ConfigItem Name', # (optional) DeplStates => ['deployment state'], # (optional) InciStates => ['incident state'], # (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) CIXMLData => $ArrayHashRef, # (optional), it depends on the Configuration # Item class and definition PreviousVersionSearch => 1, # (optional) default 0 (0|1) 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) }, }, ); $Result = { Success => 1, # 0 or 1 ErrorMessage => '', # in case of error Data => { # result data payload after Operation ConfigItemID => [123, 456], # Configuration Item IDs number in OTRS::ITSM (Service desk system) Error => { # should not return errors ErrorCode => 'ConfigItemSearch.ErrorCode' ErrorMessage => 'Error Description' }, }, }; =cut sub Run { my ( $Self, %Param ) = @_; my $Result = $Self->Init( WebserviceID => $Self->{WebserviceID}, ); if ( !$Result->{Success} ) { $Self->ReturnError( ErrorCode => 'Webservice.InvalidConfiguration', ErrorMessage => $Result->{ErrorMessage}, ); } # check needed stuff if ( !$Param{Data}->{UserLogin} && !$Param{Data}->{SessionID} ) { return $Self->ReturnError( ErrorCode => "$Self->{OperationName}.MissingParameter", ErrorMessage => "$Self->{OperationName}: UserLogin or SessionID is required!", ); } if ( $Param{Data}->{UserLogin} ) { if ( !$Param{Data}->{Password} ) { return $Self->ReturnError( ErrorCode => "$Self->{OperationName}.MissingParameter", ErrorMessage => "$Self->{OperationName}: Password or SessionID is required!", ); } } # authenticate user my ( $UserID, $UserType ) = $Self->Auth(%Param); if ( !$UserID ) { return $Self->ReturnError( ErrorCode => "$Self->{OperationName}.AuthFail", ErrorMessage => "$Self->{OperationName}: User could not be authenticated!", ); } # check needed hashes for my $Needed (qw(ConfigItem)) { if ( !IsHashRefWithData( $Param{Data}->{$Needed} ) ) { return $Self->ReturnError( ErrorCode => "$Self->{OperationName}.MissingParameter", ErrorMessage => "$Self->{OperationName}: $Needed parameter is missing or not valid!", ); } } # isolate config item parameter my $ConfigItem = $Param{Data}->{ConfigItem}; # remove leading and trailing spaces for my $Attribute ( sort keys %{$ConfigItem} ) { if ( ref $Attribute ne 'HASH' && ref $Attribute ne 'ARRAY' ) { #remove leading spaces $ConfigItem->{$Attribute} =~ s{\A\s+}{}; #remove trailing spaces $ConfigItem->{$Attribute} =~ s{\s+\z}{}; } } if ( defined $ConfigItem->{CIXMLData} ) { if ( !IsHashRefWithData( $ConfigItem->{CIXMLData} ) ) { return $Self->ReturnError( ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->CIXMLData is invalid!", ); } # remove leading and trailing spaces for CIXMLData $Self->_CleanXMLData( XMLData => $ConfigItem->{CIXMLData} ); } if ( !( $ConfigItem->{Class} ) ) { return $Self->ReturnError( ErrorCode => "$Self->{OperationName}.MissingParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->Class parameter is missing!", ); } # convert search params to arrays if ( defined $ConfigItem->{InciStates} ) { my @InciStates; if ( IsStringWithData( $ConfigItem->{InciStates} ) ) { @InciStates = split( /,/, $ConfigItem->{InciStates} ); } elsif ( IsArrayRefWithData( $ConfigItem->{InciStates} ) ) { @InciStates = @{ $ConfigItem->{InciStates} }; } else { return $Self->ReturnError( ErrorCode => "$Self->{OperationName}.WrongStructure", ErrorMessage => "$Self->{OperationName}: Structure for ConfigItem->InciStates is not correct!", ); } $ConfigItem->{InciStates} = \@InciStates; } if ( defined $ConfigItem->{DeplStates} ) { my @DeplStates; if ( IsStringWithData( $ConfigItem->{DeplStates} ) ) { @DeplStates = split( /,/, $ConfigItem->{DeplStates} ); } elsif ( IsArrayRefWithData( $ConfigItem->{DeplStates} ) ) { @DeplStates = @{ $ConfigItem->{DeplStates} }; } else { return $Self->ReturnError( ErrorCode => "$Self->{OperationName}.WrongStructure", ErrorMessage => "$Self->{OperationName}: Structure for DeplStates is not correct!", ); } $ConfigItem->{DeplStates} = \@DeplStates; } if ( defined $ConfigItem->{OrderBy} ) { my @OrderBy; if ( IsStringWithData( $ConfigItem->{OrderBy} ) ) { @OrderBy = split( /,/, $ConfigItem->{OrderBy} ); } elsif ( IsArrayRefWithData( $ConfigItem->{OrderBy} ) ) { @OrderBy = @{ $ConfigItem->{OrderBy} }; } else { return $Self->ReturnError( ErrorCode => "$Self->{OperationName}.WrongStructure", ErrorMessage => "$Self->{OperationName}: Structure for OrderBy is not correct!", ); } $ConfigItem->{OrderBy} = \@OrderBy; } if ( defined $ConfigItem->{OrderByDirection} ) { my @OrderByDirection; if ( IsStringWithData( $ConfigItem->{OrderByDirection} ) ) { @OrderByDirection = split( /,/, $ConfigItem->{OrderByDirection} ); } elsif ( IsArrayRefWithData( $ConfigItem->{OrderByDirection} ) ) { @OrderByDirection = @{ $ConfigItem->{OrderByDirection} }; } else { return $Self->ReturnError( ErrorCode => "$Self->{OperationName}.WrongStructure", ErrorMessage => "$Self->{OperationName}: Structure for OrderByDirection is not correct!", ); } $ConfigItem->{OrderByDirection} = \@OrderByDirection; } # check ConfigItem attribute values my $ConfigItemCheck = $Self->_CheckConfigItem( ConfigItem => $ConfigItem ); if ( !$ConfigItemCheck->{Success} ) { return $Self->ReturnError( %{$ConfigItemCheck} ); } # check search permissions my $Permission = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->Permission( Scope => 'Class', ClassID => $Self->{ReverseClassList}->{ $ConfigItem->{Class} }, UserID => $UserID, Type => $Self->{Config}->{Permission}, ); if ( !$Permission ) { return $Self->ReturnError( ErrorCode => "$Self->{OperationName}.AccessDenied", ErrorMessage => "$Self->{OperationName}: Can not search configuration items!", ); } return $Self->_ConfigItemSearch( ConfigItem => $ConfigItem, UserID => $UserID, ); } =head1 INTERNAL INTERFACE =head2 _CleanXMLData() removed trailing and leading white spaces in the XMLData. my $XMLDataClean = $OperationObject->_CleanXMLData( Definition => $DefinitionArrayRef, # Config Item Definition ot just part of it XMLData => $XMLDataHashRef, ); returns: $XMLDataClean = { Success => 1, # if everything is OK } $XMLDataClean = { ErrorCode => 'Function.Error', # if error ErrorMessage => 'Error description', } =cut sub _CleanXMLData { my ( $Self, %Param ) = @_; my $XMLData = $Param{XMLData}; KEY: for my $Key ( sort keys %{$XMLData} ) { if ( ref $XMLData->{$Key} eq 'ARRAY' ) { ELEMENT: for my $Element ( @{ $XMLData->{$Key} } ) { if ( ref $Element eq 'HASH' ) { # start recursion $Self->_CleanXMLData( XMLData => $Element ); next ELEMENT; } elsif ( ref $Element eq '' ) { #remove leading spaces $Element =~ s{\A\s+}{}; #remove trailing spaces $Element =~ s{\s+\z}{}; } } } elsif ( ref $XMLData->{$Key} eq 'HASH' ) { # start recursion $Self->_CleanXMLData( XMLData => $XMLData->{$Key} ); next KEY; } elsif ( ref $XMLData->{$Key} eq '' ) { #remove leading spaces $XMLData->{$Key} =~ s{\A\s+}{}; #remove trailing spaces $XMLData->{$Key} =~ s{\s+\z}{}; } } return 1; } =head2 _CheckConfigItem() checks if the given config item parameters are valid. my $ConfigItemCheck = $OperationObject->_CheckConfigItem( ConfigItem => $ConfigItem, # all config item parameters ); returns: $ConfigItemCheck = { Success => 1, # if everything is OK } $ConfigItemCheck = { ErrorCode => 'Function.Error', # if error ErrorMessage => 'Error description', } =cut sub _CheckConfigItem { my ( $Self, %Param ) = @_; my $ConfigItem = $Param{ConfigItem}; # check config item internally # check needed stuff for my $Needed (qw(Class)) { if ( !$ConfigItem->{$Needed} ) { return { ErrorCode => "$Self->{OperationName}.MissingParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->$Needed parameter is missing!", }; } } # check ConfigItem->Class if ( !$Self->ValidateClass( %{$ConfigItem} ) ) { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->Class parameter is invalid!", }; } # check optional stuff if ( IsArrayRefWithData( $ConfigItem->{InciStates} ) ) { for my $InciState ( @{ $ConfigItem->{InciStates} } ) { # check ConfigItem->InciStates if ( !$Self->ValidateInciState( InciState => $InciState ) ) { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->InciStates parameter is invalid!", }; } } } if ( IsArrayRefWithData( $ConfigItem->{DeplStates} ) ) { for my $DeplState ( @{ $ConfigItem->{DeplStates} } ) { # check ConfigItem->InciStates if ( !$Self->ValidateDeplState( DeplState => $DeplState ) ) { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->DeplStates parameter is invalid!", }; } } } for my $TimeParam ( qw(CreateTimeNewerDate CreateTimeOlderDate ChangeTimeNewerDate ChangeTimeOlderDate) ) { if ( defined $ConfigItem->{"ConfigItem$TimeParam"} ) { if ( !$Self->ValidateInputDateTime( Value => $ConfigItem->{"ConfigItem$TimeParam"}, ) ) { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->ConfigItem$TimeParam parameter is invalid!", }; } } } if ( defined $ConfigItem->{Limit} ) { if ( !IsNumber( $ConfigItem->{Limit} ) ) { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->Limit parameter is invalid!", }; } } if ( IsHashRefWithData( $ConfigItem->{CIXMLData} ) ) { # get last config item defintion my $DefinitionData = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->DefinitionGet( ClassID => $Self->{ReverseClassList}->{ $ConfigItem->{Class} }, ); my $XMLDataCheckResult = $Self->_CheckSearchXMLData( Definition => $DefinitionData->{DefinitionRef}, XMLData => $ConfigItem->{CIXMLData}, ); if ( !$XMLDataCheckResult->{Success} ) { return $XMLDataCheckResult; } } # if everything is OK then return Success return { Success => 1, }; } =head2 _ConfigItemSearch() search a configuration items. my $Response = $OperationObject->_ConfigItemSearch( ConfigItem => $ConfigItem, # all configuration item parameters UserID => 123, ); returns: $Response = { Success => 1, # if everething is OK Data => { ConfigItemIDs => [123, 456], } } $Response = { Success => 0, # if unexpected error ErrorMessage => "$Param{ErrorCode}: $Param{ErrorMessage}", } =cut sub _ConfigItemSearch { my ( $Self, %Param ) = @_; my $ConfigItem = $Param{ConfigItem}; my %SearchParams; # set search parameters that does not need any conversion for my $PlainParam ( qw( Name Number PreviousVersionSearch OrderBy OrderByDirection Limit ConfigItemCreateTimeNewerDate ConfigItemCreateTimeOlderDate ConfigItemChangeTimeNewerDate ConfigItemChangeTimeOlderDate ) ) { if ( defined $ConfigItem->{$PlainParam} ) { $SearchParams{$PlainParam} = $ConfigItem->{$PlainParam}; } } # set seach class my $ClassID = $Self->{ReverseClassList}->{ $ConfigItem->{Class} }; $SearchParams{ClassIDs} = [$ClassID]; # set search incident states if ( defined $ConfigItem->{InciStates} ) { my @InciStateIDs; for my $InciState ( @{ $ConfigItem->{InciStates} } ) { my $InciStateID = $Self->{ReverseInciStateList}->{$InciState}; push @InciStateIDs, $InciStateID; } $SearchParams{InciStateIDs} = \@InciStateIDs; } # set search deployment states if ( defined $ConfigItem->{DeplStates} ) { my @DeplStateIDs; for my $DeplState ( @{ $ConfigItem->{DeplStates} } ) { my $DeplStateID = $Self->{ReverseDeplStateList}->{$DeplState}; push @DeplStateIDs, $DeplStateID; } $SearchParams{DeplStateIDs} = \@DeplStateIDs; } my $RawXMLData = $ConfigItem->{CIXMLData}; my $ConfigItemObject = $Kernel::OM->Get('Kernel::System::ITSMConfigItem'); if ( IsHashRefWithData($RawXMLData) ) { # get last config item defintion my $DefinitionData = $ConfigItemObject->DefinitionGet( ClassID => $Self->{ReverseClassList}->{ $ConfigItem->{Class} }, ); # replace date, date time, customer, company and general catalog values my $ReplacedXMLData = $Self->ReplaceXMLData( XMLData => $RawXMLData, Definition => $DefinitionData->{DefinitionRef}, ); # create an XMLData structure suitable for ConfigItemSearch my $XMLData = $Self->_FormatSearchXMLData( XMLData => $ReplacedXMLData, ); if ( IsArrayRefWithData($XMLData) ) { $SearchParams{What} = $XMLData; } } $Self->{DebuggerObject}->Info( Summary => "$Self->{OperationName}: Search Parameters", Data => \%SearchParams, ); my $ConfigItemIDs = $ConfigItemObject->ConfigItemSearchExtended(%SearchParams); if ( IsArrayRefWithData($ConfigItemIDs) ) { return { Success => 1, Data => { ConfigItemIDs => $ConfigItemIDs, }, }; } return { Success => 1, Data => { ConfigItemIDs => '', }, }; } =head2 _CheckSearchXMLData() checks if the given XMLData value are valid. my $XMLDataCheck = $CommonObject->_CheckSearchXMLData( Definition => $DefinitionArrayRef, # Config Item Definition ot just part of it XMLData => $XMLDataHashRef, Parent => 'some parent', ); returns: $XMLDataCheck = { Success => 1, # if everything is OK } $XMLDataCheck = { ErrorCode => 'Function.Error', # if error ErrorMessage => 'Error description', } =cut sub _CheckSearchXMLData { my ( $Self, %Param ) = @_; my $Definition = $Param{Definition}; my $XMLData = $Param{XMLData}; my $Parent = $Param{Parent} || ''; my $CheckValueResult; for my $DefItem ( @{$Definition} ) { my $ItemKey = $DefItem->{Key}; if ( ref $XMLData->{$ItemKey} eq 'ARRAY' ) { for my $ArrayItem ( @{ $XMLData->{$ItemKey} } ) { if ( ref $ArrayItem eq 'HASH' ) { $CheckValueResult = $Self->_CheckValue( Value => $ArrayItem->{$ItemKey}, Input => $DefItem->{Input}, ItemKey => $ItemKey, Parent => $Parent, ); if ( !$CheckValueResult->{Success} ) { return $CheckValueResult; } } elsif ( ref $ArrayItem eq '' ) { $CheckValueResult = $Self->_CheckValue( Value => $ArrayItem, Input => $DefItem->{Input}, ItemKey => $ItemKey, Parent => $Parent, ); if ( !$CheckValueResult->{Success} ) { return $CheckValueResult; } } else { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->CIXMLData->$Parent$ItemKey parameter" . " is invalid!", }; } } } elsif ( ref $XMLData->{$ItemKey} eq 'HASH' ) { if ( $XMLData->{$ItemKey}->{$ItemKey} ) { $CheckValueResult = $Self->_CheckValue( Value => $XMLData->{$ItemKey}->{$ItemKey}, Input => $DefItem->{Input}, ItemKey => $ItemKey, Parent => $Parent, ); if ( !$CheckValueResult->{Success} ) { return $CheckValueResult; } } } else { # only perform checks if item really exits in the XMLData # CountNin checks was verified and passed before!, so it is safe to skip if needed if ( $XMLData->{$ItemKey} ) { $CheckValueResult = $Self->_CheckValue( Value => $XMLData->{$ItemKey}, Input => $DefItem->{Input}, ItemKey => $ItemKey, Parent => $Parent, ); if ( !$CheckValueResult->{Success} ) { return $CheckValueResult; } } } # check if there is a sub and start recursion if ( defined $DefItem->{Sub} ) { if ( ref $XMLData->{$ItemKey} eq 'ARRAY' ) { my $Counter = 0; for my $ArrayItem ( @{ $XMLData->{$ItemKey} } ) { # start recursion for each array item my $XMLDataCheck = $Self->_CheckSearchXMLData( Definition => $DefItem->{Sub}, XMLData => $ArrayItem, Parent => $Parent . $ItemKey . "[$Counter]->", ); if ( !$XMLDataCheck->{Success} ) { return $XMLDataCheck; } $Counter++; } } elsif ( ref $XMLData->{$ItemKey} eq 'HASH' ) { # start recursion my $XMLDataCheck = $Self->_CheckSearchXMLData( Definition => $DefItem->{Sub}, XMLData => $XMLData->{$ItemKey}, Parent => $Parent . $ItemKey . '->', ); if ( !$XMLDataCheck->{Success} ) { return $XMLDataCheck; } } else { # start recusrsion my $XMLDataCheck = $Self->_CheckSearchXMLData( Definition => $DefItem->{Sub}, XMLData => {}, Parent => $Parent . $ItemKey . '->', ); if ( !$XMLDataCheck->{Success} ) { return $XMLDataCheck; } } } } return { Success => 1, }; } =head2 _CheckValue() checks if the given value is valid. my $ValueCheck = $CommonObject->_CheckValue( Value => $Value # $Value could be a string, a time stamp, # general catalog class name, or a integer Input => $InputDefinitionHashRef, # The definition of the element input extracted # from the Configuration Item definition for # for each value ItemKey => 'some key', # The name of the value as sent in the SOAP # request Parent => 'soem parent key->', # The name of the parent followed by -> or empty # for root key items ); returns: $ValueCheck = { Success => 1, # if everything is OK } $ValueCheck = { ErrorCode => 'Function.Error', # if error ErrorMessage => 'Error description', } =cut sub _CheckValue { my ( $Self, %Param ) = @_; my $Parent = $Param{Parent}; my $ItemKey = $Param{ItemKey}; if ( $Param{Input}->{Type} eq 'Text' || $Param{Input}->{Type} eq 'TextArea' ) { # run Text validations if ( !$Self->ValidateInputText(%Param) ) { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->CIXMLData->$Parent$ItemKey parameter value" . " excedes the maxium length!", }; } } elsif ( $Param{Input}->{Type} eq 'Date' ) { # run Date validations if ( !$Self->ValidateInputDate(%Param) ) { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->CIXMLData->$Parent$ItemKey parameter value" . " is not a valid Date format!", }; } } elsif ( $Param{Input}->{Type} eq 'DateTime' ) { # run DateTime validations if ( !$Self->ValidateInputDateTime(%Param) ) { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->CIXMLData->$Parent$ItemKey parameter value" . " is not a valid DateTime format!", }; } } elsif ( $Param{Input}->{Type} eq 'Customer' ) { # run Customer validations if ( !$Self->ValidateInputCustomer(%Param) ) { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->CIXMLData->$Parent$ItemKey parameter value" . " is not a valid customer!", }; } } elsif ( $Param{Input}->{Type} eq 'CustomerCompany' ) { # run CustomerCompany validations if ( !$Self->ValidateInputCustomerCompany(%Param) ) { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->CIXMLData->$Parent$ItemKey parameter value" . " is not a valid customer company!", }; } } elsif ( $Param{Input}->{Type} eq 'Integer' ) { # run Integer validations if ( !$Self->ValidateInputInteger(%Param) ) { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->CIXMLData->$Parent$ItemKey parameter value" . " is not a valid Integer or out of range!", }; } } elsif ( $Param{Input}->{Type} eq 'GeneralCatalog' ) { # run General Catalog validations if ( !$Self->ValidateInputGeneralCatalog(%Param) ) { return { ErrorCode => "$Self->{OperationName}.InvalidParameter", ErrorMessage => "$Self->{OperationName}: ConfigItem->CIXMLData->$Parent$ItemKey parameter value" . " is not a valid for General Catalog '$Param{Input}->{Class}'!", }; } } else { # The type is dummy, do nothing } return { Success => 1, }; } =head2 _FormatSearchXMLData() Create a XMLData suitable for ConfigItemSeach. my $NewXMLData = $OperationObject->_FormatSearchXMLData( XMLData => $XMLDataHashRef, Child => 1, # or 0, optional ); returns: $NewXMLData = $XMLDataHashRef, # suitable for version add =cut sub _FormatSearchXMLData { my ( $Self, %Param ) = @_; my $XMLData = $Param{XMLData}; my $Parent = $Param{Parent} || ''; my $Child = $Param{Child}; my $NewXMLData = $Param{NewXMLData} || {}; for my $RootKey ( sort keys %{$XMLData} ) { if ( ref $XMLData->{$RootKey} eq 'ARRAY' ) { for my $ArrayItem ( @{ $XMLData->{$RootKey} } ) { if ( ref $ArrayItem eq 'HASH' ) { # extract the root key from the hash and assing it to content key my $Content = delete $ArrayItem->{$RootKey}; # start recursion my $NewXMLDataPart = $Self->_FormatSearchXMLData( XMLData => $ArrayItem, Parent => $Parent . $RootKey . '::', Child => 1, ); if ($Content) { push @{ $NewXMLData->{ $Parent . $RootKey } }, $Content; } # assamble the final value from the parts for my $NewKey ( %{$NewXMLDataPart} ) { for my $Item ( @{ $NewXMLDataPart->{$NewKey} } ) { push @{ $NewXMLData->{$NewKey} }, $Item; } } } elsif ( ref $ArrayItem eq '' ) { push @{ $NewXMLData->{ $Parent . $RootKey } }, $ArrayItem; } } } elsif ( ref $XMLData->{$RootKey} eq 'HASH' ) { # extract the root key from the hash and assing it to content key my $Content = delete $XMLData->{$RootKey}->{$RootKey}; # start recursion my $NewXMLDataPart = $Self->_FormatSearchXMLData( XMLData => $XMLData->{$RootKey}, Parent => $Parent . $RootKey . "::", Child => 1, ); if ($Content) { push @{ $NewXMLData->{ $Parent . $RootKey } }, $Content; } # assamble the final value from the part %{$NewXMLData} = ( %{$NewXMLData}, %{$NewXMLDataPart} ); } elsif ( ref $XMLData->{$RootKey} eq '' ) { push @{ $NewXMLData->{ $Parent . $RootKey } }, $XMLData->{$RootKey}; } } # return only the part on recursion if ($Child) { return $NewXMLData; } # return the complete XMLData as needed for ConfigItemSearch my @ReturnStructure; for my $SearchParam ( sort keys %{$NewXMLData} ) { my $SearchKey = $SearchParam; $SearchKey =~ s{ :: }{\'\}[%]\{\'}xmsg; $SearchKey = "[1]{'Version'}[1]{'$SearchKey'}[%]{'Content'}"; push @ReturnStructure, { $SearchKey => $NewXMLData->{$SearchParam}, }; } return \@ReturnStructure; } 1; =head1 TERMS AND CONDITIONS This software is part of the OTRS project (L). 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. =cut