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

1495 lines
51 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::AdminGenericInterfaceWebservice;
use strict;
use warnings;
use Kernel::System::VariableCheck qw(:all);
use Kernel::Language qw(Translatable);
our $ObjectManagerDisabled = 1;
sub new {
my ( $Type, %Param ) = @_;
my $Self = {%Param};
bless( $Self, $Type );
return $Self;
}
sub Run {
my ( $Self, %Param ) = @_;
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
my $WebserviceID = $ParamObject->GetParam( Param => 'WebserviceID' ) || '';
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $WebserviceObject = $Kernel::OM->Get('Kernel::System::GenericInterface::Webservice');
my $YAMLObject = $Kernel::OM->Get('Kernel::System::YAML');
# ------------------------------------------------------------ #
# sub-action Change: load web service and show edit screen
# ------------------------------------------------------------ #
if ( $Self->{Subaction} eq 'Change' ) {
# Check for WebserviceID.
if ( !$WebserviceID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('Need WebserviceID!'),
);
}
# Get web service configuration.
my $WebserviceData = $WebserviceObject->WebserviceGet(
ID => $WebserviceID,
);
# Check for valid web service configuration.
if ( !IsHashRefWithData($WebserviceData) ) {
return $LayoutObject->ErrorScreen(
Message =>
$LayoutObject->{LanguageObject}
->Translate( 'Could not get data for WebserviceID %s', $WebserviceID ),
);
}
return $Self->_ShowEdit(
%Param,
WebserviceID => $WebserviceID,
WebserviceData => $WebserviceData,
Action => 'Change',
);
}
# ------------------------------------------------------------ #
# sub-action ChangeAction: write basic config and return to edit
# screen to continue with the rest of
# the configuration
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'ChangeAction' ) {
# Challenge token check for write action.
$LayoutObject->ChallengeTokenCheck();
# Check for WebserviceID.
if ( !$WebserviceID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('Need WebserviceID!'),
);
}
# Get web service configuration.
my $WebserviceData = $WebserviceObject->WebserviceGet(
ID => $WebserviceID,
);
# Check for valid web service configuration.
if ( !IsHashRefWithData($WebserviceData) ) {
return $LayoutObject->ErrorScreen(
Message =>
$LayoutObject->{LanguageObject}
->Translate( 'Could not get data for WebserviceID %s', $WebserviceID ),
);
}
# Get parameter from web browser.
my $GetParam = $Self->_GetParams();
# Set new configuration.
$WebserviceData->{Name} = $GetParam->{Name};
$WebserviceData->{Config}->{Description} = $GetParam->{Description};
$WebserviceData->{Config}->{RemoteSystem} = $GetParam->{RemoteSystem};
$WebserviceData->{Config}->{Debugger}->{DebugThreshold} = $GetParam->{DebugThreshold};
$WebserviceData->{Config}->{Debugger}->{TestMode} = 0;
$WebserviceData->{ValidID} = $GetParam->{ValidID};
for my $CommunicationType (qw( Provider Requester )) {
# Check if selected type is different from the one on the current configuration.
if (
$WebserviceData->{Config}->{$CommunicationType}->{Transport}->{Type} ne
$GetParam->{ $CommunicationType . 'Transport' }
)
{
# Delete current communication type transport.
delete $WebserviceData->{Config}->{$CommunicationType}->{Transport};
# Replace the current transport type with the new selected one
# the rest of the configuration will be empty
# the transport need to be configured independently.
$WebserviceData->{Config}->{$CommunicationType}->{Transport}->{Type}
= $GetParam->{ $CommunicationType . 'Transport' };
}
}
# Check required parameters.
my %Error;
if ( !$GetParam->{Name} ) {
# Add server error error class.
$Error{NameServerError} = 'ServerError';
$Error{NameServerErrorMessage} = Translatable('This field is required');
}
# Check if name is duplicated.
my %WebserviceList = %{ $WebserviceObject->WebserviceList() };
%WebserviceList = reverse %WebserviceList;
if (
$WebserviceList{ $GetParam->{Name} } &&
$WebserviceList{ $GetParam->{Name} } ne $WebserviceID
)
{
# Add server error error class.
$Error{NameServerError} = 'ServerError';
$Error{NameServerErrorMessage} = Translatable('There is another web service with the same name.');
}
# If there is an error return to edit screen.
if ( IsHashRefWithData( \%Error ) ) {
return $Self->_ShowEdit(
%Error,
%Param,
WebserviceID => $WebserviceID,
WebserviceData => $WebserviceData,
Action => 'Change',
);
}
# Otherwise save configuration and return to overview screen.
my $Success = $WebserviceObject->WebserviceUpdate(
ID => $WebserviceID,
Name => $WebserviceData->{Name},
Config => $WebserviceData->{Config},
ValidID => $WebserviceData->{ValidID},
UserID => $Self->{UserID},
);
# Show error if cant update.
if ( !$Success ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('There was an error updating the web service.'),
);
}
# If the user would like to continue editing the invoker config, just redirect to the edit screen.
my $RedirectURL;
if (
defined $ParamObject->GetParam( Param => 'ContinueAfterSave' )
&& ( $ParamObject->GetParam( Param => 'ContinueAfterSave' ) eq '1' )
)
{
$RedirectURL =
'Action='
. $Self->{Action}
. ';Subaction=Change;WebserviceID='
. $WebserviceID
. ';';
}
else {
# Otherwise return to overview.
$RedirectURL =
'Action=AdminGenericInterfaceWebservice'
. ';';
}
return $LayoutObject->Redirect( OP => $RedirectURL );
}
# ------------------------------------------------------------ #
# sub-action Add: show edit screen (empty)
# ------------------------------------------------------------ #
if ( $Self->{Subaction} eq 'Add' ) {
return $Self->_ShowEdit(
Action => 'Add',
);
}
# ------------------------------------------------------------ #
# sub-action AddAction: create a web service and return to edit
# screen to continue with the rest of
# the configuration
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'AddAction' ) {
# Challenge token check for write action.
$LayoutObject->ChallengeTokenCheck();
# Get web service configuration.
my $WebserviceData;
# Get parameter from web browser.
my $GetParam = $Self->_GetParams();
# Set new configuration.
$WebserviceData->{Name} = $GetParam->{Name};
$WebserviceData->{Config}->{Description} = $GetParam->{Description};
$WebserviceData->{Config}->{RemoteSystem} = $GetParam->{RemoteSystem};
$WebserviceData->{Config}->{Debugger}->{DebugThreshold} = $GetParam->{DebugThreshold};
$WebserviceData->{Config}->{Debugger}->{TestMode} = 0;
$WebserviceData->{ValidID} = $GetParam->{ValidID};
for my $CommunicationType (qw( Provider Requester )) {
$WebserviceData->{Config}->{$CommunicationType}->{Transport}->{Type} =
$GetParam->{ $CommunicationType . 'Transport' };
}
# Check required parameters.
my %Error;
if ( !$GetParam->{Name} ) {
# Add server error error class.
$Error{NameServerError} = 'ServerError';
$Error{NameServerErrorMessage} = Translatable('This field is required');
}
# Check if name is duplicated.
my %WebserviceList = %{ $WebserviceObject->WebserviceList() };
%WebserviceList = reverse %WebserviceList;
if (
$WebserviceList{ $GetParam->{Name} } &&
$WebserviceList{ $GetParam->{Name} } ne $WebserviceID
)
{
# Add server error error class.
$Error{NameServerError} = 'ServerError';
$Error{NameServerErrorMessage} = Translatable('There is another web service with the same name.');
}
# If there is an error return to edit screen.
if ( IsHashRefWithData( \%Error ) ) {
return $Self->_ShowEdit(
%Error,
%Param,
WebserviceID => $WebserviceID,
WebserviceData => $WebserviceData,
Action => 'Add',
);
}
# Otherwise save configuration and return to overview screen.
my $ID = $WebserviceObject->WebserviceAdd(
Name => $WebserviceData->{Name},
Config => $WebserviceData->{Config},
ValidID => $WebserviceData->{ValidID},
UserID => $Self->{UserID},
);
# Show error if cant create.
if ( !$ID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('There was an error creating the web service.'),
);
}
# Set WebserviceID to the new created web service.
$WebserviceID = $ID;
# Define notification.
my $Notify = $LayoutObject->{LanguageObject}->Translate(
'Web service "%s" created!',
$WebserviceData->{Name},
);
# Return to edit to continue changing the configuration.
return $Self->_ShowEdit(
%Param,
Notify => $Notify,
WebserviceID => $WebserviceID,
WebserviceData => $WebserviceData,
Action => 'Change',
);
}
# ------------------------------------------------------------ #
# sub action Export: create a YAML file with the configuration
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'Export' ) {
# Check for WebserviceID.
if ( !$WebserviceID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('Need WebserviceID!'),
);
}
# Get web service configuration.
my $WebserviceData = $WebserviceObject->WebserviceGet(
ID => $WebserviceID
);
# Set Framework Version information for import purposes.
$WebserviceData->{Config}->{FrameworkVersion} = $Kernel::OM->Get('Kernel::Config')->Get('Version');
# Check for valid web service configuration.
if ( !IsHashRefWithData($WebserviceData) ) {
return $LayoutObject->ErrorScreen(
Message =>
$LayoutObject->{LanguageObject}
->Translate( 'Could not get data for WebserviceID %s', $WebserviceID ),
);
}
# Dump configuration into a YAML structure.
my $YAMLContent = $YAMLObject->Dump( Data => $WebserviceData->{Config} );
# Return YAML to download.
my $YAMLFile = $WebserviceData->{Name};
return $LayoutObject->Attachment(
Filename => $YAMLFile . '.yml',
ContentType => "text/plain; charset=" . $LayoutObject->{UserCharset},
Content => $YAMLContent,
);
}
# -------------------------------------------------------------- #
# sub-action Delete: delete web service and return value to dialog
# -------------------------------------------------------------- #
elsif ( $Self->{Subaction} eq 'Delete' ) {
# Challenge token check for write action.
$LayoutObject->ChallengeTokenCheck();
# get web service configuration
my $WebserviceData = $WebserviceObject->WebserviceGet(
ID => $WebserviceID,
);
my $Success = $WebserviceObject->WebserviceDelete(
ID => $WebserviceID,
UserID => $Self->{UserID},
);
# Build JSON output.
my $JSON = $LayoutObject->JSONEncode(
Data => {
Success => $Success,
DeletedWebservice => $WebserviceData->{Name},
},
);
# Send JSON response.
return $LayoutObject->Attachment(
ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
Content => $JSON,
Type => 'inline',
NoCache => 1,
);
}
# -------------------------------------------------------------- #
# sub-action Clone: clone web service and return value to dialog
# -------------------------------------------------------------- #
elsif ( $Self->{Subaction} eq 'Clone' ) {
# Challenge token check for write action.
$LayoutObject->ChallengeTokenCheck();
# Check for WebserviceID.
if ( !$WebserviceID ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('Need WebserviceID!'),
);
}
# Get web service configuration.
my $WebserviceData = $WebserviceObject->WebserviceGet(
ID => $WebserviceID,
);
# Check for valid web service configuration.
if ( !IsHashRefWithData($WebserviceData) ) {
return $LayoutObject->ErrorScreen(
Message => $LayoutObject->{LanguageObject}
->Translate( 'Could not get data for WebserviceID %s', $WebserviceID ),
);
}
my $CloneName = $ParamObject->GetParam( Param => 'CloneName' ) || '';
if ( !$CloneName ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('Need Name!'),
);
}
# Set new configuration.
$WebserviceData->{Name} = $CloneName;
# Check if name is duplicated.
my %WebserviceList = %{ $WebserviceObject->WebserviceList() };
%WebserviceList = reverse %WebserviceList;
if ( $WebserviceList{$CloneName} ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('There is another web service with the same name.'),
);
}
# Otherwise save configuration and return to overview screen.
my $Success = $WebserviceObject->WebserviceAdd(
Name => $WebserviceData->{Name},
Config => $WebserviceData->{Config},
ValidID => $WebserviceData->{ValidID},
UserID => $Self->{UserID},
);
if ( !$Success ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('There was an error creating the web service.'),
);
}
# Define notification.
my $Notify = $LayoutObject->{LanguageObject}->Translate(
'Web service "%s" created!',
$WebserviceData->{Name},
);
# Return to overview.
return $Self->_ShowOverview(
%Param,
Notify => $Notify,
Action => 'Overview',
);
}
# ------------------------------------------------------------ #
# sub-action Import: parse the file and return to overview
# if name errors return to add screen
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'Import' ) {
# Challenge token check for write action.
$LayoutObject->ChallengeTokenCheck();
my $ImportedConfig;
my $Home = $Kernel::OM->Get('Kernel::Config')->Get('Home');
my $MainObject = $Kernel::OM->Get('Kernel::System::Main');
# Get web service name.
my $WebserviceName;
my $ExampleWebServiceFilename = $ParamObject->GetParam( Param => 'ExampleWebService' ) || '';
my $FileWithoutExtension;
if ($ExampleWebServiceFilename) {
$ExampleWebServiceFilename =~ s{/+|\.{2,}}{}smx; # remove slashes and ..
if ( !$ExampleWebServiceFilename ) {
return $Kernel::OM->Get('Kernel::Output::HTML::Layout')->FatalError(
Message => Translatable('Need ExampleWebService!'),
);
}
# Extract file name.
$ExampleWebServiceFilename =~ m{(.*?)\.yml$}smx;
$FileWithoutExtension = $1;
# Run _pre.pm if available.
if ( -e "$Home/var/webservices/examples/" . $FileWithoutExtension . "_pre.pm" ) {
my $BackendName = 'var::webservices::examples::' . $FileWithoutExtension . '_pre';
my $Loaded = $MainObject->Require(
$BackendName,
);
if ( !$Loaded ) {
return $LayoutObject->ErrorScreen(
Message => $LayoutObject->{LanguageObject}->Translate( 'Could not load %s.', $BackendName ),
);
}
my $BackendPre = $Kernel::OM->Get(
$BackendName,
);
if ( $BackendPre->can('DependencyCheck') ) {
my %Result = $BackendPre->DependencyCheck();
if ( !$Result{Success} && $Result{ErrorMessage} ) {
return $Self->_ShowEdit(
DependencyErrorMessage => $Result{ErrorMessage},
%Param,
Action => 'Add',
);
}
}
my %Status = $BackendPre->Run();
if ( !$Status{Success} ) {
# Show the error screen.
return $LayoutObject->ErrorScreen(
Message => $Status{Error},
);
}
}
my $Content = $Kernel::OM->Get('Kernel::System::Main')->FileRead(
Location => "$Home/var/webservices/examples/$ExampleWebServiceFilename",
Mode => 'utf8',
);
if ( !$Content ) {
return $Kernel::OM->Get('Kernel::Output::HTML::Layout')->FatalError(
Message =>
$LayoutObject->{LanguageObject}->Translate( 'Could not read %s!', $ExampleWebServiceFilename ),
);
}
$Content = ${ $Content || \'' };
# Read configuration from a YAML structure.
$ImportedConfig = $YAMLObject->Load( Data => $Content );
$WebserviceName = $ExampleWebServiceFilename;
}
else {
# Get the web service config file from the http request.
my %ConfigFile = $ParamObject->GetUploadAll(
Param => 'ConfigFile',
);
# Check for file.
if ( !%ConfigFile ) {
return $LayoutObject->ErrorScreen(
Message => Translatable('Need a file to import!'),
);
}
# Read configuration from a YAML structure.
$ImportedConfig = $YAMLObject->Load( Data => $ConfigFile{Content} );
# Get web service name (optional), otherwise use filename of config file.
$WebserviceName = $ParamObject->GetParam( Param => 'WebserviceName' ) || '';
if ( !IsStringWithData($WebserviceName) ) {
$WebserviceName = $ConfigFile{Filename};
}
}
# Display any YAML error message as a normal otrs error message.
if ( !IsHashRefWithData($ImportedConfig) ) {
return $LayoutObject->ErrorScreen(
Message =>
Translatable('The imported file has not valid YAML content! Please check OTRS log for details'),
);
}
# Check if imported configuration has current framework version otherwise update it.
if (
!$ImportedConfig->{FrameworkVersion}
|| $ImportedConfig->{FrameworkVersion} ne $Kernel::OM->Get('Kernel::Config')->Get('Version')
)
{
$ImportedConfig = $Self->_UpdateConfiguration( Configuration => $ImportedConfig );
}
# Remove framework information since is not needed anymore.
delete $ImportedConfig->{FrameworkVersion};
# Remove file extension.
$WebserviceName =~ s{\.[^.]+$}{}g;
# Check required parameters.
my %Error;
if ( !$WebserviceName ) {
# Add server error error class.
$Error{NameServerError} = 'ServerError';
$Error{NameServerErrorMessage} = Translatable('This field is required');
}
my $WebserviceData;
# Set WebserviceData.
$WebserviceData->{Name} = $WebserviceName;
$WebserviceData->{Config} = $ImportedConfig;
$WebserviceData->{ValidID} = 1;
# Check if name is duplicated.
my %WebserviceList = %{ $WebserviceObject->WebserviceList() };
%WebserviceList = reverse %WebserviceList;
if (
$WebserviceList{$WebserviceName} &&
$WebserviceList{$WebserviceName} ne $WebserviceID
)
{
# Add server error error class.
$Error{NameServerError} = 'ServerError';
$Error{NameServerErrorMessage} = Translatable('There is another web service with the same name.');
}
# If there is an error return to edit screen.
if ( IsHashRefWithData( \%Error ) ) {
return $Self->_ShowEdit(
%Error,
%Param,
WebserviceID => $WebserviceID,
WebserviceData => $WebserviceData,
Action => 'Add',
);
}
# Otherwise save configuration and return to overview screen.
my $Success = $WebserviceObject->WebserviceAdd(
Name => $WebserviceData->{Name},
Config => $WebserviceData->{Config},
ValidID => $WebserviceData->{ValidID},
UserID => $Self->{UserID},
);
if (
$FileWithoutExtension
&& -e "$Home/var/webservices/examples/" . $FileWithoutExtension . "_post.pm"
)
{
my $BackendName = 'var::webservices::examples::' . $FileWithoutExtension . '_post';
my $Loaded = $MainObject->Require(
$BackendName,
);
if ($Loaded) {
my $BackendPost = $Kernel::OM->Get(
$BackendName,
);
my %Status = $BackendPost->Run();
if ( !$Status{Success} ) {
# Show the error screen.
return $LayoutObject->ErrorScreen(
Message => $Status{Error},
);
}
}
}
# Define notification.
my $Notify = $LayoutObject->{LanguageObject}->Translate(
'Web service "%s" created!',
$WebserviceData->{Name},
);
return $Self->_ShowOverview(
%Param,
Notify => $Notify,
Action => 'Overview',
);
}
# ------------------------------------------------------------ #
# sub-action DeleteAction: delete an operation or invoker
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'DeleteAction' ) {
# Challenge token check for write action.
$LayoutObject->ChallengeTokenCheck();
return $Self->_DeleteAction(
WebserviceID => $WebserviceID,
);
}
# ------------------------------------------------------------ #
# default: show start screen
# ------------------------------------------------------------ #
# Get Deleted web service if any.
my $DeletedWebservice = $ParamObject->GetParam( Param => 'DeletedWebservice' ) || '';
my $Notify;
if ($DeletedWebservice) {
# define notification
$Notify = $LayoutObject->{LanguageObject}->Translate(
'Web service "%s" deleted!',
$DeletedWebservice,
);
}
return $Self->_ShowOverview(
%Param,
Notify => $Notify,
Action => 'Overview',
);
}
sub _ShowOverview {
my ( $Self, %Param ) = @_;
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $Output = $LayoutObject->Header();
$Output .= $LayoutObject->NavigationBar();
# show notifications if any
if ( $Param{Notify} ) {
$Output .= $LayoutObject->Notify(
Info => $Param{Notify},
);
}
# Call all needed tt blocks.
$LayoutObject->Block(
Name => 'Main',
Data => \%Param,
);
$LayoutObject->Block( Name => 'ActionList' );
$LayoutObject->Block( Name => 'ActionAdd' );
$LayoutObject->Block( Name => 'OverviewHeader' );
$LayoutObject->Block( Name => 'OverviewResult' );
my $WebserviceObject = $Kernel::OM->Get('Kernel::System::GenericInterface::Webservice');
# Get web services list.
my $WebserviceList = $WebserviceObject->WebserviceList(
Valid => 0,
);
# Check if no web services are registered.
if ( !IsHashRefWithData($WebserviceList) ) {
$LayoutObject->Block( Name => 'NoDataFoundMsg' );
}
# Otherwise show all web services.
else {
WEBSERVICEID:
for my $WebserviceID (
sort { $WebserviceList->{$a} cmp $WebserviceList->{$b} }
keys %{$WebserviceList}
)
{
next WEBSERVICEID if !$WebserviceID;
# Get web service data.
my $Webservice = $WebserviceObject->WebserviceGet( ID => $WebserviceID );
next WEBSERVICEID if !$Webservice;
# Convert ValidID to text.
my $ValidStrg = $Kernel::OM->Get('Kernel::System::Valid')->ValidLookup(
ValidID => $Webservice->{ValidID},
);
if ( !$Webservice->{Config} || !IsHashRefWithData( $Webservice->{Config} ) ) {
# Write an error message to the OTRS log.
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Configuration of WebserviceID $WebserviceID is invalid!",
);
# Notify the user of problems loading this web service.
$Output .= $LayoutObject->Notify(
Priority => 'Error',
);
# Continue loading the list of web services.
next WEBSERVICEID;
}
# Prepare data to output.
my $Data = {
ID => $WebserviceID,
Name => $Webservice->{Name},
Description => $Webservice->{Config}->{Description} || '-',
RemoteSystem => $Webservice->{Config}->{RemoteSystem} || '-',
ProviderTransport => $Webservice->{Config}->{Provider}->{Transport}->{Type} || '-',
RequesterTransport => $Webservice->{Config}->{Requester}->{Transport}->{Type} || '-',
Valid => $ValidStrg,
};
$LayoutObject->Block(
Name => 'OverviewResultRow',
Data => $Data,
);
}
}
$Output .= $LayoutObject->Output(
TemplateFile => 'AdminGenericInterfaceWebservice',
Data => {
%Param,
},
);
$Output .= $LayoutObject->Footer();
return $Output;
}
sub _ShowEdit {
my ( $Self, %Param ) = @_;
my $WebserviceData = $Param{WebserviceData};
my $DebuggerData = $WebserviceData->{Config}->{Debugger} || {};
my $ProviderData = $WebserviceData->{Config}->{Provider} || {};
my $RequesterData = $WebserviceData->{Config}->{Requester} || {};
my $ErrorHandlingProvider = $WebserviceData->{Config}->{Provider}->{ErrorHandling} || {};
my $ErrorHandlingPriorityProvider = $WebserviceData->{Config}->{Provider}->{ErrorHandlingPriority} || [];
my $ErrorHandlingRequester = $WebserviceData->{Config}->{Requester}->{ErrorHandling} || {};
my $ErrorHandlingPriorityRequester = $WebserviceData->{Config}->{Requester}->{ErrorHandlingPriority} || [];
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $Output = $LayoutObject->Header();
$Output .= $LayoutObject->NavigationBar();
if ( $Param{DependencyErrorMessage} ) {
$Output .= $LayoutObject->Notify(
Priority => 'Notice',
Data => $Param{DependencyErrorMessage},
);
}
# Show notifications if any.
if ( $Param{Notify} ) {
$Output .= $LayoutObject->Notify(
Info => $Param{Notify},
);
}
$LayoutObject->Block(
Name => 'Main',
Data => \%Param,
);
if ( $Param{Action} eq 'Add' ) {
my @ExampleWebServices = $Kernel::OM->Get('Kernel::System::Main')->DirectoryRead(
Directory => $Kernel::OM->Get('Kernel::Config')->Get('Home') . '/var/webservices/examples',
Filter => '*.yml',
Silent => 1,
);
my %ExampleWebServicesData;
for my $ExampleWebServiceFilename (@ExampleWebServices) {
my $Key = $ExampleWebServiceFilename;
$Key =~ s{^.*/([^/]+)$}{$1}smx;
my $Value = $Key;
$Value =~ s{^(.+).yml}{$1}smx;
$Value =~ s{_}{ }smxg;
$ExampleWebServicesData{$Key} = $Value;
}
my %Frontend;
if ( %ExampleWebServicesData && $Kernel::OM->Get('Kernel::System::OTRSBusiness')->OTRSBusinessIsInstalled() ) {
$Frontend{ExampleWebServiceList} = $Kernel::OM->Get('Kernel::Output::HTML::Layout')->BuildSelection(
Name => 'ExampleWebService',
Data => \%ExampleWebServicesData,
PossibleNone => 1,
Translation => 0,
Class => 'Modernize Validate_Required',
);
}
# Enable Example web services.
$LayoutObject->Block(
Name => 'ExampleWebServices',
Data => {
%Frontend,
},
);
}
$LayoutObject->Block( Name => 'ActionList' );
$LayoutObject->Block( Name => 'ActionOverview' );
if ( $Param{Action} eq 'Change' ) {
$LayoutObject->Block(
Name => 'ActionClone',
Data => \%Param,
);
$LayoutObject->Block(
Name => 'ActionExport',
Data => \%Param,
);
$LayoutObject->Block(
Name => 'ActionHistory',
Data => \%Param,
);
$LayoutObject->Block(
Name => 'ActionDelete',
Data => \%Param,
);
$LayoutObject->Block(
Name => 'ActionDebugger',
Data => \%Param,
);
}
elsif ( $Param{Action} eq 'Add' ) {
$LayoutObject->Block(
Name => 'ActionImport',
Data => \%Param,
);
}
$LayoutObject->Block( Name => 'Hint' );
my %GeneralData = (
Name => $WebserviceData->{Name},
Description => $WebserviceData->{Config}->{Description},
RemoteSystem => $WebserviceData->{Config}->{RemoteSystem},
);
# Define the debug Thresholds (this needs to be hard-coded).
my %DebugThreshold = (
debug => Translatable('Debug'),
info => Translatable('Info'),
notice => Translatable('Notice'),
error => Translatable('Error'),
);
# Create the DebugThreshold select.
my $DebugThresholdStrg = $LayoutObject->BuildSelection(
Data => \%DebugThreshold,
Name => 'DebugThreshold',
SelectedID => $DebuggerData->{DebugThreshold} || '',
PossibleNone => 0,
Translate => 1,
Class => 'Modernize HideTrigger',
Sort => 'IndividualKey',
SortIndividual => [ 'debug', 'info', 'notice', 'error' ],
);
my %ValidList = $Kernel::OM->Get('Kernel::System::Valid')->ValidList();
# Create the validity select.
my $ValidtyStrg = $LayoutObject->BuildSelection(
Data => \%ValidList,
Name => 'ValidID',
SelectedID => $WebserviceData->{ValidID} || 1,
PossibleNone => 0,
Translate => 1,
Class => 'Modernize HideTrigger',
);
# Prevent HTML validation waring.
if ( !$Param{NameServerErrorMessage} ) {
$Param{NameServerErrorMessage} = '-';
}
$LayoutObject->Block(
Name => 'Details',
Data => {
%Param,
%GeneralData,
DebugThresholdStrg => $DebugThresholdStrg,
ValidtyStrg => $ValidtyStrg,
},
);
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
# Set transports data.
my %GITransports;
my $GITransportConfig = $ConfigObject->Get('GenericInterface::Transport::Module');
TRANSPORT:
for my $Transport ( sort keys %{$GITransportConfig} ) {
next TRANSPORT if !$Transport;
$GITransports{$Transport} = $GITransportConfig->{$Transport}->{ConfigDialog};
}
# Get operation data.
my %GIOperations;
my $GIOperationConfig = $ConfigObject->Get('GenericInterface::Operation::Module');
OPERATION:
for my $Operation ( sort keys %{$GIOperationConfig} ) {
next OPERATION if !$Operation;
$GIOperations{$Operation} = $GIOperationConfig->{$Operation}->{ConfigDialog};
}
# Get invoker data.
my %GIInvokers;
my $GIInvokerConfig = $ConfigObject->Get('GenericInterface::Invoker::Module');
INVOKER:
for my $Invoker ( sort keys %{$GIInvokerConfig} ) {
next INVOKER if !$Invoker;
$GIInvokers{$Invoker} = $GIInvokerConfig->{$Invoker}->{ConfigDialog};
}
# Get error handling modules data.
my %GIErrorHandlingModules;
my $GIErrorHandlingModuleConfig = $ConfigObject->Get('GenericInterface::ErrorHandling::Module');
ERRORHANDLINGMODULE:
for my $ErrorHandlingModules ( sort keys %{$GIErrorHandlingModuleConfig} ) {
next ERRORHANDLINGMODULE if !$ErrorHandlingModules;
$GIErrorHandlingModules{$ErrorHandlingModules}
= $GIErrorHandlingModuleConfig->{$ErrorHandlingModules}->{ConfigDialog};
}
$Self->_OutputGIConfig(
GITransports => \%GITransports,
GIOperations => \%GIOperations,
GIInvokers => \%GIInvokers,
GIErrorHandlingModules => \%GIErrorHandlingModules,
);
# Meta configuration for output blocks.
my %CommTypeConfig = (
Provider => {
Title => Translatable('OTRS as provider'),
SelectedTransport => $ProviderData->{Transport}->{Type},
ActionType => 'Operation',
ActionsTitle => Translatable('Operations'),
ActionsConfig => $ProviderData->{Operation},
ControllerData => \%GIOperations,
ErrorHandling => $ErrorHandlingProvider,
ErrorHandlingPriority => $ErrorHandlingPriorityProvider,
},
Requester => {
Title => Translatable('OTRS as requester'),
SelectedTransport => $RequesterData->{Transport}->{Type},
ActionType => 'Invoker',
ActionsTitle => Translatable('Invokers'),
ActionsConfig => $RequesterData->{Invoker},
ControllerData => \%GIInvokers,
ErrorHandling => $ErrorHandlingRequester,
ErrorHandlingPriority => $ErrorHandlingPriorityRequester,
},
);
for my $CommunicationType (qw(Provider Requester)) {
my @TransportList;
for my $Transport ( sort keys %GITransports ) {
push @TransportList, $Transport;
}
# Create the list of transports.
my $TransportsStrg = $LayoutObject->BuildSelection(
Data => \@TransportList,
Name => $CommunicationType . 'TransportList',
SelectedValue => $CommTypeConfig{$CommunicationType}->{SelectedTransport},
PossibleNone => 1,
Sort => 'AlphanumericValue',
Class => 'Modernize HideTrigger',
);
my $ErrorModuleConfig = $ConfigObject->Get('GenericInterface::ErrorHandling::Module');
my @ErrorModules;
ERRORMODULEKEY:
for my $ErrorModuleKey ( sort keys %{$ErrorModuleConfig} ) {
next ERRORMODULEKEY if !$ErrorModuleKey;
next ERRORMODULEKEY if !IsHashRefWithData( $ErrorModuleConfig->{$ErrorModuleKey} );
next ERRORMODULEKEY if !IsStringWithData( $ErrorModuleConfig->{$ErrorModuleKey}->{Name} );
next ERRORMODULEKEY if !IsStringWithData( $ErrorModuleConfig->{$ErrorModuleKey}->{ConfigDialog} );
# Check for active communication type filter.
if (
IsStringWithData( $ErrorModuleConfig->{$ErrorModuleKey}->{CommunicationTypeFilter} )
&& $ErrorModuleConfig->{$ErrorModuleKey}->{CommunicationTypeFilter} ne $CommunicationType
)
{
next ERRORMODULEKEY;
}
push @ErrorModules, {
Key => $ErrorModuleKey,
Value => $ErrorModuleConfig->{$ErrorModuleKey}->{Name},
};
}
# Create the list of error handling modules.
$Param{ErrorHandlingStrg} = $LayoutObject->BuildSelection(
Data => \@ErrorModules,
Name => $CommunicationType . 'ErrorHandling',
PossibleNone => 1,
Sort => 'AlphanumericValue',
Class => 'Modernize ConfigureErrorHandling',
);
# Get the controllers config for Requesters or Providers.
my %GIControllers = %{ $CommTypeConfig{$CommunicationType}->{ControllerData} };
my @ControllerList;
for my $Action ( sort keys %GIControllers ) {
push @ControllerList, $Action;
}
# Create the list of controllers.
my $ControllersStrg = $LayoutObject->BuildSelection(
Data => \@ControllerList,
Name => $CommTypeConfig{$CommunicationType}->{ActionType} . 'List',
Sort => 'AlphanumericValue',
PossibleNone => 1,
Class => 'Modernize',
);
$LayoutObject->Block(
Name => 'DetailsCommunicationType',
Data => {
%Param,
CommunicationType => $CommunicationType,
Title => $CommTypeConfig{$CommunicationType}->{Title},
TransportsStrg => $TransportsStrg,
ActionType => $CommTypeConfig{$CommunicationType}->{ActionType},
ControllersStrg => $ControllersStrg,
ActionsTitle => $CommTypeConfig{$CommunicationType}->{ActionsTitle},
},
);
$LayoutObject->Block(
Name => 'DetailsCommunicationTypeExplanation' . $CommunicationType,
);
# Check if selected transport can be configured and show the "configure button".
if (
$CommTypeConfig{$CommunicationType}->{SelectedTransport} &&
$GITransports{ $CommTypeConfig{$CommunicationType}->{SelectedTransport} }
)
{
$LayoutObject->Block(
Name => 'DetailsTransportPropertiesButton',
Data => {
CommunicationType => $CommunicationType,
},
);
}
$LayoutObject->Block(
Name => 'DetailsCommunicationTypeActionsExplanation' . $CommunicationType,
);
# Flag to display a message if at least one controller was not found.
my $NoControllerFound;
if ( !IsHashRefWithData( $CommTypeConfig{$CommunicationType}->{ActionsConfig} ) ) {
$LayoutObject->Block(
Name => 'DetailsActionsNoDataFoundMsg',
Data => {},
);
}
else {
# Output operation and invoker tables.
for my $ActionName (
sort keys %{ $CommTypeConfig{$CommunicationType}->{ActionsConfig} }
)
{
# Get control information.
my $ActionDetails = $CommTypeConfig{$CommunicationType}->{ActionsConfig}->{$ActionName};
# Create output data.
my %ActionData = (
Name => $ActionName,
Description => $ActionDetails->{Description} || '-',
Controller => $ActionDetails->{Type},
MappingInbound => $ActionDetails->{MappingInbound}->{Type} || '-',
MappingOutbound => $ActionDetails->{MappingOutbound}->{Type} || '-',
Module => $GIControllers{ $ActionDetails->{Type} },
ActionType => $CommTypeConfig{$CommunicationType}->{ActionType},
);
my $ControllerClass = '';
if ( !$GIControllers{ $ActionData{Controller} } ) {
$NoControllerFound = 1;
$ControllerClass = 'Error';
}
$LayoutObject->Block(
Name => 'DetailsActionsRow',
Data => {
%Param,
%ActionData,
ControllerClass => $ControllerClass,
},
);
if ( !$GIControllers{ $ActionData{Controller} } ) {
$LayoutObject->Block(
Name => 'DetailsActionsRowDelete',
Data => {
%Param,
%ActionData,
},
);
}
else {
$LayoutObject->Block(
Name => 'DetailsActionsRowLink',
Data => {
%Param,
%ActionData,
},
);
}
}
}
if ($NoControllerFound) {
$LayoutObject->Block(
Name => 'DetailsActionsNoControllerFoundMsg',
Data => {
%Param,
ActionType => lc $CommTypeConfig{$CommunicationType}->{ActionType},
},
);
}
# Check error handling modules and priority for consistency,
# correct possible inconsistencies and save the web service.
my $ErrorConfigUpdated = 0;
my $ErrorHandlingModulesCheck = join '',
sort @{ $CommTypeConfig{$CommunicationType}->{ErrorHandlingPriority} || [] };
my $ErrorHandlingPriorityCheck = join '',
sort keys %{ $CommTypeConfig{$CommunicationType}->{ErrorHandling} || {} };
if ( $ErrorHandlingModulesCheck ne $ErrorHandlingPriorityCheck ) {
my @CorrectedErrorHandlingModules
= sort keys %{ $CommTypeConfig{$CommunicationType}->{ErrorHandling} || [] };
$CommTypeConfig{$CommunicationType}->{ErrorHandlingPriority} = \@CorrectedErrorHandlingModules;
$ErrorConfigUpdated = 1;
}
# Check for type and set RequestRetry as default.
for my $CurrentErrorHandlingModule ( sort keys %{ $CommTypeConfig{$CommunicationType}->{ErrorHandling} || {} } )
{
if (
!defined $CommTypeConfig{$CommunicationType}->{ErrorHandling}->{$CurrentErrorHandlingModule}->{Type}
)
{
$CommTypeConfig{$CommunicationType}->{ErrorHandling}->{$CurrentErrorHandlingModule}->{Type}
= 'RequestRetry';
$ErrorConfigUpdated = 1;
}
}
# Update config if needed.
if ($ErrorConfigUpdated) {
$WebserviceData->{Config}->{$CommunicationType}->{ErrorHandling}
= $CommTypeConfig{$CommunicationType}->{ErrorHandling};
$WebserviceData->{Config}->{$CommunicationType}->{ErrorHandlingPriority}
= $CommTypeConfig{$CommunicationType}->{ErrorHandlingPriority};
$Kernel::OM->Get('Kernel::System::GenericInterface::Webservice')->WebserviceUpdate(
%{$WebserviceData},
UserID => $Self->{UserID},
);
}
# No error handling modules defined.
if ( !IsHashRefWithData( $CommTypeConfig{$CommunicationType}->{ErrorHandling} ) ) {
$LayoutObject->Block(
Name => 'ErrorHandlingRowNoDataFoundMsg',
);
}
# List available error handling modules.
else {
ERRORHANDLINGMODULE:
for my $ErrorHandlingModule ( @{ $CommTypeConfig{$CommunicationType}->{ErrorHandlingPriority} || [] } ) {
next ERRORHANDLINGMODULE if !$ErrorHandlingModule;
next ERRORHANDLINGMODULE
if !IsHashRefWithData(
$CommTypeConfig{$CommunicationType}->{ErrorHandling}->{$ErrorHandlingModule}
);
next ERRORHANDLINGMODULE
if !$CommTypeConfig{$CommunicationType}->{ErrorHandling}->{$ErrorHandlingModule}->{Type};
my $ErrorModuleAction = $ErrorModuleConfig->{
$CommTypeConfig{$CommunicationType}->{ErrorHandling}
->{$ErrorHandlingModule}->{Type}
}->{ConfigDialog};
next ERRORHANDLINGMODULE if !$ErrorModuleAction;
$LayoutObject->Block(
Name => 'ErrorHandlingRow',
Data => {
ErrorHandling => $ErrorHandlingModule,
Description =>
$CommTypeConfig{$CommunicationType}->{ErrorHandling}->{$ErrorHandlingModule}->{Description},
ErrorHandlingType =>
$CommTypeConfig{$CommunicationType}->{ErrorHandling}->{$ErrorHandlingModule}->{Type},
Dialog => $ErrorModuleAction,
CommunicationType => $CommunicationType,
WebserviceID => $Param{WebserviceID},
}
);
}
}
}
$Output .= $LayoutObject->Output(
TemplateFile => 'AdminGenericInterfaceWebservice',
Data => {
%Param,
},
);
$Output .= $LayoutObject->Footer();
return $Output;
}
sub _OutputGIConfig {
my ( $Self, %Param ) = @_;
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
# Send data to JS.
$LayoutObject->AddJSData(
Key => 'Webservice',
Value => {
Transport => $Param{GITransports},
Operation => $Param{GIOperations},
Invoker => $Param{GIInvokers},
ErrorHandling => $Param{GIErrorHandlingModules},
},
);
return 1;
}
sub _GetParams {
my ( $Self, %Param ) = @_;
my $GetParam;
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
# Get parameters from web browser.
for my $ParamName (
qw( Name Description RemoteSystem DebugThreshold ValidID )
)
{
$GetParam->{$ParamName} = $ParamObject->GetParam( Param => $ParamName ) || '';
}
$GetParam->{ProviderTransport} =
$ParamObject->GetParam( Param => 'ProviderTransportList' ) || '';
$GetParam->{RequesterTransport} =
$ParamObject->GetParam( Param => 'RequesterTransportList' ) || '';
return $GetParam;
}
sub _UpdateConfiguration {
my ( $Self, %Param ) = @_;
my $Configuration = $Param{Configuration};
# This function needs to be extended for further otrs versions
# it could be that newer otrs versions has different configuration options
# migration from previous version should be automatic and needs to be done here
return $Configuration;
}
sub _DeleteAction {
my ( $Self, %Param ) = @_;
my $WebserviceObject = $Kernel::OM->Get('Kernel::System::GenericInterface::Webservice');
# Get web service configuration.
my $WebserviceData = $WebserviceObject->WebserviceGet(
ID => $Param{WebserviceID},
);
# Get needed params.
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
my $ActionType = $ParamObject->GetParam( Param => 'ActionType' );
my $ActionName = $ParamObject->GetParam( Param => 'ActionName' );
# Set the communication type to Provider or Requester.
my $CommunicationType = $ActionType eq 'Operation' ? 'Provider' : 'Requester';
return if !$WebserviceData->{Config}->{$CommunicationType}->{$ActionType};
# Get the configuration config for the communication type (all operations or all invokers).
my %ActionTypeConfig = %{ $WebserviceData->{Config}->{$CommunicationType}->{$ActionType} };
my $Success;
# Delete communication type.
if ( $ActionTypeConfig{$ActionName} ) {
delete $ActionTypeConfig{$ActionName};
# Update web service configuration.
my %Config = %{ $WebserviceData->{Config} };
$Config{$CommunicationType}->{$ActionType} = \%ActionTypeConfig;
# Update web service.
$Success = $WebserviceObject->WebserviceUpdate(
%{$WebserviceData},
Config => \%Config,
UserID => $Self->{UserID},
);
}
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
# Build JSON output.
my $JSON = $LayoutObject->JSONEncode(
Data => {
Success => $Success,
},
);
# Send JSON response.
return $LayoutObject->Attachment(
ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
Content => $JSON,
Type => 'inline',
NoCache => 1,
);
}
1;