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

558 lines
17 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::AgentITSMConfigItemZoom;
use strict;
use warnings;
## nofilter(TidyAll::Plugin::OTRS::Migrations::OTRS6::SysConfig)
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 ) = @_;
# get param object
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
# get params
my $ConfigItemID = $ParamObject->GetParam( Param => 'ConfigItemID' ) || 0;
my $VersionID = $ParamObject->GetParam( Param => 'VersionID' ) || 0;
# get layout object
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
# check needed stuff
if ( !$ConfigItemID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('No ConfigItemID is given!'),
Comment => Translatable('Please contact the administrator.'),
);
}
# get needed object
my $ConfigItemObject = $Kernel::OM->Get('Kernel::System::ITSMConfigItem');
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
# check for access rights
my $HasAccess = $ConfigItemObject->Permission(
Scope => 'Item',
ItemID => $ConfigItemID,
UserID => $Self->{UserID},
Type => $ConfigObject->Get("ITSMConfigItem::Frontend::$Self->{Action}")->{Permission},
);
if ( !$HasAccess ) {
# error page
return $LayoutObject->ErrorScreen(
Message => Translatable('Can\'t show item, no access rights for ConfigItem are given!'),
Comment => Translatable('Please contact the administrator.'),
);
}
# set show versions
$Param{ShowVersions} = 0;
if ( $ParamObject->GetParam( Param => 'ShowVersions' ) ) {
$Param{ShowVersions} = 1;
}
# get content
my $ConfigItem = $ConfigItemObject->ConfigItemGet(
ConfigItemID => $ConfigItemID,
);
if ( !$ConfigItem->{ConfigItemID} ) {
return $LayoutObject->ErrorScreen(
Message =>
$LayoutObject->{LanguageObject}->Translate( 'ConfigItemID %s not found in database!', $ConfigItemID ),
Comment => Translatable('Please contact the administrator.'),
);
}
# get version list
my $VersionList = $ConfigItemObject->VersionZoomList(
ConfigItemID => $ConfigItemID,
);
if ( !$VersionList->[0]->{VersionID} ) {
return $LayoutObject->ErrorScreen(
Message =>
$LayoutObject->{LanguageObject}->Translate( 'No version found for ConfigItemID %s!', $ConfigItemID ),
Comment => Translatable('Please contact the administrator.'),
);
}
# set version id
if ( !$VersionID ) {
$VersionID = $VersionList->[-1]->{VersionID};
}
if ( $VersionID ne $VersionList->[-1]->{VersionID} ) {
$Param{ShowVersions} = 1;
}
# set version id in param hash (only for menu module)
if ($VersionID) {
$Param{VersionID} = $VersionID;
}
# run config item menu modules
if ( ref $ConfigObject->Get('ITSMConfigItem::Frontend::MenuModule') eq 'HASH' ) {
my %Menus = %{ $ConfigObject->Get('ITSMConfigItem::Frontend::MenuModule') };
my $Counter = 0;
for my $Menu ( sort keys %Menus ) {
# load module
if ( $Kernel::OM->Get('Kernel::System::Main')->Require( $Menus{$Menu}->{Module} ) ) {
my $Object = $Menus{$Menu}->{Module}->new(
%{$Self},
ConfigItemID => $Self->{ConfigItemID},
);
# set classes
if ( $Menus{$Menu}->{Target} ) {
if ( $Menus{$Menu}->{Target} eq 'PopUp' ) {
$Menus{$Menu}->{MenuClass} = 'AsPopup';
}
elsif ( $Menus{$Menu}->{Target} eq 'Back' ) {
$Menus{$Menu}->{MenuClass} = 'HistoryBack';
}
}
# run module
$Counter = $Object->Run(
%Param,
ConfigItem => $ConfigItem,
Counter => $Counter,
Config => $Menus{$Menu},
MenuID => $Menu,
);
}
else {
return $LayoutObject->FatalError();
}
}
}
# build version tree
$LayoutObject->Block( Name => 'Tree' );
my $Counter = 1;
if ( !$Param{ShowVersions} && $VersionID eq $VersionList->[-1]->{VersionID} ) {
$Counter = @{$VersionList};
$VersionList = [ $VersionList->[-1] ];
}
# get last version
my $LastVersion = $VersionList->[-1];
# set incident signal
my %InciSignals = (
Translatable('operational') => 'greenled',
Translatable('warning') => 'yellowled',
Translatable('incident') => 'redled',
);
# to store the color for the deployment states
my %DeplSignals;
# get general catalog object
my $GeneralCatalogObject = $Kernel::OM->Get('Kernel::System::GeneralCatalog');
# get list of deployment states
my $DeploymentStatesList = $GeneralCatalogObject->ItemList(
Class => 'ITSM::ConfigItem::DeploymentState',
);
# set deployment style colors
my $StyleClasses = '';
ITEMID:
for my $ItemID ( sort keys %{$DeploymentStatesList} ) {
# get deployment state preferences
my %Preferences = $GeneralCatalogObject->GeneralCatalogPreferencesGet(
ItemID => $ItemID,
);
# check if a color is defined in preferences
next ITEMID if !$Preferences{Color};
# get deployment state
my $DeplState = $DeploymentStatesList->{$ItemID};
# remove any non ascii word characters
$DeplState =~ s{ [^a-zA-Z0-9] }{_}msxg;
# store the original deployment state as key
# and the ss safe coverted deployment state as value
$DeplSignals{ $DeploymentStatesList->{$ItemID} } = $DeplState;
# covert to lower case
my $DeplStateColor = lc $Preferences{Color};
# add to style classes string
$StyleClasses .= "
.Flag span.$DeplState {
background-color: #$DeplStateColor;
}
";
}
# wrap into style tags
if ($StyleClasses) {
$StyleClasses = "<style>$StyleClasses</style>";
}
# output version tree header
if ( $Param{ShowVersions} ) {
$LayoutObject->Block(
Name => 'Collapse',
Data => {
ConfigItemID => $ConfigItemID,
},
);
}
else {
$LayoutObject->Block(
Name => 'Expand',
Data => {
ConfigItemID => $ConfigItemID,
},
);
}
# get user object
my $UserObject = $Kernel::OM->Get('Kernel::System::User');
# output version tree
for my $VersionHash ( @{$VersionList} ) {
$Param{CreateByUserFullName} = $UserObject->UserName(
UserID => $VersionHash->{CreateBy},
);
$LayoutObject->Block(
Name => 'TreeItem',
Data => {
%Param,
%{$ConfigItem},
%{$VersionHash},
Count => $Counter,
InciSignal => $InciSignals{ $VersionHash->{InciStateType} },
DeplSignal => $DeplSignals{ $VersionHash->{DeplState} },
Active => $VersionHash->{VersionID} eq $VersionID ? 'Active' : '',
},
);
$Counter++;
}
# output header
my $Output = $LayoutObject->Header( Value => $ConfigItem->{Number} );
$Output .= $LayoutObject->NavigationBar();
# get version
my $Version = $ConfigItemObject->VersionGet(
VersionID => $VersionID,
);
if (
$Version
&& ref $Version eq 'HASH'
&& $Version->{XMLDefinition}
&& $Version->{XMLData}
&& ref $Version->{XMLDefinition} eq 'ARRAY'
&& ref $Version->{XMLData} eq 'ARRAY'
&& $Version->{XMLData}->[1]
&& ref $Version->{XMLData}->[1] eq 'HASH'
&& $Version->{XMLData}->[1]->{Version}
&& ref $Version->{XMLData}->[1]->{Version} eq 'ARRAY'
)
{
# transform ascii to html
$Version->{Name} = $LayoutObject->Ascii2Html(
Text => $Version->{Name},
HTMLResultMode => 1,
LinkFeature => 1,
);
# output name
$LayoutObject->Block(
Name => 'Data',
Data => {
Name => Translatable('Name'),
Description => Translatable('The name of this config item'),
Value => $Version->{Name},
Identation => 10,
},
);
# output deployment state
$LayoutObject->Block(
Name => 'Data',
Data => {
Name => Translatable('Deployment State'),
Description => Translatable('The deployment state of this config item'),
Value => $LayoutObject->{LanguageObject}->Translate(
$Version->{DeplState},
),
Identation => 10,
},
);
# output incident state
$LayoutObject->Block(
Name => 'Data',
Data => {
Name => Translatable('Incident State'),
Description => Translatable('The incident state of this config item'),
Value => $LayoutObject->{LanguageObject}->Translate(
$Version->{InciState},
),
Identation => 10,
},
);
# start xml output
$Self->_XMLOutput(
XMLDefinition => $Version->{XMLDefinition},
XMLData => $Version->{XMLData}->[1]->{Version}->[1],
);
}
# get create & change user data
for my $Key (qw(Create Change)) {
$ConfigItem->{ $Key . 'ByUserFullName' } = $UserObject->UserName(
UserID => $ConfigItem->{ $Key . 'By' },
);
}
# output meta block
$LayoutObject->Block(
Name => 'Meta',
Data => {
%{$LastVersion},
%{$ConfigItem},
CurInciSignal => $InciSignals{ $LastVersion->{CurInciStateType} },
CurDeplSignal => $DeplSignals{ $LastVersion->{DeplState} },
},
);
# get linked objects
my $LinkListWithData = $Kernel::OM->Get('Kernel::System::LinkObject')->LinkListWithData(
Object => 'ITSMConfigItem',
Key => $ConfigItemID,
State => 'Valid',
UserID => $Self->{UserID},
);
# get link table view mode
my $LinkTableViewMode = $ConfigObject->Get('LinkObject::ViewMode');
# create the link table
my $LinkTableStrg = $LayoutObject->LinkObjectTableCreate(
LinkListWithData => $LinkListWithData,
ViewMode => $LinkTableViewMode,
Object => 'ITSMConfigItem',
Key => $ConfigItemID,
);
# output the link table
if ($LinkTableStrg) {
$LayoutObject->Block(
Name => 'LinkTable' . $LinkTableViewMode,
Data => {
LinkTableStrg => $LinkTableStrg,
},
);
}
my @Attachments = $ConfigItemObject->ConfigItemAttachmentList(
ConfigItemID => $ConfigItemID,
);
if (@Attachments) {
# get the metadata of the 1st attachment
my $FirstAttachment = $ConfigItemObject->ConfigItemAttachmentGet(
ConfigItemID => $ConfigItemID,
Filename => $Attachments[0],
);
$LayoutObject->Block(
Name => 'Attachments',
Data => {
ConfigItemID => $ConfigItemID,
Filename => $FirstAttachment->{Filename},
Filesize => $FirstAttachment->{Filesize},
},
);
# the 1st attachment was directly rendered into the 1st row's right cell, all further
# attachments are rendered into a separate row
ATTACHMENT:
for my $Attachment (@Attachments) {
# skip the 1st attachment
next ATTACHMENT if $Attachment eq $Attachments[0];
# get the metadata of the current attachment
my $AttachmentData = $ConfigItemObject->ConfigItemAttachmentGet(
ConfigItemID => $ConfigItemID,
Filename => $Attachment,
);
$LayoutObject->Block(
Name => 'AttachmentRow',
Data => {
ConfigItemID => $ConfigItemID,
Filename => $AttachmentData->{Filename},
Filesize => $AttachmentData->{Filesize},
},
);
}
}
# handle DownloadAttachment
if ( $Self->{Subaction} eq 'DownloadAttachment' ) {
# get data for attachment
my $Filename = $ParamObject->GetParam( Param => 'Filename' );
my $AttachmentData = $ConfigItemObject->ConfigItemAttachmentGet(
ConfigItemID => $ConfigItemID,
Filename => $Filename,
);
# return error if file does not exist
if ( !$AttachmentData ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Message => "No such attachment ($Filename)!",
Priority => 'error',
);
return $LayoutObject->ErrorScreen();
}
return $LayoutObject->Attachment(
%{$AttachmentData},
Type => 'attachment',
);
}
# store last screen
$Kernel::OM->Get('Kernel::System::AuthSession')->UpdateSessionID(
SessionID => $Self->{SessionID},
Key => 'LastScreenView',
Value => $Self->{RequestedURL},
);
$LayoutObject->AddJSData(
Key => 'UserConfigItemZoomTableHeight',
Value => $Self->{UserConfigItemZoomTableHeight},
);
# start template output
$Output .= $LayoutObject->Output(
TemplateFile => 'AgentITSMConfigItemZoom',
Data => {
%{$LastVersion},
%{$ConfigItem},
CurInciSignal => $InciSignals{ $LastVersion->{CurInciStateType} },
CurDeplSignal => $DeplSignals{ $LastVersion->{DeplState} },
StyleClasses => $StyleClasses,
},
);
# add footer
$Output .= $LayoutObject->Footer();
return $Output;
}
sub _XMLOutput {
my ( $Self, %Param ) = @_;
# check needed stuff
return if !$Param{XMLData};
return if !$Param{XMLDefinition};
return if ref $Param{XMLData} ne 'HASH';
return if ref $Param{XMLDefinition} ne 'ARRAY';
$Param{Level} ||= 0;
ITEM:
for my $Item ( @{ $Param{XMLDefinition} } ) {
COUNTER:
for my $Counter ( 1 .. $Item->{CountMax} ) {
# stop loop, if no content was given
last COUNTER if !defined $Param{XMLData}->{ $Item->{Key} }->[$Counter]->{Content};
# lookup value
my $Value = $Kernel::OM->Get('Kernel::System::ITSMConfigItem')->XMLValueLookup(
Item => $Item,
Value => $Param{XMLData}->{ $Item->{Key} }->[$Counter]->{Content},
);
# get layout object
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
# create output string
$Value = $LayoutObject->ITSMConfigItemOutputStringCreate(
Value => $Value,
Item => $Item,
);
# calculate indentation for left-padding css based on 15px per level and 10px as default
my $Indentation = 10;
if ( $Param{Level} ) {
$Indentation += 15 * $Param{Level};
}
# output data block
$LayoutObject->Block(
Name => 'Data',
Data => {
Name => $Item->{Name},
Description => $Item->{Description} || $Item->{Name},
Value => $Value,
Indentation => $Indentation,
},
);
# start recursion, if "Sub" was found
if ( $Item->{Sub} ) {
$Self->_XMLOutput(
XMLDefinition => $Item->{Sub},
XMLData => $Param{XMLData}->{ $Item->{Key} }->[$Counter],
Level => $Param{Level} + 1,
);
}
}
}
return 1;
}
1;