Files
scripts/Perl OTRS/Kernel/Modules/AgentITSMConfigItemEdit.pm
2024-10-14 00:08:40 +02:00

1054 lines
33 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::Modules::AgentITSMConfigItemEdit;
use strict;
use warnings;
## nofilter(TidyAll::Plugin::OTRS::Migrations::OTRS6::SysConfig)
use Kernel::System::VariableCheck qw(:all);
use Kernel::Language qw(Translatable);
our $ObjectManagerDisabled = 1;
sub new {
my ( $Type, %Param ) = @_;
# allocate new hash for object
my $Self = {%Param};
bless( $Self, $Type );
return $Self;
}
sub Run {
my ( $Self, %Param ) = @_;
# my param object
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
# get configitem id and class id
my $ConfigItem = {};
$ConfigItem->{ConfigItemID} = $ParamObject->GetParam( Param => 'ConfigItemID' ) || 0;
$ConfigItem->{ClassID} = $ParamObject->GetParam( Param => 'ClassID' ) || 0;
my $DuplicateID = $ParamObject->GetParam( Param => 'DuplicateID' ) || 0;
my $HasAccess;
# get needed objects
my $ConfigItemObject = $Kernel::OM->Get('Kernel::System::ITSMConfigItem');
my $GeneralCatalogObject = $Kernel::OM->Get('Kernel::System::GeneralCatalog');
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
# get config of frontend module
$Self->{Config} = $ConfigObject->Get("ITSMConfigItem::Frontend::$Self->{Action}");
# get needed data
if ( $ConfigItem->{ConfigItemID} && $ConfigItem->{ConfigItemID} ne 'NEW' ) {
# check access for config item
$HasAccess = $ConfigItemObject->Permission(
Scope => 'Item',
ItemID => $ConfigItem->{ConfigItemID},
UserID => $Self->{UserID},
Type => $Self->{Config}->{Permission},
);
# get config item
$ConfigItem = $ConfigItemObject->ConfigItemGet(
ConfigItemID => $ConfigItem->{ConfigItemID},
);
}
elsif ($DuplicateID) {
# get config item to duplicate
$ConfigItem = $ConfigItemObject->ConfigItemGet(
ConfigItemID => $DuplicateID,
);
# check access for config item
$HasAccess = $ConfigItemObject->Permission(
Scope => 'Item',
ItemID => $ConfigItem->{ConfigItemID},
UserID => $Self->{UserID},
Type => $Self->{Config}->{Permission},
);
# set config item id and number
$ConfigItem->{ConfigItemID} = 'NEW';
$ConfigItem->{Number} = Translatable('New');
}
elsif ( $ConfigItem->{ClassID} ) {
# set config item id and number
$ConfigItem->{ConfigItemID} = 'NEW';
$ConfigItem->{Number} = Translatable('New');
# check access for config item
$HasAccess = $ConfigItemObject->Permission(
Scope => 'Class',
ClassID => $ConfigItem->{ClassID},
UserID => $Self->{UserID},
Type => $Self->{Config}->{Permission},
);
# get class list
my $ClassList = $GeneralCatalogObject->ItemList(
Class => 'ITSM::ConfigItem::Class',
);
$ConfigItem->{Class} = $ClassList->{ $ConfigItem->{ClassID} };
}
else {
return $LayoutObject->ErrorScreen(
Message => Translatable('No ConfigItemID, DuplicateID or ClassID is given!'),
Comment => Translatable('Please contact the administrator.'),
);
}
# if user has no access rights show error page
if ( !$HasAccess ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('No access is given!'),
Comment => Translatable('Please contact the administrator.'),
);
}
# get definition
my $XMLDefinition = $ConfigItemObject->DefinitionGet(
ClassID => $ConfigItem->{ClassID},
);
# abort, if no definition is defined
if ( !$XMLDefinition->{DefinitionID} ) {
return $LayoutObject->ErrorScreen(
Message => $LayoutObject->{LanguageObject}
->Translate( 'No definition was defined for class %s!', $ConfigItem->{Class} ),
Comment => Translatable('Please contact the administrator.'),
);
}
# get upload cache object
my $UploadCacheObject = $Kernel::OM->Get('Kernel::System::Web::UploadCache');
# get form id
$Self->{FormID} = $ParamObject->GetParam( Param => 'FormID' );
# create form id
if ( !$Self->{FormID} ) {
$Self->{FormID} = $UploadCacheObject->FormIDCreate();
}
# when there's no ClassID it means, an existing config item is edited as the ClassID is only
# provided as GET param when creating a new config item
if ( !$ParamObject->GetParam( Param => 'ClassID' ) ) {
# get all attachments meta data
my @ExistingAttachments = $ConfigItemObject->ConfigItemAttachmentList(
ConfigItemID => $ConfigItem->{ConfigItemID},
);
# copy all existing attachments to upload cache
FILENAME:
for my $Filename (@ExistingAttachments) {
# get the existing attachment data
my $AttachmentData = $ConfigItemObject->ConfigItemAttachmentGet(
ConfigItemID => $ConfigItem->{ConfigItemID},
Filename => $Filename,
UserID => $Self->{UserID},
);
# add attachment to the upload cache
$UploadCacheObject->FormIDAddFile(
FormID => $Self->{FormID},
Filename => $AttachmentData->{Filename},
Content => $AttachmentData->{Content},
ContentType => $AttachmentData->{ContentType},
);
}
}
# get submit save
my $SubmitSave = $ParamObject->GetParam( Param => 'SubmitSave' );
# get log object
my $LogObject = $Kernel::OM->Get('Kernel::System::Log');
# get xml data
my $Version = {};
my $NameDuplicates;
my $CINameRegexErrorMessage;
if ( $Self->{Subaction} eq 'VersionSave' ) {
# get the uploaded attachment
my %UploadStuff = $ParamObject->GetUploadAll(
Param => 'FileUpload',
Source => 'string',
);
if (%UploadStuff) {
# add attachment to the upload cache
$UploadCacheObject->FormIDAddFile(
FormID => $Self->{FormID},
%UploadStuff,
);
}
my $AllRequired = 1;
# get general form data
for my $FormParam (qw(Name DeplStateID InciStateID)) {
$Version->{$FormParam} = $ParamObject->GetParam( Param => $FormParam );
if ( !$Version->{$FormParam} ) {
$AllRequired = 0;
}
}
# get xml form data
$Version->{XMLData}->[1]->{Version}->[1] = $Self->_XMLFormGet(
XMLDefinition => $XMLDefinition->{DefinitionRef},
AllRequired => \$AllRequired,
ConfigItemID => $ConfigItem->{ConfigItemID},
);
# check, whether the feature to check for a unique name is enabled
if (
IsStringWithData( $Version->{Name} )
&& $ConfigObject->Get('UniqueCIName::EnableUniquenessCheck')
)
{
if ( $ConfigObject->{Debug} > 0 ) {
$LogObject->Log(
Priority => 'debug',
Message => "Checking for duplicate names (ClassID: $ConfigItem->{ClassID}, "
. "Name: $Version->{Name}, ConfigItemID: $ConfigItem->{ConfigItemID})",
);
}
$NameDuplicates = $ConfigItemObject->UniqueNameCheck(
ConfigItemID => $ConfigItem->{ConfigItemID},
ClassID => $ConfigItem->{ClassID},
Name => $Version->{Name},
);
# stop processing if the name is not unique
if ( IsArrayRefWithData($NameDuplicates) ) {
$AllRequired = 0;
# build a string of all duplicate IDs
my $NameDuplicatesString = join ', ', @{$NameDuplicates};
$LogObject->Log(
Priority => 'error',
Message =>
"The name $Version->{Name} is already in use by the ConfigItemID(s): "
. $NameDuplicatesString,
);
}
}
# get the config option for the name regex checks
my $CINameRegexConfig = $ConfigObject->Get("ITSMConfigItem::CINameRegex");
# check if the CI name is given and should be checked with a regular expression
if ( IsStringWithData( $Version->{Name} ) && $CINameRegexConfig ) {
# get class list
my $ClassList = $GeneralCatalogObject->ItemList(
Class => 'ITSM::ConfigItem::Class',
);
# get the class name
my $ClassName = $ClassList->{ $ConfigItem->{ClassID} } || '';
# get the regex for this class
my $CINameRegex = $CINameRegexConfig->{ $ClassName . '::' . 'CINameRegex' } || '';
# if a regex is defined and the CI name does not match the regular expression
if ( $CINameRegex && $Version->{Name} !~ m{ $CINameRegex }xms ) {
$AllRequired = 0;
# get the error message for this class
$CINameRegexErrorMessage = $CINameRegexConfig->{ $ClassName . '::' . 'CINameRegexErrorMessage' } || '';
}
}
# save version to database
if ( $SubmitSave && $AllRequired ) {
if ( $ConfigItem->{ConfigItemID} eq 'NEW' ) {
$ConfigItem->{ConfigItemID} = $ConfigItemObject->ConfigItemAdd(
ClassID => $ConfigItem->{ClassID},
UserID => $Self->{UserID},
);
}
# get all attachments from upload cache
my @Attachments = $UploadCacheObject->FormIDGetAllFilesData(
FormID => $Self->{FormID},
);
# build a lookup lookup hash of the new attachments
my %NewAttachment;
for my $Attachment (@Attachments) {
# the key is the filename + filesize + content type
my $Key = $Attachment->{Filename}
. $Attachment->{Filesize}
. $Attachment->{ContentType};
# store all of the new attachment data
$NewAttachment{$Key} = $Attachment;
}
# get all attachments meta data
my @ExistingAttachments = $ConfigItemObject->ConfigItemAttachmentList(
ConfigItemID => $ConfigItem->{ConfigItemID},
);
# check the existing attachments
FILENAME:
for my $Filename (@ExistingAttachments) {
# get the existing attachment data
my $AttachmentData = $ConfigItemObject->ConfigItemAttachmentGet(
ConfigItemID => $ConfigItem->{ConfigItemID},
Filename => $Filename,
UserID => $Self->{UserID},
);
# the key is the filename + filesize + content type
# (no content id, as existing attachments don't have it)
my $Key = $AttachmentData->{Filename}
. $AttachmentData->{Filesize}
. $AttachmentData->{ContentType};
# attachment is already existing, we can delete it from the new attachment hash
if ( $NewAttachment{$Key} ) {
delete $NewAttachment{$Key};
}
# existing attachment is no longer in new attachments hash
else {
# delete the existing attachment
my $DeleteSuccessful = $ConfigItemObject->ConfigItemAttachmentDelete(
ConfigItemID => $ConfigItem->{ConfigItemID},
Filename => $Filename,
UserID => $Self->{UserID},
);
# check error
if ( !$DeleteSuccessful ) {
return $LayoutObject->FatalError();
}
}
}
# write the new attachments
ATTACHMENT:
for my $Attachment ( values %NewAttachment ) {
# add attachment
my $Success = $ConfigItemObject->ConfigItemAttachmentAdd(
%{$Attachment},
ConfigItemID => $ConfigItem->{ConfigItemID},
UserID => $Self->{UserID},
);
# check error
if ( !$Success ) {
return $LayoutObject->FatalError();
}
}
# add version
$ConfigItemObject->VersionAdd(
%{$Version},
ConfigItemID => $ConfigItem->{ConfigItemID},
DefinitionID => $XMLDefinition->{DefinitionID},
UserID => $Self->{UserID},
);
# redirect to zoom mask
my $ScreenType = $ParamObject->GetParam( Param => 'ScreenType' ) || 0;
if ($ScreenType) {
my $URL = "Action=AgentITSMConfigItemZoom;ConfigItemID=$ConfigItem->{ConfigItemID}";
# return to overview or search results instead if called Duplicate from row action
if (
$Self->{LastScreenView} eq 'Action=AgentITSMConfigItem'
|| $Self->{LastScreenView} =~ m{\A Action=AgentITSMConfigItem(?: Search)?;}msx
)
{
$URL = $Self->{LastScreenView};
}
return $LayoutObject->PopupClose(
URL => $URL,
);
}
else {
return $LayoutObject->Redirect(
OP => "Action=AgentITSMConfigItemZoom;ConfigItemID=$ConfigItem->{ConfigItemID}",
);
}
}
}
elsif ($DuplicateID) {
my $VersionID = $ParamObject->GetParam( Param => 'VersionID' );
if ($VersionID) {
# get version data to duplicate config item
$Version = $ConfigItemObject->VersionGet(
VersionID => $VersionID,
);
}
else {
# get last version data to duplicate config item
$Version = $ConfigItemObject->VersionGet(
ConfigItemID => $DuplicateID,
);
}
}
elsif ( $ConfigItem->{ConfigItemID} ne 'NEW' ) {
# get last version data
$Version = $ConfigItemObject->VersionGet(
ConfigItemID => $ConfigItem->{ConfigItemID},
);
}
my %XMLFormOutputParam;
if ( $Version->{XMLData}->[1]->{Version}->[1] ) {
$XMLFormOutputParam{XMLData} = $Version->{XMLData}->[1]->{Version}->[1];
}
# output name invalid block
my $RowNameInvalid = '';
if ( !$Version->{Name} && $Self->{Subaction} eq 'VersionSave' && $SubmitSave ) {
$RowNameInvalid = 'ServerError';
}
# check for name duplicates
if ( IsArrayRefWithData($NameDuplicates) ) {
$RowNameInvalid = 'ServerError';
}
# check for not matched name regex
if ($CINameRegexErrorMessage) {
$RowNameInvalid = 'ServerError';
}
# output name block
$LayoutObject->Block(
Name => 'RowName',
Data => {
%{$Version},
RowNameInvalid => $RowNameInvalid,
},
);
if (
IsStringWithData($RowNameInvalid)
&& !IsArrayRefWithData($NameDuplicates)
&& !$CINameRegexErrorMessage
)
{
if ( $ConfigObject->{Debug} > 0 ) {
$LogObject->Log(
Priority => 'debug',
Message => "Rendering default error block",
);
}
$LayoutObject->Block(
Name => 'RowNameErrorDefault',
);
}
elsif ( IsArrayRefWithData($NameDuplicates) ) {
# build array with CI-Numbers
my @NameDuplicatesByCINumber;
for my $ConfigItemID ( @{$NameDuplicates} ) {
# lookup the CI number
my $CINumber = $ConfigItemObject->ConfigItemLookup(
ConfigItemID => $ConfigItemID,
);
push @NameDuplicatesByCINumber, $CINumber;
}
my $DuplicateString = join ', ', @NameDuplicatesByCINumber;
if ( $ConfigObject->{Debug} > 0 ) {
$LogObject->Log(
Priority => 'debug',
Message =>
"Rendering block for duplicates (CI-Numbers: $DuplicateString) error message",
);
}
$LayoutObject->Block(
Name => 'RowNameErrorDuplicates',
Data => {
Duplicates => $DuplicateString,
},
);
}
elsif ($CINameRegexErrorMessage) {
$LayoutObject->Block(
Name => 'RowNameErrorRegEx',
Data => {
RegExErrorMessage => $CINameRegexErrorMessage,
},
);
}
# get deployment state list
my $DeplStateList = $GeneralCatalogObject->ItemList(
Class => 'ITSM::ConfigItem::DeploymentState',
);
# output deployment state invalid block
my $RowDeplStateInvalid = '';
if ( !$Version->{DeplStateID} && $Self->{Subaction} eq 'VersionSave' && $SubmitSave ) {
$RowDeplStateInvalid = ' ServerError';
}
# generate DeplStateOptionStrg
my $DeplStateOptionStrg = $LayoutObject->BuildSelection(
Data => $DeplStateList,
Name => 'DeplStateID',
PossibleNone => 1,
Class => 'Validate_Required Modernize' . $RowDeplStateInvalid,
SelectedID => $Version->{DeplStateID},
);
# output deployment state block
$LayoutObject->Block(
Name => 'RowDeplState',
Data => {
DeplStateOptionStrg => $DeplStateOptionStrg,
},
);
# get incident state list
my $InciStateList = $GeneralCatalogObject->ItemList(
Class => 'ITSM::Core::IncidentState',
Preferences => {
Functionality => [ 'operational', 'incident' ],
},
);
# output incident state invalid block
my $RowInciStateInvalid = '';
if ( !$Version->{InciStateID} && $Self->{Subaction} eq 'VersionSave' && $SubmitSave ) {
$RowInciStateInvalid = ' ServerError';
}
# generate InciStateOptionStrg
my $InciStateOptionStrg = $LayoutObject->BuildSelection(
Data => $InciStateList,
Name => 'InciStateID',
PossibleNone => 1,
Class => 'Validate_Required Modernize' . $RowInciStateInvalid,
SelectedID => $Version->{InciStateID},
);
# output incident state block
$LayoutObject->Block(
Name => 'RowInciState',
Data => {
InciStateOptionStrg => $InciStateOptionStrg,
},
);
# output xml form
if ( $XMLDefinition->{Definition} ) {
$Self->{CustomerSearchItemIDs} = [];
$Self->_XMLFormOutput(
XMLDefinition => $XMLDefinition->{DefinitionRef},
%XMLFormOutputParam,
);
}
# get all attachments meta data
$Param{AttachmentList} = [
$UploadCacheObject->FormIDGetAllFilesMeta(
FormID => $Self->{FormID},
)
];
my $Output = '';
if ( ( $ConfigItem->{ConfigItemID} && $ConfigItem->{ConfigItemID} ne 'NEW' ) || $DuplicateID ) {
# output block
$LayoutObject->Block(
Name => 'StartSmall',
Data => {
%Param,
%{$ConfigItem},
},
);
$LayoutObject->Block( Name => 'EndSmall' );
# output header
$Output .= $LayoutObject->Header(
Title => Translatable('Edit'),
Type => 'Small',
);
# start template output
$Output .= $LayoutObject->Output(
TemplateFile => 'AgentITSMConfigItemEdit',
Data => {
%Param,
%{$ConfigItem},
DuplicateID => $DuplicateID,
FormID => $Self->{FormID},
},
);
$Output .= $LayoutObject->Footer( Type => 'Small' );
}
else {
# Necessary stuff for Add New
# get class list
my $ClassList = $GeneralCatalogObject->ItemList(
Class => 'ITSM::ConfigItem::Class',
);
# check for access rights
for my $ClassID ( sort keys %{$ClassList} ) {
my $HasAccess = $ConfigItemObject->Permission(
Type => $Self->{Config}->{Permission},
Scope => 'Class',
ClassID => $ClassID,
UserID => $Self->{UserID},
);
delete $ClassList->{$ClassID} if !$HasAccess;
}
# generate ClassOptionStrg
my $ClassOptionStrg = $LayoutObject->BuildSelection(
Data => $ClassList,
Name => 'ClassID',
PossibleNone => 1,
Translation => 0,
Class => 'W100pc',
SelectedID => $ConfigItem->{ClassID},
);
# End Necessary stuff for Add New
# output block
$LayoutObject->Block(
Name => 'StartNormal',
Data => {
ClassOptionStrg => $ClassOptionStrg,
%Param,
%{$ConfigItem},
},
);
$LayoutObject->Block( Name => 'EndNormal' );
# output header
$Output .= $LayoutObject->Header(
Title => Translatable('Edit'),
);
$Output .= $LayoutObject->NavigationBar();
# start template output
$Output .= $LayoutObject->Output(
TemplateFile => 'AgentITSMConfigItemEdit',
Data => {
%Param,
%{$ConfigItem},
DuplicateID => $DuplicateID,
FormID => $Self->{FormID},
},
);
$Output .= $LayoutObject->Footer();
}
return $Output;
}
sub _XMLFormGet {
my ( $Self, %Param ) = @_;
# check needed stuff
return if !$Param{XMLDefinition};
return if !$Param{AllRequired};
return if ref $Param{XMLDefinition} ne 'ARRAY';
return if ref $Param{AllRequired} ne 'SCALAR';
return if !$Param{ConfigItemID};
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
my $FormData = {};
ITEM:
for my $Item ( @{ $Param{XMLDefinition} } ) {
my $CounterInsert = 1;
COUNTER:
for my $Counter ( 1 .. $Item->{CountMax} ) {
# create inputkey and addkey
my $InputKey = $Item->{Key} . '::' . $Counter;
my $AddKey = $Item->{Key} . '::Add';
if ( $Param{Prefix} ) {
$InputKey = $Param{Prefix} . '::' . $InputKey;
$AddKey = $Param{Prefix} . '::' . $AddKey;
}
# get param
my $FormValues = $LayoutObject->ITSMConfigItemFormDataGet(
Key => $InputKey,
Item => $Item,
ConfigItemID => $Param{ConfigItemID},
);
if ( defined $FormValues->{Value} ) {
# check required value
if ( $FormValues->{Invalid} ) {
${ $Param{AllRequired} } = 0;
}
# check delete button
next COUNTER if $ParamObject->GetParam( Param => $InputKey . '::Delete' );
# start recursion, if "Sub" was found
if ( $Item->{Sub} ) {
my $SubFormData = $Self->_XMLFormGet(
XMLDefinition => $Item->{Sub},
Prefix => $InputKey,
AllRequired => $Param{AllRequired},
ConfigItemID => $Param{ConfigItemID},
);
$FormData->{ $Item->{Key} }->[$CounterInsert] = $SubFormData;
}
$FormData->{ $Item->{Key} }->[$CounterInsert]->{Content} = $FormValues->{Value};
$CounterInsert++;
}
else {
# check add button
if ( $ParamObject->GetParam( Param => $AddKey ) ) {
if ( $Item->{Sub} ) {
$FormData->{ $Item->{Key} }->[$CounterInsert] = $Self->_XMLDefaultSet(
XMLDefinition => $Item->{Sub},
);
}
$FormData->{ $Item->{Key} }->[$CounterInsert]->{Content} = '';
}
last COUNTER;
}
}
}
return $FormData;
}
sub _XMLDefaultSet {
my ( $Self, %Param ) = @_;
# check needed stuff
return if !$Param{XMLDefinition};
return if ref $Param{XMLDefinition} ne 'ARRAY';
my $DefaultData = {};
for my $Item ( @{ $Param{XMLDefinition} } ) {
for my $Counter ( 1 .. $Item->{CountDefault} ) {
# start recursion, if "Sub" was found
if ( $Item->{Sub} ) {
$DefaultData->{ $Item->{Key} }->[$Counter] = $Self->_XMLDefaultSet(
XMLDefinition => $Item->{Sub},
);
}
$DefaultData->{ $Item->{Key} }->[$Counter]->{Content} = '';
}
}
return $DefaultData;
}
sub _XMLFormOutput {
my ( $Self, %Param ) = @_;
# check needed stuff
return if !$Param{XMLDefinition};
return if ref $Param{XMLDefinition} ne 'ARRAY';
$Param{Level} ||= 0;
$Param{Prefix} ||= '';
# get submit save
my $SubmitSave = $Kernel::OM->Get('Kernel::System::Web::Request')->GetParam( Param => 'SubmitSave' );
# set data present mode
my $DataPresentMode = 0;
if ( $Param{XMLData} && ref $Param{XMLData} eq 'HASH' ) {
$DataPresentMode = 1;
}
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $ItemCounter = 1;
ITEM:
for my $Item ( @{ $Param{XMLDefinition} } ) {
# set loop
my $Loop = $Item->{CountDefault};
if ($DataPresentMode) {
$Loop = 0;
# search the last content
COUNTER:
for my $Counter ( 1 .. $Item->{CountMax} ) {
last COUNTER if !defined $Param{XMLData}->{ $Item->{Key} }->[$Counter]->{Content};
$Loop = $Counter;
}
# set absolut minimum
if ( $Loop < $Item->{CountMin} ) {
$Loop = $Item->{CountMin};
}
}
# set delete
my $Delete = 0;
if ( $Loop > $Item->{CountMin} ) {
$Delete = 1;
}
# output content rows
for my $Counter ( 1 .. $Loop ) {
# output row block
$LayoutObject->Block( Name => 'XMLRow' );
if ( !$Param{Level} ) {
$LayoutObject->Block( Name => 'XMLRowFieldsetStart' );
}
# create inputkey and addkey
my $InputKey = $Item->{Key} . '::' . $Counter;
if ( $Param{Prefix} ) {
$InputKey = $Param{Prefix} . '::' . $InputKey;
}
# output blue required star
my $XMLRowValueContentRequired = 0;
my $LabelClass = '';
if ( $Item->{Input}->{Required} ) {
$XMLRowValueContentRequired = 1;
$LabelClass = 'Mandatory';
}
# output red invalid star
my $XMLRowValueContentInvalid = 0;
if ( $Item->{Form}->{$InputKey}->{Invalid} && $SubmitSave ) {
$XMLRowValueContentInvalid = 1;
}
my $ItemID = 'Item' . $ItemCounter++ . $Param{Prefix} . $Param{Level};
if ( $Item->{Input}->{Type} eq 'Customer' ) {
push @{ $Self->{CustomerSearchItemIDs} }, $ItemID;
}
# create input element
my $InputString = $LayoutObject->ITSMConfigItemInputCreate(
Key => $InputKey,
Item => $Item,
Value => $Param{XMLData}->{ $Item->{Key} }->[$Counter]->{Content},
ItemId => $ItemID,
Required => $XMLRowValueContentRequired,
Invalid => $XMLRowValueContentInvalid,
OverrideTimeZone => 1,
);
# ID?
my $LabelFor = $ItemID;
if ( $Item->{Input}->{Type} eq 'Date' || $Item->{Input}->{Type} eq 'DateTime' ) {
$LabelFor = '';
}
# id needed?
if ($LabelFor) {
$LabelFor = 'for="' . $LabelFor . '"';
}
# is this a sub field?
my $Class = '';
if ( $Param{Level} ) {
$Class = 'SubElement';
}
# class needed?
if ($LabelClass) {
$LabelClass = 'class="' . "$Class $LabelClass" . '"';
}
else {
$LabelClass = 'class="' . $Class . '"';
}
# output row value content block
$LayoutObject->Block(
Name => 'XMLRowValue',
Data => {
Name => $Item->{Name},
ItemID => $ItemID,
LabelFor => $LabelFor || '',
Description => $Item->{Description} || $Item->{Name},
InputString => $InputString,
LabelClass => $LabelClass || '',
Class => $Class || '',
},
);
if ( $Item->{Input}->{Required} ) {
$LayoutObject->Block( Name => 'XMLRowValueContentRequired' );
}
# output delete button
if ($Delete) {
$LayoutObject->Block(
Name => 'XMLRowValueContentDelete',
Data => {
InputKey => $InputKey,
},
);
}
# the content is invalid
if ($XMLRowValueContentInvalid) {
# show regex error message block
if ( $Item->{Form}->{$InputKey}->{RegExErrorMessage} ) {
$LayoutObject->Block(
Name => 'XMLRowValueRegExError',
Data => {
ItemID => $ItemID,
RegExErrorMessage => $Item->{Form}->{$InputKey}->{RegExErrorMessage},
},
);
}
# otherwise show normal server error block
else {
$LayoutObject->Block(
Name => 'XMLRowValueServerError',
Data => {
ItemID => $ItemID,
},
);
}
}
# start recursion, if "Sub" was found
if ( $Item->{Sub} ) {
my %XMLFormOutputParam;
if (
$DataPresentMode
&& defined $Param{XMLData}->{ $Item->{Key} }->[$Counter]->{Content}
)
{
$XMLFormOutputParam{XMLData} = $Param{XMLData}->{ $Item->{Key} }->[$Counter];
}
$Self->_XMLFormOutput(
XMLDefinition => $Item->{Sub},
%XMLFormOutputParam,
Level => $Param{Level} + 1,
Prefix => $InputKey,
);
}
if ( !$Param{Level} ) {
$LayoutObject->Block( Name => 'XMLRowFieldsetEnd' );
}
# output row to sort rows correctly
$LayoutObject->Block( Name => 'XMLRow' );
}
# output add button
if ( $Loop < $Item->{CountMax} ) {
# if no item should be shown we need to show the add button
# and therefore we need to show the XMLRow block
if ( !$Loop ) {
$LayoutObject->Block( Name => 'XMLRow' );
}
my $Class = '';
if ( $Param{Level} ) {
$Class = 'class="SubElement"';
}
else {
$LayoutObject->Block( Name => 'XMLRowFieldsetEnd' );
$LayoutObject->Block( Name => 'XMLRowFieldsetStart' );
}
# set prefix
my $InputKey = $Item->{Key};
if ( $Param{Prefix} ) {
$InputKey = $Param{Prefix} . '::' . $InputKey;
}
# output row add content block
$LayoutObject->Block(
Name => 'XMLRowAddContent',
Data => {
ItemID => $InputKey . 'Add',
Name => $Item->{Name},
Description => $Item->{Description} || $Item->{Name},
InputKey => $InputKey,
Class => $Class,
},
);
}
}
if ( IsArrayRefWithData( $Self->{CustomerSearchItemIDs} ) ) {
$LayoutObject->AddJSData(
Key => 'CustomerSearchItemIDs',
Value => $Self->{CustomerSearchItemIDs},
);
}
return 1;
}
1;