Files
2024-10-14 00:08:40 +02:00

2923 lines
145 KiB
Perl

# --
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (GPL). If you
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
# --
package Kernel::System::SysConfig::Migration;
use strict;
use warnings;
use parent qw(scripts::DBUpdateTo6::Base);
use List::Util qw(first);
our @ObjectDependencies = (
'Kernel::System::Log',
'Kernel::System::Main',
'Kernel::System::SysConfig',
);
use Kernel::System::VariableCheck qw( :all );
=head1 NAME
Kernel::System::SysConfig::Migration - System configuration settings migration tools.
=head1 PUBLIC INTERFACE
=head2 new()
Create an object. Do not use it directly, instead use:
use Kernel::System::ObjectManager;
local $Kernel::OM = Kernel::System::ObjectManager->new();
my $SysConfigMigrationObject = $Kernel::OM->Get('Kernel::System::SysConfig::Migration');
=cut
sub new {
my ( $Type, %Param ) = @_;
# allocate new hash for object
my $Self = {};
bless( $Self, $Type );
return $Self;
}
=head2 MigrateXMLStructure()
Migrate XML file content from OTRS 5 to OTRS 6.
my $Result = $SysConfigMigrationObject->MigrateXMLStructure(
Content => '
<?xml version="1.0" encoding="utf-8" ?>
<otrs_config version="1.0" init="Framework">
...
</otrs_config>',
Name => 'Framework',
);
Returns:
$Result = '
<?xml version="1.0" encoding="utf-8" ?>
<otrs_config version="2.0" init="Framework">
...
</otrs_config>';
=cut
sub MigrateXMLStructure {
my ( $Self, %Param ) = @_;
for my $Needed (qw(Content Name)) {
if ( !$Param{$Needed} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!",
);
return;
}
}
my $Init = "";
if ( $Param{Content} =~ m{<otrs_config.*?init="(.*?)"} ) {
$Init = $1;
}
# Stop if we don't have Init (configuration xml file is corrupt or invalid).
return if !$Init;
# Stop if its a configuration file is not from OTRS 5 or prior (OTRS 6 uses version 2.0).
return if !$Param{Content} =~ m{^<otrs_config.*?version="1.0"}gsmx;
# Split settings - prevent deleting some settings due to greedy RegEx. Each array item contains
# only one setting.
my @Settings = split( "</ConfigItem>", $Param{Content} );
my %InitToLoaderMapping = (
Framework => '001-',
Application => '002-',
Config => '003-',
Changes => '004-',
);
my %NavigationLookup = $Self->NavigationLookupGet();
my @Frontends;
SETTING:
for my $Setting (@Settings) {
# Stop the setting loop process if it's the ending tag.
last SETTING if $Setting =~ m/<\/otrs_config>/i;
# Update version (from 1.0 to 2.0).
$Setting =~ s{^(<otrs_config.*?version)="1.0"}{$1="2.0"}gsmx;
$Setting .= "</ConfigItem>";
# Update to preferences group
if ( $Setting =~ m{PreferencesGroups###} && $Setting =~ m{<Item Key="Column">} ) {
$Setting =~ s{<Item\s+Key="Column">}{<Item Key="PreferenceGroup">}gsmx;
}
# Check if FrontendModuleReg.
if ( $Setting =~ m{<FrontendModuleReg>} ) {
# Extract Loader and delete.
my $Loader;
if ( $Setting =~ s{\s+<Loader>(.*?)</Loader>$}{}gsmx ) {
$Loader = $1;
}
# Extract NavBar and delete
my $NavBar;
if ( $Setting =~ s{\s+<NavBar>(.*)</NavBar>$}{}gsmx ) {
$NavBar = "<NavBar>\n$1</NavBar>\n";
}
# Extract NavBarModule and delete
my $NavBarModule;
if ( $Setting =~ s{\s+<NavBarModule>(.*?)</NavBarModule>$}{}gsmx ) {
$NavBarModule = $1;
}
# Extract FrontendModuleReg and delete.
$Setting =~ s{<FrontendModuleReg>(.*?)</FrontendModuleReg>}{}gsmx;
my $FrontendModuleReg = $1;
# Split on new line.
my @Lines = split( "\n", $FrontendModuleReg );
LINE:
for my $Line (@Lines) {
my $Tag;
# Extract tag name.
if ( $Line =~ m{</(.*?)>} ) {
$Tag = $1;
}
next LINE if !$Tag;
# Create Item to replace $Tag.
$Line =~ s{<$Tag(.*?)</$Tag>}{<Item Key="$Tag"$1</Item>}gsmx;
}
$FrontendModuleReg = join( "\n", @Lines );
my %GroupItems;
@Lines = split( "\n", $FrontendModuleReg );
my @OutputLines;
LINE:
for my $Line (@Lines) {
next LINE if !$Line;
$Line =~ m{Item Key="(.*?)"};
my $ItemKey = $1 || '';
if ( $ItemKey eq 'Group' || $ItemKey eq 'GroupRo' ) {
$Line =~ m{<Item.*?>(.*?)</Item>}gsmg;
my $Value = $1;
if ( $GroupItems{$ItemKey} ) {
push @{ $GroupItems{$ItemKey} }, $Value;
# Skip this line.
next LINE;
}
else {
$GroupItems{$ItemKey} = [$Value];
# Put Placeholder.
$Line =~ s{^(\s+)<Item.*?</Item>.*?$}{$1 PLACEHOLDER_$ItemKey _END}gsmx;
}
}
$Line = " $Line";
push @OutputLines, $Line;
}
$FrontendModuleReg = join( "\n", @OutputLines );
my $FirstItem = 1;
for my $Key ( sort keys %GroupItems ) {
if ( ref $GroupItems{$Key} eq 'ARRAY' ) {
my $ArrayItems = '';
if ($FirstItem) {
$ArrayItems .= "\n";
}
$ArrayItems .= sprintf "%-*s%s", 20, "",
"<Item Key=\"$Key\">\n";
$ArrayItems .= sprintf "%-*s%s", 24, "",
"<Array>\n";
for my $ArrayItem ( @{ $GroupItems{$Key} } ) {
if ($ArrayItem) {
$ArrayItems .= sprintf "%-*s%s", 28, "",
"<Item>$ArrayItem</Item>\n";
}
}
$ArrayItems .= sprintf "%-*s%s", 24, "",
"</Array>\n";
$ArrayItems .= sprintf "%-*s%s", 20, "",
"</Item>";
$FrontendModuleReg =~ s{^\s+PLACEHOLDER_$Key\s_END.*?$}{$ArrayItems}gsmx;
}
$FirstItem = 0;
}
# Make sure each FrontendModuleReg has Group and GroupRo items
for my $GroupTag (qw(GroupRo Group)) {
if ( $FrontendModuleReg !~ m{<Item Key="$GroupTag"} ) {
my $MissingTag = sprintf "%-*s%s", 20, "",
"<Item Key=\"$GroupTag\">\n";
$MissingTag .= sprintf "%-*s%s", 24, "",
"<Array>\n";
$MissingTag .= sprintf "%-*s%s", 24, "",
"</Array>\n";
$MissingTag .= sprintf "%-*s%s", 20, "",
"</Item>\n";
# prepend
$FrontendModuleReg = $MissingTag .= $FrontendModuleReg;
}
}
# check if NavBarName exists
if ( $FrontendModuleReg !~ m{<Item Key="NavBarName"} ) {
$FrontendModuleReg .= sprintf "%-*s%s", 4, "",
"<Item Key=\"NavBarName\"></Item>\n";
$FrontendModuleReg .= sprintf "%-*s", 16, "";
}
my $FirstCharacter = substr $FrontendModuleReg, 0, 1;
if ( $FirstCharacter ne "\n" ) {
$FrontendModuleReg = "\n$FrontendModuleReg";
}
my $Value = "<Value>\n";
$Value .= sprintf "%-*s%s", 12, "", "<Item ValueType=\"FrontendRegistration\">\n";
$Value .= sprintf "%-*s%s", 16, "", "<Hash>";
$Value .= $FrontendModuleReg;
$Value .= "</Hash>\n";
$Value .= sprintf "%-*s%s", 12, "", "</Item>\n";
$Value .= sprintf "%-*s%s", 8, "", "</Value>";
$Setting =~ s{<Setting>.*?</Setting>}{$Value}gsmx;
# Put Loader stuff in a separated setting.
if (
$Loader
&& $Setting =~ m{<ConfigItem\s+Name="(.*?)"(.*?)>}gsmx
)
{
my $LoaderSetting = sprintf "%-*s%s", 4, "", "<ConfigItem Name=\"$1\"$2>";
my $LoaderName = ( $InitToLoaderMapping{$Init} // '005-' )
. $Param{Name};
$LoaderSetting =~ s{Name=".*?\#\#\#(.*?)" (.*?)>}{Name="Loader::Module::$1###$LoaderName"$2>}gsmx;
$LoaderSetting .= sprintf(
"\n%-*s%s",
8,
"",
"<Description Translatable=\"1\">Loader module registration for the agent interface.</Description>"
);
if ( $Setting =~ m{<SubGroup>(.*?)</SubGroup>} ) {
my $NavigationStr = $NavigationLookup{$1} || $1;
$NavigationStr .= "::Loader";
$LoaderSetting .= sprintf( "\n%-*s%s", 8, "", "<Navigation>$NavigationStr</Navigation>" );
}
$LoaderSetting .= sprintf( "\n%-*s%s", 8, "", "<Value>" );
$LoaderSetting .= sprintf( "\n%-*s%s", 12, "", "<Hash>" );
my @LoaderLines = split( "\n", $Loader );
my ( @CSS, @JS );
# Check for CSS and JS content.
for my $Line (@LoaderLines) {
if ( $Line =~ m{<CSS>(.*?)</CSS>} ) {
push @CSS, $1;
}
if ( $Line =~ m{<JavaScript>(.*?)</JavaScript>} ) {
push @JS, $1;
}
}
if ( scalar @CSS ) {
$LoaderSetting .= sprintf( "\n%-*s%s", 16, "", "<Item Key=\"CSS\">" );
$LoaderSetting .= sprintf( "\n%-*s%s", 20, "", "<Array>" );
}
for my $CSSItem (@CSS) {
$LoaderSetting .= sprintf( "\n%-*s%s", 24, "", "<Item>$CSSItem</Item>" );
}
if ( scalar @CSS ) {
$LoaderSetting .= sprintf( "\n%-*s%s", 20, "", "</Array>" );
$LoaderSetting .= sprintf( "\n%-*s%s", 16, "", "</Item>" );
}
if ( scalar @JS ) {
$LoaderSetting .= sprintf( "\n%-*s%s", 16, "", "<Item Key=\"JavaScript\">" );
$LoaderSetting .= sprintf( "\n%-*s%s", 20, "", "<Array>" );
}
for my $JSItem (@JS) {
$LoaderSetting .= sprintf( "\n%-*s%s", 24, "", "<Item>$JSItem</Item>" );
}
if ( scalar @JS ) {
$LoaderSetting .= sprintf( "\n%-*s%s", 20, "", "</Array>" );
$LoaderSetting .= sprintf( "\n%-*s%s", 16, "", "</Item>" );
}
$LoaderSetting .= sprintf( "\n%-*s%s", 12, "", "</Hash>" );
$LoaderSetting .= sprintf( "\n%-*s%s", 8, "", "</Value>" );
$LoaderSetting .= sprintf( "\n%-*s%s", 4, "", "</ConfigItem>" );
$Setting .= "\n" . $LoaderSetting;
}
if ( $NavBar && $Setting =~ m{<ConfigItem\s+Name="(.*?)"(.*?)>}gsmx ) {
my $Name = $1;
my $Options = $2;
my @NavBars = split m{<\/NavBar>\s+?<NavBar}, $NavBar;
$Name =~ s{Frontend::Module}{Frontend::Navigation}gsmx;
$Name .= '###' . ( $InitToLoaderMapping{$Init} // '005-' ) . $Param{Name};
my $Navigation = sprintf "%-*s%s", 4, "", "<Setting Name=\"$Name\"$Options>\n";
$Navigation .= sprintf "%-*s%s", 8, "",
"<Description Translatable=\"1\">Main menu item registration.</Description>";
if ( $Setting =~ m{<SubGroup>(.*?)</SubGroup>} ) {
my $NavigationStr = $NavigationLookup{$1} || $1;
$NavigationStr .= "::MainMenu";
$Navigation .= sprintf( "\n%-*s%s", 8, "", "<Navigation>$NavigationStr</Navigation>" );
}
$Navigation .= sprintf( "\n%-*s%s", 8, "", "<Value>" );
$Navigation .= sprintf( "\n%-*s%s", 12, "", "<Array>" );
$Navigation .= sprintf( "\n%-*s%s", 16, "", "<DefaultItem ValueType=\"FrontendNavigation\">" );
$Navigation .= sprintf( "\n%-*s%s", 20, "", "<Hash>" );
$Navigation .= sprintf( "\n%-*s%s", 20, "", "</Hash>" );
$Navigation .= sprintf( "\n%-*s%s", 16, "", "</DefaultItem>" );
for my $NavBarItem (@NavBars) {
$Navigation .= sprintf( "\n%-*s%s", 16, "", "<Item>" );
$Navigation .= sprintf( "\n%-*s%s", 20, "", "<Hash>" );
for my $NavBarTag (qw(Group GroupRo)) {
my @Items;
while ( $NavBarItem =~ s{<$NavBarTag>(.*?)<\/$NavBarTag}{}smx ) {
push @Items, $1;
}
$Navigation .= sprintf( "\n%-*s%s", 24, "", "<Item Key=\"$NavBarTag\">" );
$Navigation .= sprintf( "\n%-*s%s", 28, "", "<Array>" );
for my $Value (@Items) {
$Navigation .= sprintf( "\n%-*s%s", 32, "", "<Item>$Value</Item>" );
}
if (
!scalar @Items
&& $GroupItems{$NavBarTag}
)
{
# take group items from FrontendModuleReg
for my $Value ( @{ $GroupItems{$NavBarTag} } ) {
if ($Value) {
$Navigation .= sprintf( "\n%-*s%s", 32, "", "<Item>$Value</Item>" );
}
}
}
$Navigation .= sprintf( "\n%-*s%s", 28, "", "</Array>" );
$Navigation .= sprintf( "\n%-*s%s", 24, "", "</Item>" );
}
for my $NavBarTag (qw(Description Name Link LinkOption NavBar Type Block AccessKey Prio)) {
my $Value = '';
my $Attributes = '';
if ( $NavBarItem =~ m{<$NavBarTag>(.*?)<\/$NavBarTag} ) {
$Value = $1;
}
elsif ( $NavBarItem =~ m{<$NavBarTag\s(.*?)>(.*?)<\/$NavBarTag} ) {
$Attributes = " $1";
$Value = $2;
}
$Navigation .= sprintf(
"\n%-*s%s", 24, "",
"<Item Key=\"$NavBarTag\"$Attributes>$Value</Item>",
);
}
$Navigation .= sprintf( "\n%-*s%s", 20, "", "</Hash>" );
$Navigation .= sprintf( "\n%-*s%s", 16, "", "</Item>" );
}
$Navigation .= sprintf( "\n%-*s%s", 12, "", "</Array>" );
$Navigation .= sprintf( "\n%-*s%s", 8, "", "</Value>" );
$Navigation .= sprintf( "\n%-*s%s", 4, "", "</ConfigItem>\n" ); # We rename ConfigItems later
$Setting .= "\n" . $Navigation;
}
elsif ( !$NavBar && $Setting =~ m{<ConfigItem\s+Name="(.*?)"(.*?)>}gsmx ) {
my $Name = $1;
my $Options = $2;
my %NoDefaultNavigationSetting = (
'CustomerFrontend::Module###AjaxAttachment' => 1,
'CustomerFrontend::Module###CustomerAccept' => 1,
'CustomerFrontend::Module###CustomerChatDownload' => 1,
'CustomerFrontend::Module###CustomerDynamicFieldDatabaseDetailedSearch' => 1,
'CustomerFrontend::Module###CustomerDynamicFieldDatabaseDetails' => 1,
'CustomerFrontend::Module###CustomerDynamicFieldDatabaseSearch' => 1,
'CustomerFrontend::Module###CustomerTicketArticleContent' => 1,
'CustomerFrontend::Module###CustomerTicketAttachment' => 1,
'CustomerFrontend::Module###CustomerTicketPrint' => 1,
'CustomerFrontend::Module###CustomerTicketZoom' => 1,
'CustomerFrontend::Module###CustomerVideoChat' => 1,
'CustomerFrontend::Module###Login' => 1,
'CustomerFrontend::Module###Logout' => 1,
'CustomerFrontend::Module###PictureUpload' => 1,
'Frontend::Module###AdminAppointmentImport' => 1,
'Frontend::Module###AdminDynamicFieldCheckbox' => 1,
'Frontend::Module###AdminDynamicFieldContactWithData' => 1,
'Frontend::Module###AdminDynamicFieldDatabase' => 1,
'Frontend::Module###AdminDynamicFieldDateTime' => 1,
'Frontend::Module###AdminDynamicFieldDropdown' => 1,
'Frontend::Module###AdminDynamicFieldMultiselect' => 1,
'Frontend::Module###AdminDynamicFieldText' => 1,
'Frontend::Module###AdminDynamicFieldWebService' => 1,
'Frontend::Module###AdminGenericInterfaceErrorHandlingDefault' => 1,
'Frontend::Module###AdminGenericInterfaceErrorHandlingRequestRetry' => 1,
'Frontend::Module###AdminGenericInterfaceInvokerDefault' => 1,
'Frontend::Module###AdminGenericInterfaceInvokerEvent' => 1,
'Frontend::Module###AdminGenericInterfaceMappingSimple' => 1,
'Frontend::Module###AdminGenericInterfaceMappingXSLT' => 1,
'Frontend::Module###AdminGenericInterfaceOperationDefault' => 1,
'Frontend::Module###AdminGenericInterfaceTransportHTTPREST' => 1,
'Frontend::Module###AdminGenericInterfaceTransportHTTPSOAP' => 1,
'Frontend::Module###AdminGenericInterfaceWebserviceHistory' => 1,
'Frontend::Module###AdminInit' => 1,
'Frontend::Module###AdminProcessManagementActivity' => 1,
'Frontend::Module###AdminProcessManagementActivityDialog' => 1,
'Frontend::Module###AdminProcessManagementPath' => 1,
'Frontend::Module###AdminProcessManagementTransition' => 1,
'Frontend::Module###AdminProcessManagementTransitionAction' => 1,
'Frontend::Module###AgentAppointmentEdit' => 1,
'Frontend::Module###AgentAppointmentPluginSearch' => 1,
'Frontend::Module###AgentChatAppend' => 1,
'Frontend::Module###AgentChatAvailability' => 1,
'Frontend::Module###AgentChatDownload' => 1,
'Frontend::Module###AgentChatPopup' => 1,
'Frontend::Module###AgentChatPreview' => 1,
'Frontend::Module###AgentContactWithDataSearch' => 1,
'Frontend::Module###AgentCustomerSearch' => 1,
'Frontend::Module###AgentCustomerSearchSMS' => 1,
'Frontend::Module###AgentCustomerUserAddressBook' => 1,
'Frontend::Module###AgentCustomerUserInformationCenterSearch' => 1,
'Frontend::Module###AgentDaemonInfo' => 1,
'Frontend::Module###AgentDynamicFieldDatabaseDetailedSearch' => 1,
'Frontend::Module###AgentDynamicFieldDatabaseDetails' => 1,
'Frontend::Module###AgentDynamicFieldDatabaseSearch' => 1,
'Frontend::Module###AgentInfo' => 1,
'Frontend::Module###AgentHTMLReference' => 1,
'Frontend::Module###AgentOTRSBusiness' => 1,
'Frontend::Module###AgentSplitSelection' => 1,
'Frontend::Module###AgentTicketArticleContent' => 1,
'Frontend::Module###AgentTicketAttachment' => 1,
'Frontend::Module###AgentTicketAttachmentView' => 1,
'Frontend::Module###AgentTicketBounce' => 1,
'Frontend::Module###AgentTicketBulk' => 1,
'Frontend::Module###AgentTicketClose' => 1,
'Frontend::Module###AgentTicketCompose' => 1,
'Frontend::Module###AgentTicketCustomer' => 1,
'Frontend::Module###AgentTicketEmailOutbound' => 1,
'Frontend::Module###AgentTicketEmailResend' => 1,
'Frontend::Module###AgentTicketForward' => 1,
'Frontend::Module###AgentTicketFreeText' => 1,
'Frontend::Module###AgentTicketHistory' => 1,
'Frontend::Module###AgentTicketLock' => 1,
'Frontend::Module###AgentTicketMerge' => 1,
'Frontend::Module###AgentTicketMove' => 1,
'Frontend::Module###AgentTicketNote' => 1,
'Frontend::Module###AgentTicketOwner' => 1,
'Frontend::Module###AgentTicketPending' => 1,
'Frontend::Module###AgentTicketPhoneInbound' => 1,
'Frontend::Module###AgentTicketPhoneOutbound' => 1,
'Frontend::Module###AgentTicketPlain' => 1,
'Frontend::Module###AgentTicketPrint' => 1,
'Frontend::Module###AgentTicketPriority' => 1,
'Frontend::Module###AgentTicketResponsible' => 1,
'Frontend::Module###AgentTicketSMSOutbound' => 1,
'Frontend::Module###AgentTicketWatcher' => 1,
'Frontend::Module###AgentTicketZoom' => 1,
'Frontend::Module###AgentUserSearch' => 1,
'Frontend::Module###AgentVideoChat' => 1,
'Frontend::Module###AgentZoom' => 1,
'Frontend::Module###AjaxAttachment' => 1,
'Frontend::Module###Login' => 1,
'Frontend::Module###Logout' => 1,
'Frontend::Module###PictureUpload' => 1,
'PublicFrontend::Module###PublicCalendar' => 1,
'PublicFrontend::Module###PublicDefault' => 1,
'PublicFrontend::Module###PublicRepository' => 1,
'PublicFrontend::Module###PublicSupportDataCollector' => 1,
);
if ( !$NoDefaultNavigationSetting{$Name} ) {
$Name =~ s{Frontend::Module}{Frontend::Navigation}gsmx;
$Name .= '###' . ( $InitToLoaderMapping{$Init} // '005-' ) . $Param{Name};
my $Navigation = sprintf "%-*s%s", 4, "", "<Setting Name=\"$Name\" Required=\"0\" Valid=\"0\">\n";
$Navigation .= sprintf "%-*s%s", 8, "",
"<Description Translatable=\"1\">Main menu item registration.</Description>";
if ( $Setting =~ m{<SubGroup>(.*?)</SubGroup>} ) {
my $NavigationStr = $NavigationLookup{$1} || $1;
$NavigationStr .= "::MainMenu";
$Navigation .= sprintf( "\n%-*s%s", 8, "", "<Navigation>$NavigationStr</Navigation>" );
}
$Navigation .= sprintf( "\n%-*s%s", 8, "", "<Value>" );
$Navigation .= sprintf( "\n%-*s%s", 12, "", "<Array>" );
$Navigation .= sprintf( "\n%-*s%s", 16, "", "<DefaultItem ValueType=\"FrontendNavigation\">" );
$Navigation .= sprintf( "\n%-*s%s", 20, "", "<Hash>" );
$Navigation .= sprintf( "\n%-*s%s", 20, "", "</Hash>" );
$Navigation .= sprintf( "\n%-*s%s", 16, "", "</DefaultItem>" );
$Navigation .= sprintf( "\n%-*s%s", 12, "", "</Array>" );
$Navigation .= sprintf( "\n%-*s%s", 8, "", "</Value>" );
$Navigation .= sprintf( "\n%-*s%s", 4, "", "</ConfigItem>\n" ); # We rename ConfigItems later
$Setting .= "\n" . $Navigation;
}
}
if ( $NavBarModule && $Setting =~ m{<ConfigItem\s+Name="(.*?)"(.*?)>}gsmx ) {
# FrontendNavigationModule
my $Name = $1;
my $Options = $2;
$Name =~ s{Frontend::Module}{Frontend::NavigationModule}gsmx;
my $NavigationModule = sprintf "%-*s%s", 4, "", "<Setting Name=\"$Name\"$Options>\n";
$NavigationModule .= sprintf "%-*s%s", 8, "",
"<Description Translatable=\"1\">Admin area navigation for the agent interface.</Description>";
if ( $Setting =~ m{<SubGroup>(.*?)</SubGroup>} ) {
my $NavigationStr = $NavigationLookup{$1} || $1;
$NavigationStr .= '::AdminOverview';
$NavigationModule .= sprintf( "\n%-*s%s", 8, "", "<Navigation>$NavigationStr</Navigation>" );
}
$NavigationModule .= sprintf( "\n%-*s%s", 8, "", "<Value>" );
$NavigationModule .= sprintf( "\n%-*s%s", 12, "", "<Hash>" );
for my $NavBarTag (qw(Group GroupRo)) {
my @Items;
while ( $NavBarModule =~ s{<$NavBarTag>(.*?)<\/$NavBarTag}{}smx ) {
push @Items, $1;
}
$NavigationModule .= sprintf( "\n%-*s%s", 16, "", "<Item Key=\"$NavBarTag\">" );
$NavigationModule .= sprintf( "\n%-*s%s", 20, "", "<Array>" );
for my $Value (@Items) {
$NavigationModule .= sprintf( "\n%-*s%s", 24, "", "<Item>$Value</Item>" );
}
if (
!scalar @Items
&& $GroupItems{$NavBarTag}
)
{
# take group items from FrontendModuleReg
for my $Value ( @{ $GroupItems{$NavBarTag} } ) {
if ($Value) {
$NavigationModule .= sprintf( "\n%-*s%s", 24, "", "<Item>$Value</Item>" );
}
}
}
$NavigationModule .= sprintf( "\n%-*s%s", 20, "", "</Array>" );
$NavigationModule .= sprintf( "\n%-*s%s", 16, "", "</Item>" );
}
NAVBARTAG:
for my $NavBarTag (qw(Module Name Block Description IconBig IconSmall CssClass)) {
my $Value = '';
my $Attributes = '';
if ( $NavBarModule =~ m{<$NavBarTag>(.*?)<\/$NavBarTag} ) {
$Value = $1;
}
elsif ( $NavBarModule =~ m{<$NavBarTag\s(.*?)>(.*?)<\/$NavBarTag} ) {
$Attributes = " $1";
$Value = $2;
}
# special treatment for OTRSBusiness tile CssClass
if ( $NavBarTag eq 'CssClass' ) {
next NAVBARTAG if $Name ne 'Frontend::NavigationModule###AdminOTRSBusiness';
$Value = 'OTRSBusiness';
}
$NavigationModule .= sprintf(
"\n%-*s%s", 16, "",
"<Item Key=\"$NavBarTag\"$Attributes>$Value</Item>",
);
}
$NavigationModule .= sprintf( "\n%-*s%s", 12, "", "</Hash>" );
$NavigationModule .= sprintf( "\n%-*s%s", 8, "", "</Value>" );
$NavigationModule .= sprintf( "\n%-*s%s", 4, "", "</ConfigItem>\n" ); # We rename ConfigItems later
$Setting .= "\n" . $NavigationModule;
}
}
# Rename Regex to ValueRegex.
$Setting =~ s{^(\s+<String\s+)Regex="(.*?)"}{$1ValueRegex="$2"}gsmx;
# Check for known old validation modules.
for my $ValidateModule (qw(StateValidate PriorityValidate QueueValidate)) {
if ( $Setting =~ m{<ValidateModule>.*?$ValidateModule</ValidateModule>}gsm ) {
# Remove ValidateModule tag.
$Setting =~ s{^\s+<ValidateModule>.*?::$ValidateModule</ValidateModule>}{}gsmx;
my $Entity;
if ( $ValidateModule eq 'StateValidate' ) {
$Entity = 'State';
}
elsif ( $ValidateModule eq 'PriorityValidate' ) {
$Entity = 'Priority';
}
elsif ( $ValidateModule eq 'QueueValidate' ) {
$Entity = 'Queue';
}
# Update string tag.
$Setting =~ s{<String(.*?)>(.*?)</String>}
{<Item ValueType="Entity" ValueEntityType="$Entity"$1>$2</Item>}gsmx;
}
}
# Update file path.
$Setting =~ s{<String\s+ValueRegex="(.*?)"\s+Check="File".*?>(.*?)<\/String>}
{<Item ValueRegex="$1" ValueType="File">$2</Item>}gsmx;
# Update file directory.
$Setting =~ s{<String\s+ValueRegex="(.*?)"\s+Check="Directory".*?>(.*?)<\/String>}
{<Item ValueRegex="$1" ValueType="Directory">$2</Item>}gsmx;
# Replace No/Yes drop-down with Checkbox.
$Setting =~ s{
^(\s+) # match space
<Option.*?SelectedID="(\d)" # match SelectedID inside Option tag
.*? Key="0" .*?>No< # match No
.*? Key="1" .*?>Yes</Item> # match Yes
\s+?</Option>? # match end of option
}
{$1<Item ValueType="Checkbox">$2</Item>}gsmx;
$Setting =~ s{
^(\s+) # match space
<Option.*?SelectedID="" # match empty SelectedID inside Option tag
.*? Key="0" .*?>No< # match No
.*? Key="1" .*?>Yes</Item> # match Yes
\s+?</Option>? # match end of option
}
{$1<Item ValueType="Checkbox">0</Item>}gsmx;
# Replace Yes/No drop-down with Checkbox
$Setting =~ s{
^(\s+) # match space
<Option.*?SelectedID="(\d)" # match SelectedID inside Option tag
.*? Key="1" .*?>Yes< # match Yes
.*? Key="0" .*?>No</Item> # match No
\s+?</Option> # match end of option
}
{$1<Item ValueType="Checkbox">$2</Item>}gsmx;
$Setting =~ s{
^(\s+) # match space
<Option.*?SelectedID="" # match empty SelectedID inside Option tag
.*? Key="1" .*?>Yes< # match Yes
.*? Key="0" .*?>No</Item> # match No
\s+?</Option> # match end of option
}
{$1<Item ValueType="Checkbox">0</Item>}gsmx;
# Check if this Setting contains Option with Items.
if ( $Setting =~ m{<Option.*?<Item.*?</Option>}gsm ) {
my @Items = split( '</Item>', $Setting );
for my $Item (@Items) {
# Set the ValueType 'Option' tag to the main item.
$Item =~ s{<Item\s+Key="(.*?)"(.*?)>(.*?)$}{<Item ValueType="Option" Value="$1"$2>$3}gsmx;
# Convert Options to children Item.
$Item =~ s{<Option(.*?)>}{<Item ValueType="Select"$1>}gsmx;
# Convert </Option> to </Item>
$Item =~ s{</Option>}{</Item>}gsmx;
}
$Setting = join( '</Item>', @Items );
}
elsif ( $Setting =~ m{<Option\s+Location="(.*?)"\s+SelectedID="(.*?)".*?</Option>}gsm ) {
my ( $Location, $SelectedID ) = ( $1, $2 );
$Setting =~ s{<Option.*?</Option>}
{<Item ValueType="PerlModule" ValueFilter="$Location">$SelectedID</Item>}gsmx;
}
# Update WorkingHours.
if ( $Setting =~ m{TimeWorkingHours} ) {
my @Days = split( "</Day>", $Setting );
pop @Days; # contains not needed item
my $WorkingHoursString = '';
my $SpaceString = '';
for my $Day (@Days) {
# Check if this item contains string and update to WorkingHours ValueType.
if ( $Day =~ s{^(\s+)<TimeWorkingHours>}{$1<Item ValueType="WorkingHours">}gsmx ) {
if ($1) {
$SpaceString = $1;
}
}
# Set Day ValueType tag.
$Day =~ s{<Day\s+Name="(.*?)">}{<Item ValueType="Day" ValueName="$1">}gsmx;
# Set Hour ValueType tag.
$Day =~ s{<Hour>(\d+)</Hour>}{<Item ValueType="Hour">$1</Item>}gsmx;
# Add block closure tag on the last item.
if ( $Day eq $Days[-1] ) {
$Day .= "</Item>\n$SpaceString</Item>";
}
}
my $DaysString = join( '</Item>', @Days );
$Setting =~ s{.*?<TimeWorkingHours>.*?</TimeWorkingHours>}{$DaysString}gsmx;
}
# Update VacationDays.
if ( $Setting =~ m{<(TimeVacationDays.*?)>} ) {
my $Type = $1;
my $TypeNew;
if ( $Type eq 'TimeVacationDays' ) {
$TypeNew = "VacationDays";
}
else {
$TypeNew = "VacationDaysOneTime";
}
# Update item tags to the new format.
$Setting =~ s{Year=}{ValueYear=}gsmx;
$Setting =~ s{Month=}{ValueMonth=}gsmx;
$Setting =~ s{Day=}{ValueDay=}gsmx;
# Update TimeVacationDays tags.
$Setting =~ s{<$Type>}{<Item ValueType="$TypeNew">}gsmx;
$Setting =~ s{</$Type>}{</Item>}gsmx;
}
# Update DynamicField Settings
my $Hashtag = '###';
my @DFoptions;
if (
$Setting =~ m{Name=(.*?)\#\#\#(|FollowUp|ProcessWidget|SearchOverview|SearchCSV)DynamicField\"} ||
$Setting =~ m{Name=(.*?)(\#\#\#DefaultColumns|DefaultOverviewColumns)} ||
$Setting =~ m{Name=\"(AgentCustomerInformationCenter::Backend|DashboardBackend)\#\#\#} ||
$Setting =~ m{Name=\"LinkObject::ComplexTable\#\#\#Ticket\"}
)
{
# 0 = Disabled, 1 = Enabled, 2 = Enabled and shown by default
if (
$Setting
=~ m{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sEnabled,\s2\s=\sEnabled\sand\sshown\sby\sdefault.}
)
{
@DFoptions = ( '0 - Disabled', '1 - Enabled', '2 - Enabled and shown by default' );
$Setting
=~ s{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sEnabled,\s2\s=\sEnabled\sand\sshown\sby\sdefault.}{}gsmx;
}
# 0 = Disabled, 1 = Enabled, 2 = Enabled and required.
elsif (
$Setting =~ m{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sEnabled,\s2\s=\sEnabled\sand\srequired.}
)
{
@DFoptions = ( '0 - Disabled', '1 - Enabled', '2 - Enabled and required' );
$Setting
=~ s{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sEnabled,\s2\s=\sEnabled\sand\srequired.}{}gsmx;
}
# 0 = Disabled, 1 = Available, 2 = Enabled by default.
elsif (
$Setting =~ m{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sAvailable,\s2\s=\sEnabled\sby\sdefault.} ||
$Setting =~ m{Name=\"DashboardBackend\#\#\#0140-RunningTicketProcess\"}
)
{
@DFoptions = ( '0 - Disabled', '1 - Available', '2 - Enabled by default' );
$Setting
=~ s{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sAvailable,\s2\s=\sEnabled\sby\sdefault.}{}gmsx;
}
# 0 = Disabled, 1 = Enabled.
elsif (
$Setting =~ m{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sEnabled.}
)
{
@DFoptions = ( '0 - Disabled', '1 - Enabled' );
$Setting =~ s{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sEnabled.}{}gsmx;
}
my $ReplacementString;
my $DFCount = 0;
if (@DFoptions) {
$ReplacementString = "\n\t\t\t<Hash>\n" .
"\t\t\t\t<DefaultItem ValueType=\"Select\">\n";
for my $DFoption (@DFoptions) {
## nofilter(TidyAll::Plugin::OTRS::Perl::Translatable)
$ReplacementString
.= "\t\t\t\t\t<Item ValueType=\"Option\" Value=\"$DFCount\" Translatable=\"1\">$DFoption</Item>\n";
$DFCount++;
}
$ReplacementString .= "\t\t\t\t</DefaultItem>\n" .
"\t\t\t</Hash>\n";
}
if ($ReplacementString) {
# DynamicFields
$Setting =~ s{
Name=(.*?)\#\#\#(|FollowUp|ProcessWidget|SearchOverview|SearchCSV)DynamicField\"(.*?)
<Setting>(\s+)<Hash>(\s+)<\/Hash>
}{Name=$1$Hashtag$2DynamicField"$3<Value>$ReplacementString}gsmx;
# DefaultColumns
$ReplacementString =~ s{\n\t\t\t<Hash>\n}{\n\t<Hash>\n};
$ReplacementString =~ s{\n}{\n\t\t};
$ReplacementString =~ s{\t\t\t</Hash>\n}{};
$ReplacementString .= "\t\t<Item Key=\"Age\">2</Item>";
my $DefaultColumnsHashtag = $Hashtag . 'DefaultColumns';
$Setting =~ s{
Name=(.*?)\#\#\#DefaultColumns\"(.*?)
<Setting>(\s+)<Hash>(\s+)<Item\sKey=\"Age\">2</Item>
}{Name=$1$DefaultColumnsHashtag"$2<Value>$ReplacementString}gsmx;
$Setting =~ s{
Name=(.*?)DefaultOverviewColumns\"(.*?)
<Setting>(\s+)<Hash>(\s+)<Item\sKey=\"Age\">2</Item>
}{Name=$1DefaultOverviewColumns"$2<Value>$ReplacementString}gsmx;
# AgentCustomerInformationCenter-||DashboardBackend
my $BackendReplacement = "<Item Key=\"DefaultColumns\">" .
$ReplacementString . "\n";
$BackendReplacement =~ s{\n\t}{\n\t\t\t}gsmx;
$Setting =~ s{
Name=\"(DashboardBackend|AgentCustomerInformationCenter::Backend)\#\#\#(.*?)\"(.*?)
<Item\sKey=\"DefaultColumns\">(\s+)<Hash>(\s+)<Item\sKey=\"Age\">2</Item>
}
{Name="$1$Hashtag$2"$3$BackendReplacement}gsmx;
if ( $Setting =~ m{Name=\"LinkObject::ComplexTable\#\#\#Ticket\"} ) {
my $LinkBackendReplace = $BackendReplacement;
$LinkBackendReplace =~ s{DefaultItem>(\s+)<Item\sKey}{DefaultItem>\n\t\t\t\t\t\t<Item Key}gsmx;
$LinkBackendReplace =~ s{\t\t<Item\sKey=\"Age\">2</Item>}{<Item Key="Age">1</Item>}gsmx;
$Setting =~ s{
<Item\sKey=\"DefaultColumns\">(\s+)<Hash>(\s+)<Item\sKey=\"Age\">1</Item>
}
{$LinkBackendReplace}gsmx;
}
# Fill dropdowns with existing values.
$Setting =~ s{<\/DefaultItem>(\s*?)<Item\sKey="(.*?)">(0|1|2)<}
{<\/DefaultItem>$1\t\t<Item Key="$2" SelectedID="$3"><}gsmx;
# Only alter <Items> right after </DefaultItem> and before the closing the hash </Hash>
my $DropdownItems;
if ( $Setting =~ m{<\/DefaultItem>(.+)<\/Hash>\s+^[\s]}smx ) {
$DropdownItems = $1;
while (
$DropdownItems =~ m{"(0|1|2)"><\/Item>(\s*)<Item\sKey="(.*?)">(0|1|2)<}
)
{
if ( $2 ne 'Default' ) {
$DropdownItems =~ s{><\/Item>(\s*)<Item\sKey="(.*?)">(0|1|2)<}
{></Item>$1<Item Key="$2" SelectedID="$3"><}gsmx;
}
}
$DropdownItems =~ s{><\/Item>(\s*)<Item\sKey="Default"\sSelectedID="(0|1)"><}
{></Item>\n\t\t\t\t<Item Key="Default">$2<}gsmx;
}
if ($DropdownItems) {
$Setting =~ s{(<\/DefaultItem>).+(<\/Hash>\s+^[\s])}{$1$DropdownItems$2}msx;
}
# replace tab with spaces
$Setting =~ s{\t}{ }gsmx;
# FAQ.xml
# LinkObject::ComplexTable###FAQ
# ITSMTicket.xml
# Ticket::Frontend::AgentTicketAddtlITSMField###DynamicField
# Ticket::Frontend::AgentTicketDecision###DynamicField
# TicketITSMTicket.xml
# Ticket::Frontend::AgentTicketPhone###DynamicField
# Ticket::Frontend::AgentTicketEmail###DynamicField
# Ticket::Frontend::AgentTicketSearch###DynamicField
# Ticket::Frontend::AgentTicketZoom###DynamicField
# Ticket::Frontend::AgentTicketPriority###DynamicField
# Ticket::Frontend::AgentTicketClose###DynamicField
# Ticket::Frontend::AgentTicketCompose###DynamicField
# Ticket::Frontend::CustomerTicketZoom###DynamicField
}
}
# get the needed ArticleTypeMapping from a YML file
my $TaskConfig = $Self->GetTaskConfig( Module => 'MigrateArticleData' );
my %ArticleTypeMapping = %{ $TaskConfig->{ArticleTypeMapping} };
# Migrate Postmaster settings for
# PostMaster::PreFilterModule
# PostMaster::PreCreateFilterModule
# PostMaster::PostFilterModule
# PostMaster::CheckFollowUpModule
if (
$Setting =~ m{ Name="PostMaster::(PreFilter|PreCreateFilter|PostFilter|CheckFollowUp)Module\#\#\# .+ }xms
)
{
$Setting
=~ s{<Item Key="X-OTRS-ArticleType">(.*?)</Item>}{<Item Key="X-OTRS-IsVisibleForCustomer">$ArticleTypeMapping{$1}->{Visible}</Item>}g;
$Setting
=~ s{<Item Key="X-OTRS-FollowUp-ArticleType">(.*?)</Item>}{<Item Key="X-OTRS-FollowUp-IsVisibleForCustomer">$ArticleTypeMapping{$1}->{Visible}</Item>}g;
$Setting
=~ s{<Item Key="ArticleType"[^>]*>(.*?)</Item>}{<Item Key="IsVisibleForCustomer" Translatable="1">$ArticleTypeMapping{$1}->{Visible}</Item>}g;
$Setting
=~ s{<Item Key="Module">Kernel::System::PostMaster::Filter::FollowUpArticleTypeCheck</Item>}{<Item Key="Module">Kernel::System::PostMaster::Filter::FollowUpArticleVisibilityCheck</Item>}g;
}
# Remove Group.
$Setting =~ s{\s+<Group>(.*?)</Group>}{}gsmx;
# Update SubGroup to the Navigation.
$Setting =~ s{SubGroup>}{Navigation>}gsmx;
my @NavigationValues = $Setting =~ m{<Navigation>(.*?)</Navigation>}g;
if ( scalar @NavigationValues ) {
my $NavigationValue = $NavigationValues[0];
my $NavigationStr = $NavigationLookup{$NavigationValue} || $NavigationValue;
if (
scalar @NavigationValues < 2
|| !grep { $NavigationStr eq $_ } (
'Frontend::Admin::ModuleRegistration',
'Frontend::Agent::ModuleRegistration',
'Frontend::Customer::ModuleRegistration',
)
)
{
$Setting =~ s{<Navigation>.*?</Navigation>}{<Navigation>$NavigationStr</Navigation>}gsmx;
}
}
# Update Setting to the Value.
$Setting =~ s{Setting>}{Value>}gsmx;
# # Add missing RegEx to all Numbers
$Setting =~ s{<String>(\d+)</String>$}
{<Item ValueType="String" ValueRegex="^\\d+\$">$1</Item>}gsmx;
$Setting =~ s{<String\sValueRegex="">(\d+)</String>}
{<Item ValueType="String" ValueRegex="^\\d+\$">$1</Item>}gsmx;
$Setting =~ s{<String\sValueRegex="\\d\+">(\d+?)</String>}
{<Item ValueType="String" ValueRegex="^\\d+\$">$1</Item>}gsmx;
$Setting =~ s{<String\sValueRegex="\[(.*?)">(\d+)</String>}
{<Item ValueType="String" ValueRegex="^[$1">$2</Item>}gmsx;
# Update string and text-area to items with its corresponding ValueType.
$Setting =~ s{<TextArea(.*?)</TextArea>}{<Item ValueType="Textarea"$1</Item>}gsmx;
$Setting =~ s{<String(.*?)</String>}{<Item ValueType="String"$1</Item>}gsmx;
# Convert password strings
$Setting =~ s{<Item\sValueType="String"(.*?)Type="Password"(.*?)$}
{<Item ValueType="Password"$2}gsmx;
$Setting =~ s{<Item\sKey="Password">(.*?)$}
{<Item Key="Password" ValueType="Password">$1}gsmx;
# Convert TicketType to Entity
$Setting =~ s{<Item\sValueType="String"\sValueRegex=""(.*?)>Unclassified(.*?)$}
{<Item ValueType="Entity" ValueEntityType="Type"$1>Unclassified$2}gsmx;
$Setting =~ m{<ConfigItem\sName="(.*?)"}gsmx;
my $SettingName = $1;
my @SettingsUserModificationPossible = (
'Frontend::Admin::AdminNotificationEvent###RichTextHeight',
'Frontend::Admin::AdminNotificationEvent###RichTextWidth',
'Frontend::CustomerUser::Item###1-GoogleMaps',
'Frontend::CustomerUser::Item###15-OpenTickets',
'Frontend::CustomerUser::Item###16-OpenTicketsForCustomerUserLogin',
'Frontend::CustomerUser::Item###17-ClosedTickets',
'Frontend::CustomerUser::Item###18-ClosedTicketsForCustomerUserLogin',
'Frontend::CustomerUser::Item###2-Google',
'Frontend::CustomerUser::Item###2-LinkedIn',
'Frontend::CustomerUser::Item###3-XING',
'Frontend::ToolBarModule###110-Ticket::AgentTicketQueue',
'Frontend::ToolBarModule###120-Ticket::AgentTicketStatus',
'Frontend::ToolBarModule###130-Ticket::AgentTicketEscalation',
'Frontend::ToolBarModule###140-Ticket::AgentTicketPhone',
'Frontend::ToolBarModule###150-Ticket::AgentTicketEmail',
'Frontend::ToolBarModule###160-Ticket::AgentTicketProcess',
'Frontend::ToolBarModule###210-Ticket::TicketSearchProfile',
'Frontend::ToolBarModule###220-Ticket::TicketSearchFulltext',
'Frontend::ToolBarModule###230-CICSearchCustomerID',
'Frontend::ToolBarModule###240-CICSearchCustomerUser',
'Ticket::Frontend::AgentTicketBounce###StateDefault',
'Ticket::Frontend::AgentTicketBulk###ArticleTypeDefault',
'Ticket::Frontend::AgentTicketBulk###Owner',
'Ticket::Frontend::AgentTicketBulk###Priority',
'Ticket::Frontend::AgentTicketBulk###PriorityDefault',
'Ticket::Frontend::AgentTicketBulk###Responsible',
'Ticket::Frontend::AgentTicketBulk###State',
'Ticket::Frontend::AgentTicketBulk###StateDefault',
'Ticket::Frontend::AgentTicketBulk###TicketType',
'Ticket::Frontend::AgentTicketClose###ArticleTypeDefault',
'Ticket::Frontend::AgentTicketClose###Body',
'Ticket::Frontend::AgentTicketClose###InformAgent',
'Ticket::Frontend::AgentTicketClose###InvolvedAgent',
'Ticket::Frontend::AgentTicketClose###Note',
'Ticket::Frontend::AgentTicketClose###NoteMandatory',
'Ticket::Frontend::AgentTicketClose###Owner',
'Ticket::Frontend::AgentTicketClose###OwnerMandatory',
'Ticket::Frontend::AgentTicketClose###Priority',
'Ticket::Frontend::AgentTicketClose###PriorityDefault',
'Ticket::Frontend::AgentTicketClose###Queue',
'Ticket::Frontend::AgentTicketClose###Responsible',
'Ticket::Frontend::AgentTicketClose###ResponsibleMandatory',
'Ticket::Frontend::AgentTicketClose###RichTextHeight',
'Ticket::Frontend::AgentTicketClose###RichTextWidth',
'Ticket::Frontend::AgentTicketClose###Service',
'Ticket::Frontend::AgentTicketClose###ServiceMandatory',
'Ticket::Frontend::AgentTicketClose###SLAMandatory',
'Ticket::Frontend::AgentTicketClose###State',
'Ticket::Frontend::AgentTicketClose###StateDefault',
'Ticket::Frontend::AgentTicketClose###Subject',
'Ticket::Frontend::AgentTicketClose###TicketType',
'Ticket::Frontend::AgentTicketClose###Title',
'Ticket::Frontend::AgentTicketCompose###DefaultArticleType',
'Ticket::Frontend::AgentTicketCompose###StateDefault',
'Ticket::Frontend::AgentTicketCustomer::CustomerIDReadOnly',
'Ticket::Frontend::AgentTicketEmail::CustomerIDReadOnly',
'Ticket::Frontend::AgentTicketEmail###ArticleType',
'Ticket::Frontend::AgentTicketEmail###Body',
'Ticket::Frontend::AgentTicketEmail###Priority',
'Ticket::Frontend::AgentTicketEmail###RichTextHeight',
'Ticket::Frontend::AgentTicketEmail###RichTextWidth',
'Ticket::Frontend::AgentTicketEmail###ServiceMandatory',
'Ticket::Frontend::AgentTicketEmail###SLAMandatory',
'Ticket::Frontend::AgentTicketEmail###StateDefault',
'Ticket::Frontend::AgentTicketEmail###Subject',
'Ticket::Frontend::AgentTicketEmailOutbound###ArticleTypeDefault',
'Ticket::Frontend::AgentTicketEmailOutbound###RichTextHeight',
'Ticket::Frontend::AgentTicketEmailOutbound###RichTextWidth',
'Ticket::Frontend::AgentTicketEmailOutbound###StateDefault',
'Ticket::Frontend::AgentTicketEscalationView###Order::Default',
'Ticket::Frontend::AgentTicketEscalationView###SortBy::Default',
'Ticket::Frontend::AgentTicketForward###ArticleTypeDefault',
'Ticket::Frontend::AgentTicketForward###RichTextHeight',
'Ticket::Frontend::AgentTicketForward###RichTextWidth',
'Ticket::Frontend::AgentTicketForward###StateDefault',
'Ticket::Frontend::AgentTicketFreeText###ArticleTypeDefault',
'Ticket::Frontend::AgentTicketFreeText###Body',
'Ticket::Frontend::AgentTicketFreeText###InformAgent',
'Ticket::Frontend::AgentTicketFreeText###InvolvedAgent',
'Ticket::Frontend::AgentTicketFreeText###Note',
'Ticket::Frontend::AgentTicketFreeText###NoteMandatory',
'Ticket::Frontend::AgentTicketFreeText###Owner',
'Ticket::Frontend::AgentTicketFreeText###OwnerMandatory',
'Ticket::Frontend::AgentTicketFreeText###Priority',
'Ticket::Frontend::AgentTicketFreeText###PriorityDefault',
'Ticket::Frontend::AgentTicketFreeText###Queue',
'Ticket::Frontend::AgentTicketFreeText###Responsible',
'Ticket::Frontend::AgentTicketFreeText###ResponsibleMandatory',
'Ticket::Frontend::AgentTicketFreeText###RichTextHeight',
'Ticket::Frontend::AgentTicketFreeText###RichTextWidth',
'Ticket::Frontend::AgentTicketFreeText###Service',
'Ticket::Frontend::AgentTicketFreeText###ServiceMandatory',
'Ticket::Frontend::AgentTicketFreeText###SLAMandatory',
'Ticket::Frontend::AgentTicketFreeText###State',
'Ticket::Frontend::AgentTicketFreeText###StateDefault',
'Ticket::Frontend::AgentTicketFreeText###Subject',
'Ticket::Frontend::AgentTicketFreeText###TicketType',
'Ticket::Frontend::AgentTicketFreeText###Title',
'Ticket::Frontend::AgentTicketLockedView###Order::Default',
'Ticket::Frontend::AgentTicketLockedView###SortBy::Default',
'Ticket::Frontend::AgentTicketMerge###RichTextHeight',
'Ticket::Frontend::AgentTicketMerge###RichTextWidth',
'Ticket::Frontend::AgentTicketMove###Body',
'Ticket::Frontend::AgentTicketMove###NextScreen',
'Ticket::Frontend::AgentTicketMove###Note',
'Ticket::Frontend::AgentTicketMove###NoteMandatory',
'Ticket::Frontend::AgentTicketMove###Priority',
'Ticket::Frontend::AgentTicketMove###RichTextHeight',
'Ticket::Frontend::AgentTicketMove###RichTextWidth',
'Ticket::Frontend::AgentTicketMove###State',
'Ticket::Frontend::AgentTicketMove###Subject',
'Ticket::Frontend::AgentTicketNote###ArticleTypeDefault',
'Ticket::Frontend::AgentTicketNote###Body',
'Ticket::Frontend::AgentTicketNote###InformAgent',
'Ticket::Frontend::AgentTicketNote###InvolvedAgent',
'Ticket::Frontend::AgentTicketNote###Note',
'Ticket::Frontend::AgentTicketNote###NoteMandatory',
'Ticket::Frontend::AgentTicketNote###Owner',
'Ticket::Frontend::AgentTicketNote###OwnerMandatory',
'Ticket::Frontend::AgentTicketNote###Priority',
'Ticket::Frontend::AgentTicketNote###PriorityDefault',
'Ticket::Frontend::AgentTicketNote###Queue',
'Ticket::Frontend::AgentTicketNote###Responsible',
'Ticket::Frontend::AgentTicketNote###ResponsibleMandatory',
'Ticket::Frontend::AgentTicketNote###RichTextHeight',
'Ticket::Frontend::AgentTicketNote###RichTextWidth',
'Ticket::Frontend::AgentTicketNote###Service',
'Ticket::Frontend::AgentTicketNote###ServiceMandatory',
'Ticket::Frontend::AgentTicketNote###SLAMandatory',
'Ticket::Frontend::AgentTicketNote###State',
'Ticket::Frontend::AgentTicketNote###StateDefault',
'Ticket::Frontend::AgentTicketNote###Subject',
'Ticket::Frontend::AgentTicketNote###TicketType',
'Ticket::Frontend::AgentTicketNote###Title',
'Ticket::Frontend::AgentTicketQueue###Blink',
'Ticket::Frontend::AgentTicketQueue###HideEmptyQueues',
'Ticket::Frontend::AgentTicketQueue###HighlightAge1',
'Ticket::Frontend::AgentTicketQueue###HighlightAge2',
'Ticket::Frontend::AgentTicketQueue###Order::Default',
'Ticket::Frontend::AgentTicketQueue###QueueSort',
'Ticket::Frontend::AgentTicketQueue###SortBy::Default',
'Ticket::Frontend::AgentTicketSearch###Defaults###ArticleCreateTimePoint',
'Ticket::Frontend::AgentTicketSearch###Defaults###ArticleCreateTimeSlot',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Body',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Cc',
'Ticket::Frontend::AgentTicketSearch###Defaults###CustomerID',
'Ticket::Frontend::AgentTicketSearch###Defaults###CustomerUserLogin',
'Ticket::Frontend::AgentTicketSearch###Defaults###DynamicField',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_From',
'Ticket::Frontend::AgentTicketSearch###Defaults###Fulltext',
'Ticket::Frontend::AgentTicketSearch###Defaults###QueueIDs',
'Ticket::Frontend::AgentTicketSearch###Defaults###SearchInArchive',
'Ticket::Frontend::AgentTicketSearch###Defaults###StateIDs',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Subject',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketChangeTimePoint',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketChangeTimeSlot',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCloseTimePoint',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCloseTimeSlot',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCreateTimePoint',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCreateTimeSlot',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketEscalationTimePoint',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketEscalationTimeSlot',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketNumber',
'Ticket::Frontend::AgentTicketSearch###Defaults###Title',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_To',
'Ticket::Frontend::AgentTicketSearch###Order::Default',
'Ticket::Frontend::AgentTicketSearch###SortBy::Default',
'Ticket::Frontend::AgentTicketService###Order::Default',
'Ticket::Frontend::AgentTicketService###SortBy::Default',
'Ticket::Frontend::AgentTicketStatusView###Order::Default',
'Ticket::Frontend::AgentTicketStatusView###SortBy::Default',
'Ticket::Frontend::AgentTicketWatchView###Order::Default',
'Ticket::Frontend::AgentTicketWatchView###SortBy::Default',
'Ticket::Frontend::AgentTicketZoom###ProcessDisplay',
'Ticket::Frontend::HTMLArticleHeightDefault',
'Ticket::Frontend::HTMLArticleHeightMax',
'Ticket::Frontend::MaxArticlesPerPage',
'Ticket::Frontend::PendingDiffTime',
'Ticket::Frontend::PlainView',
'Ticket::Frontend::TicketArticleFilter',
'Ticket::Frontend::ZoomCollectMeta',
'Ticket::Frontend::ZoomExpandSort',
'Ticket::Frontend::ZoomRichTextForce',
'Ticket::UseArticleColors',
'Ticket::ZoomTimeDisplay',
'TimeInputFormat',
);
if ( grep { $SettingName eq $_ } @SettingsUserModificationPossible ) {
$Setting =~ s{(ConfigItem\sName=".*?")}{$1 UserModificationPossible="1"}gsmx;
}
my @SettingsUserModificationActive = (
'Frontend::ToolBarModule###110-Ticket::AgentTicketQueue',
'Frontend::ToolBarModule###120-Ticket::AgentTicketStatus',
'Frontend::ToolBarModule###130-Ticket::AgentTicketEscalation',
'Frontend::ToolBarModule###140-Ticket::AgentTicketPhone',
'Frontend::ToolBarModule###150-Ticket::AgentTicketEmail',
'Frontend::ToolBarModule###160-Ticket::AgentTicketProcess',
'Frontend::ToolBarModule###210-Ticket::TicketSearchProfile',
'Frontend::ToolBarModule###230-CICSearchCustomerID',
'Frontend::ToolBarModule###240-CICSearchCustomerUser',
'Ticket::Frontend::AgentTicketEscalationView###Order::Default',
'Ticket::Frontend::AgentTicketEscalationView###SortBy::Default',
'Ticket::Frontend::AgentTicketLockedView###Order::Default',
'Ticket::Frontend::AgentTicketLockedView###SortBy::Default',
'Ticket::Frontend::AgentTicketMove###NextScreen',
'Ticket::Frontend::AgentTicketQueue###Blink',
'Ticket::Frontend::AgentTicketQueue###HideEmptyQueues',
'Ticket::Frontend::AgentTicketQueue###Order::Default',
'Ticket::Frontend::AgentTicketQueue###QueueSort',
'Ticket::Frontend::AgentTicketQueue###SortBy::Default',
'Ticket::Frontend::AgentTicketSearch###Defaults###ArticleCreateTimePoint',
'Ticket::Frontend::AgentTicketSearch###Defaults###ArticleCreateTimeSlot',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Body',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Cc',
'Ticket::Frontend::AgentTicketSearch###Defaults###CustomerID',
'Ticket::Frontend::AgentTicketSearch###Defaults###CustomerUserLogin',
'Ticket::Frontend::AgentTicketSearch###Defaults###DynamicField',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_From',
'Ticket::Frontend::AgentTicketSearch###Defaults###Fulltext',
'Ticket::Frontend::AgentTicketSearch###Defaults###QueueIDs',
'Ticket::Frontend::AgentTicketSearch###Defaults###SearchInArchive',
'Ticket::Frontend::AgentTicketSearch###Defaults###StateIDs',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Subject',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketChangeTimePoint',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketChangeTimeSlot',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCloseTimePoint',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCloseTimeSlot',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCreateTimePoint',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCreateTimeSlot',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketEscalationTimePoint',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketEscalationTimeSlot',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketNumber',
'Ticket::Frontend::AgentTicketSearch###Defaults###Title',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_To',
'Ticket::Frontend::AgentTicketSearch###Order::Default',
'Ticket::Frontend::AgentTicketSearch###SortBy::Default',
'Ticket::Frontend::AgentTicketService###Order::Default',
'Ticket::Frontend::AgentTicketService###SortBy::Default',
'Ticket::Frontend::AgentTicketStatusView###Order::Default',
'Ticket::Frontend::AgentTicketStatusView###SortBy::Default',
'Ticket::Frontend::AgentTicketWatchView###Order::Default',
'Ticket::Frontend::AgentTicketWatchView###SortBy::Default',
'Ticket::Frontend::PendingDiffTime',
'Ticket::Frontend::ZoomExpandSort',
'Ticket::ZoomTimeDisplay',
);
if ( grep { $SettingName eq $_ } @SettingsUserModificationActive ) {
$Setting =~ s{(ConfigItem\sName=".*?")}{$1 UserModificationActive="1"}gsmx;
}
my @SettingsToDisable = (
'PGP::Bin',
'SMIME::Bin',
'SMIME::CertPath',
'SMIME::PrivatePath',
);
if ( grep { $SettingName eq $_ } @SettingsToDisable ) {
$Setting =~ s{(ConfigItem\sName=".*?"\sRequired=)"1"(\sValid=)"1"}{$1"0"$2"0"}gsmx;
}
my %SettingsUserPreferencesGroup = (
'Frontend::Admin::AdminNotificationEvent###RichTextHeight' => 'Advanced',
'Frontend::Admin::AdminNotificationEvent###RichTextWidth' => 'Advanced',
'Frontend::CustomerUser::Item###1-GoogleMaps' => 'Advanced',
'Frontend::CustomerUser::Item###15-OpenTickets' => 'Advanced',
'Frontend::CustomerUser::Item###16-OpenTicketsForCustomerUserLogin' => 'Advanced',
'Frontend::CustomerUser::Item###17-ClosedTickets' => 'Advanced',
'Frontend::CustomerUser::Item###18-ClosedTicketsForCustomerUserLogin' => 'Advanced',
'Frontend::CustomerUser::Item###2-Google' => 'Advanced',
'Frontend::CustomerUser::Item###2-LinkedIn' => 'Advanced',
'Frontend::CustomerUser::Item###3-XING' => 'Advanced',
'Frontend::ToolBarModule###110-Ticket::AgentTicketQueue' => 'Advanced',
'Frontend::ToolBarModule###120-Ticket::AgentTicketStatus' => 'Advanced',
'Frontend::ToolBarModule###130-Ticket::AgentTicketEscalation' => 'Advanced',
'Frontend::ToolBarModule###140-Ticket::AgentTicketPhone' => 'Advanced',
'Frontend::ToolBarModule###150-Ticket::AgentTicketEmail' => 'Advanced',
'Frontend::ToolBarModule###160-Ticket::AgentTicketProcess' => 'Advanced',
'Frontend::ToolBarModule###210-Ticket::TicketSearchProfile' => 'Advanced',
'Frontend::ToolBarModule###220-Ticket::TicketSearchFulltext' => 'Advanced',
'Frontend::ToolBarModule###230-CICSearchCustomerID' => 'Advanced',
'Frontend::ToolBarModule###240-CICSearchCustomerUser' => 'Advanced',
'Ticket::Frontend::AgentTicketBounce###StateDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketBulk###ArticleTypeDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketBulk###Owner' => 'Advanced',
'Ticket::Frontend::AgentTicketBulk###Priority' => 'Advanced',
'Ticket::Frontend::AgentTicketBulk###PriorityDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketBulk###Responsible' => 'Advanced',
'Ticket::Frontend::AgentTicketBulk###State' => 'Advanced',
'Ticket::Frontend::AgentTicketBulk###StateDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketBulk###TicketType' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###ArticleTypeDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###Body' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###InformAgent' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###InvolvedAgent' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###Note' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###NoteMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###Owner' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###OwnerMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###Priority' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###PriorityDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###Queue' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###Responsible' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###ResponsibleMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###RichTextHeight' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###RichTextWidth' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###Service' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###ServiceMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###SLAMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###State' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###StateDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###Subject' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###TicketType' => 'Advanced',
'Ticket::Frontend::AgentTicketClose###Title' => 'Advanced',
'Ticket::Frontend::AgentTicketCompose###DefaultArticleType' => 'Advanced',
'Ticket::Frontend::AgentTicketCompose###StateDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketCustomer::CustomerIDReadOnly' => 'Advanced',
'Ticket::Frontend::AgentTicketEmail::CustomerIDReadOnly' => 'Advanced',
'Ticket::Frontend::AgentTicketEmail###ArticleType' => 'Advanced',
'Ticket::Frontend::AgentTicketEmail###Body' => 'Advanced',
'Ticket::Frontend::AgentTicketEmail###Priority' => 'Advanced',
'Ticket::Frontend::AgentTicketEmail###RichTextHeight' => 'Advanced',
'Ticket::Frontend::AgentTicketEmail###RichTextWidth' => 'Advanced',
'Ticket::Frontend::AgentTicketEmail###ServiceMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketEmail###SLAMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketEmail###StateDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketEmail###Subject' => 'Advanced',
'Ticket::Frontend::AgentTicketEmailOutbound###ArticleTypeDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketEmailOutbound###RichTextHeight' => 'Advanced',
'Ticket::Frontend::AgentTicketEmailOutbound###RichTextWidth' => 'Advanced',
'Ticket::Frontend::AgentTicketEmailOutbound###StateDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketEscalationView###Order::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketEscalationView###SortBy::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketForward###ArticleTypeDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketForward###RichTextHeight' => 'Advanced',
'Ticket::Frontend::AgentTicketForward###RichTextWidth' => 'Advanced',
'Ticket::Frontend::AgentTicketForward###StateDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###ArticleTypeDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###Body' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###InformAgent' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###InvolvedAgent' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###Note' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###NoteMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###Owner' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###OwnerMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###Priority' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###PriorityDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###Queue' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###Responsible' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###ResponsibleMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###RichTextHeight' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###RichTextWidth' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###Service' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###ServiceMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###SLAMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###State' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###StateDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###Subject' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###TicketType' => 'Advanced',
'Ticket::Frontend::AgentTicketFreeText###Title' => 'Advanced',
'Ticket::Frontend::AgentTicketLockedView###Order::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketLockedView###SortBy::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketMerge###RichTextHeight' => 'Advanced',
'Ticket::Frontend::AgentTicketMerge###RichTextWidth' => 'Advanced',
'Ticket::Frontend::AgentTicketMove###Body' => 'Advanced',
'Ticket::Frontend::AgentTicketMove###NextScreen' => 'Advanced',
'Ticket::Frontend::AgentTicketMove###Note' => 'Advanced',
'Ticket::Frontend::AgentTicketMove###NoteMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketMove###Priority' => 'Advanced',
'Ticket::Frontend::AgentTicketMove###RichTextHeight' => 'Advanced',
'Ticket::Frontend::AgentTicketMove###RichTextWidth' => 'Advanced',
'Ticket::Frontend::AgentTicketMove###State' => 'Advanced',
'Ticket::Frontend::AgentTicketMove###Subject' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###ArticleTypeDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###Body' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###InformAgent' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###InvolvedAgent' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###Note' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###NoteMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###Owner' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###OwnerMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###Priority' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###PriorityDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###Queue' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###Responsible' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###ResponsibleMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###RichTextHeight' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###RichTextWidth' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###Service' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###ServiceMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###SLAMandatory' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###State' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###StateDefault' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###Subject' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###TicketType' => 'Advanced',
'Ticket::Frontend::AgentTicketNote###Title' => 'Advanced',
'Ticket::Frontend::AgentTicketQueue###Blink' => 'Advanced',
'Ticket::Frontend::AgentTicketQueue###HideEmptyQueues' => 'Advanced',
'Ticket::Frontend::AgentTicketQueue###HighlightAge1' => 'Advanced',
'Ticket::Frontend::AgentTicketQueue###HighlightAge2' => 'Advanced',
'Ticket::Frontend::AgentTicketQueue###Order::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketQueue###QueueSort' => 'Advanced',
'Ticket::Frontend::AgentTicketQueue###SortBy::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###ArticleCreateTimePoint' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###ArticleCreateTimeSlot' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Body' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Cc' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###CustomerID' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###CustomerUserLogin' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###DynamicField' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_From' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###Fulltext' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###QueueIDs' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###SearchInArchive' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###StateIDs' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Subject' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketChangeTimePoint' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketChangeTimeSlot' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCloseTimePoint' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCloseTimeSlot' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCreateTimePoint' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCreateTimeSlot' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketEscalationTimePoint' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketEscalationTimeSlot' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###TicketNumber' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###Title' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_To' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###Order::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketSearch###SortBy::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketService###Order::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketService###SortBy::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketStatusView###Order::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketStatusView###SortBy::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketWatchView###Order::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketWatchView###SortBy::Default' => 'Advanced',
'Ticket::Frontend::AgentTicketZoom###ProcessDisplay' => 'Advanced',
'Ticket::Frontend::HTMLArticleHeightDefault' => 'Advanced',
'Ticket::Frontend::HTMLArticleHeightMax' => 'Advanced',
'Ticket::Frontend::MaxArticlesPerPage' => 'Advanced',
'Ticket::Frontend::PendingDiffTime' => 'Advanced',
'Ticket::Frontend::PlainView' => 'Advanced',
'Ticket::Frontend::TicketArticleFilter' => 'Advanced',
'Ticket::Frontend::ZoomCollectMeta' => 'Advanced',
'Ticket::Frontend::ZoomExpandSort' => 'Advanced',
'Ticket::Frontend::ZoomRichTextForce' => 'Advanced',
'Ticket::UseArticleColors' => 'Advanced',
'Ticket::ZoomTimeDisplay' => 'Advanced',
'TimeInputFormat' => 'Advanced',
);
if ( $SettingsUserPreferencesGroup{$SettingName} ) {
$Setting
=~ s{(ConfigItem\sName=".*?")}{$1 UserPreferencesGroup="$SettingsUserPreferencesGroup{$SettingName}"}gsmx;
}
if ( $Setting =~ m{Name=\"DashboardBackend\#\#\#} ) {
$Setting =~ s{\n([ ]*)(<\/Hash>\n[ ]*<\/Value>)}{\n$1 <Item Key="Mandatory">0</Item>\n$1$2}xms;
}
}
my $Result = join( "", @Settings );
# Rename ConfigItem to Setting.
$Result =~ s{<ConfigItem}{<Setting}gsmx;
$Result =~ s{</ConfigItem}{</Setting}gsmx;
# Remove empty lines
$Result =~ s{>\n\n\s}{>\n }gsmx;
# Remove white space at the end of the file
$Result =~ s{</otrs_config>.*}{</otrs_config>}gsmx;
# Add new line at the end
$Result .= "\n";
return $Result;
}
=head2 MigrateConfigEffectiveValues()
Migrate the configs effective values to the new format for OTRS 6.
my $Result = $SysConfigMigrationObject->MigrateConfigEffectiveValues(
FileClass => $FileClass,
FilePath => $FilePath,
NoOutput => 1, # ( 0 | 1 ) optional, default 0.
# if set to 1 no info output will be printed to the screen.
PackageSettings => [ # (optional) only migrate the given package settings
'Frontend::Module###AdminGeneralCatalog',
'Frontend::NavigationModule###AdminGeneralCatalog',
'GeneralCatalogPreferences###Comment2',
'GeneralCatalogPreferences###Permissions',
'Loader::Agent::CommonJS###100-GeneralCatalog'
],
PackageLookupNewConfigName => {
'Ticket::EventModulePost###999-GenericInterface' => 'Ticket::EventModulePost###9900-GenericInterface',
},
ReturnMigratedSettingsCounts => 1, # (optional) returns an array with counts of un/successful migrated settings
);
Returns:
$Result = 1; # True on success or false on error.
# or
# if ReturnMigratedSettingsCounts parameter is set
$Result = {
AllSettingsCount => 1,
MissingSettings => [],
UnsuccessfullSettings => [],
};
=cut
sub MigrateConfigEffectiveValues {
my ( $Self, %Param ) = @_;
for my $Needed (qw(FileClass FilePath)) {
if ( !$Param{$Needed} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!",
);
return;
}
}
my $SysConfigObject = $Kernel::OM->Get('Kernel::System::SysConfig');
my %OTRS5Config;
delete $INC{ $Param{FilePath} };
$Kernel::OM->Get('Kernel::System::Main')->Require( $Param{FileClass} );
$Param{FileClass}->Load( \%OTRS5Config );
my $OTRS5ConfigFileContentList = $Kernel::OM->Get('Kernel::System::Main')->FileRead(
Location => $Param{FilePath},
Result => 'ARRAY',
);
my @DisabledOTRS5Config;
for my $Line ( @{$OTRS5ConfigFileContentList} ) {
# Check if the line starts with a delete.
if ( $Line =~ m{ \A delete[ ]\$Self->\{(.+)\};}xms ) {
my $DisabledSettingString = $1;
$DisabledSettingString =~ s{['"]}{}xmsg;
$DisabledSettingString =~ s{\}->\{}{###}xmsg;
push @DisabledOTRS5Config, $DisabledSettingString;
}
}
# get all OTRS 6 default settings
my @DefaultSettings = $SysConfigObject->ConfigurationList();
# search for settings with ### in the name
# my @SearchResult = grep /###/, sort values %DefaultSettings;
my @SearchResult = grep { $_->{Name} =~ m{###} } @DefaultSettings;
# find all the setting which have sublevels and store them in a hash for OTRS 6
my %SettingsWithSubLevelsOTRS6;
for my $Setting (@SearchResult) {
my @SettingNameParts = split /###/, $Setting->{Name};
my $FirstLevelKey = shift @SettingNameParts;
my $LastLevelKey = pop @SettingNameParts;
if (
@SettingNameParts
# Skip any setting with more than one sub-levels in hash key (unsupported in OTRS 5).
&& !defined $SettingsWithSubLevelsOTRS6{$FirstLevelKey}->{ $SettingNameParts[0] }
)
{
$SettingsWithSubLevelsOTRS6{$FirstLevelKey}->{ $SettingNameParts[0] }->{$LastLevelKey} = 1;
}
else {
$SettingsWithSubLevelsOTRS6{$FirstLevelKey}->{$LastLevelKey} = 1;
}
}
# get the needed ArticleTypeMapping from a YML file (needed for Postmaster filter settings later)
my $TaskConfig = $Self->GetTaskConfig( Module => 'MigrateArticleData' );
my %ArticleTypeMapping = %{ $TaskConfig->{ArticleTypeMapping} };
# build a lookup hash of all given package settings
my %PackageSettingLookup;
if ( IsArrayRefWithData( $Param{PackageSettings} ) ) {
%PackageSettingLookup = map { $_ => 1 } @{ $Param{PackageSettings} };
}
# to store settings which do not exist in OTRS 6
my @MissingSettings;
# to store unsuccessfull settings which could not be migrated
my @UnsuccessfullSettings;
# Add an additional mapping for 2-Level settings, which have a renamed first part.
if ( $Param{PackageLookupNewConfigName} ) {
my %AdditionalMapping;
for my $OldName ( sort keys %{ $Param{PackageLookupNewConfigName} } ) {
my $NewName = $Param{PackageLookupNewConfigName}->{$OldName};
$OldName =~ s{#.*\z}{}ms;
$NewName =~ s{#.*\z}{}ms;
$AdditionalMapping{$OldName} = $NewName;
}
%{ $Param{PackageLookupNewConfigName} } = ( %{ $Param{PackageLookupNewConfigName} }, %AdditionalMapping );
}
SETTINGNAME:
for my $SettingName ( sort keys %OTRS5Config ) {
# skip loader common settings
next SETTINGNAME if $SettingName eq 'Loader::Agent::CommonCSS';
next SETTINGNAME if $SettingName eq 'Loader::Agent::CommonJS';
next SETTINGNAME if $SettingName eq 'Loader::Customer::CommonCSS';
next SETTINGNAME if $SettingName eq 'Loader::Customer::CommonJS';
# skip no longer existing sysconfig settings
next SETTINGNAME if $SettingName eq 'CustomerPreferencesView';
next SETTINGNAME if $SettingName eq 'DisableMSIFrameSecurityRestricted';
next SETTINGNAME if $SettingName eq 'Frontend::AnimationEnabled';
next SETTINGNAME if $SettingName eq 'LogModule::SysLog::LogSock';
next SETTINGNAME if $SettingName eq 'PreferencesView';
next SETTINGNAME if $SettingName eq 'Ticket::Frontend::ComposeExcludeCcRecipients';
next SETTINGNAME if $SettingName eq 'TimeZoneUser';
next SETTINGNAME if $SettingName eq 'TimeZoneUserBrowserAutoOffset';
next SETTINGNAME if $SettingName eq 'Ticket::StorageModule';
next SETTINGNAME if $SettingName eq 'Ticket::StorageModule::CheckAllBackends';
next SETTINGNAME if $SettingName eq 'ArticleDir';
my $CheckSubLevels;
if ( $SettingsWithSubLevelsOTRS6{$SettingName} ) {
$CheckSubLevels = 1;
}
elsif (
$Param{PackageLookupNewConfigName}
&& $Param{PackageLookupNewConfigName}->{$SettingName}
&& $SettingsWithSubLevelsOTRS6{ $Param{PackageLookupNewConfigName}->{$SettingName} }
)
{
$CheckSubLevels = 1;
}
# check if this OTRS5 setting has subhashes in the name
if ($CheckSubLevels) {
SETTINGKEYFIRSTLEVEL:
for my $SettingKeyFirstLevel ( sort keys %{ $OTRS5Config{$SettingName} } ) {
# there is a second level
# example: Ticket::Frontend::AgentTicketZoom###Widgets###0100-TicketInformation
if (
$SettingsWithSubLevelsOTRS6{$SettingName}->{$SettingKeyFirstLevel}
&& IsHashRefWithData( $SettingsWithSubLevelsOTRS6{$SettingName}->{$SettingKeyFirstLevel} )
&& IsHashRefWithData( $OTRS5Config{$SettingName}->{$SettingKeyFirstLevel} )
)
{
SETTINGKEYSECONDLEVEL:
for my $SettingKeySecondLevel (
sort keys %{ $OTRS5Config{$SettingName}->{$SettingKeyFirstLevel} }
)
{
# get the effective value from the OTRS 5 config
my $OTRS5EffectiveValue
= $OTRS5Config{$SettingName}->{$SettingKeyFirstLevel}->{$SettingKeySecondLevel};
# build the new setting key
my $NewSettingKey
= $SettingName . '###' . $SettingKeyFirstLevel . '###' . $SettingKeySecondLevel;
# check and convert config name if it has been renamed in OTRS 6
# otherwise it will use the given old name
$NewSettingKey = $Self->_LookupNewConfigName(
OldName => $NewSettingKey,
PackageLookupNewConfigName => $Param{PackageLookupNewConfigName},
);
# skip settings which are not in the given package settings
if ( %PackageSettingLookup && !$PackageSettingLookup{$NewSettingKey} ) {
next SETTINGKEYSECONDLEVEL;
}
# try to get the default setting from OTRS 6 for the new setting name
my %OTRS6Setting = $SysConfigObject->SettingGet(
Name => $NewSettingKey,
NoLog => 1,
);
# skip settings which already have been modified in the meantime
next SETTINGKEYSECONDLEVEL if $OTRS6Setting{ModifiedID};
# skip this setting if it is a readonly setting
next SETTINGKEYSECONDLEVEL if $OTRS6Setting{IsReadonly};
# log if there is a setting that can not be found in OTRS 6 (might come from packages)
if ( !%OTRS6Setting ) {
push @MissingSettings, $NewSettingKey;
next SETTINGKEYSECONDLEVEL;
}
# check if the setting value structure from OTRS 5 is still valid on OTRS6
my %Result = $SysConfigObject->SettingEffectiveValueCheck(
EffectiveValue => $OTRS5EffectiveValue,
XMLContentParsed => $OTRS6Setting{XMLContentParsed},
NoValidation => 1,
UserID => 1,
);
if ( !$Result{Success} ) {
push @UnsuccessfullSettings, $NewSettingKey;
next SETTINGKEYSECONDLEVEL;
}
# update the setting.
%Result = $Self->_SettingUpdate(
Name => $NewSettingKey,
IsValid => 1,
EffectiveValue => $OTRS5EffectiveValue,
);
if ( !$Result{Success} ) {
push @UnsuccessfullSettings, $NewSettingKey;
next SETTINGKEYSECONDLEVEL;
}
}
}
# there is only one level
# example: Ticket::Frontend::AgentTicketService###StripEmptyLines
else {
# get the effective value from the OTRS 5 config
my $OTRS5EffectiveValue = $OTRS5Config{$SettingName}->{$SettingKeyFirstLevel};
# build the new setting key
my $NewSettingKey = $SettingName . '###' . $SettingKeyFirstLevel;
# Skip not longer existing settings.
if ( $NewSettingKey eq 'Ticket::Frontend::OverviewSmall###ColumnHeader' ) {
next SETTINGKEYFIRSTLEVEL;
}
# check and convert config name if it has been renamed in OTRS 6
# otherwise it will use the given old name
$NewSettingKey = $Self->_LookupNewConfigName(
OldName => $NewSettingKey,
PackageLookupNewConfigName => $Param{PackageLookupNewConfigName},
);
# skip settings which are not in the given package settings
if ( %PackageSettingLookup && !$PackageSettingLookup{$NewSettingKey} ) {
next SETTINGKEYFIRSTLEVEL;
}
# try to get the default setting from OTRS 6 for the modified setting name
my %OTRS6Setting = $SysConfigObject->SettingGet(
Name => $NewSettingKey,
NoLog => 1,
);
# skip settings which already have been modified in the meantime
next SETTINGKEYFIRSTLEVEL if $OTRS6Setting{ModifiedID};
# skip this setting if it is a readonly setting
next SETTINGKEYFIRSTLEVEL if $OTRS6Setting{IsReadonly};
# log if there is a setting that can not be found in OTRS 6 (might come from packages)
if ( !%OTRS6Setting ) {
push @MissingSettings, $NewSettingKey;
next SETTINGKEYFIRSTLEVEL;
}
# migrate frontend module registrations
if (
$SettingName eq 'Frontend::Module'
|| $SettingName eq 'CustomerFrontend::Module'
|| $SettingName eq 'PublicFrontend::Module'
)
{
# migrate (and split) the frontend module settings
my $Result = $Self->_MigrateFrontendModuleSetting(
FrontendSettingName => $SettingName,
FrontendModuleName => $SettingKeyFirstLevel,
OTRS5EffectiveValue => $OTRS5EffectiveValue,
OTRS6Setting => \%OTRS6Setting,
);
# success
next SETTINGKEYFIRSTLEVEL if $Result;
# error
push @UnsuccessfullSettings, $NewSettingKey;
next SETTINGKEYFIRSTLEVEL;
}
# migrate preferences groups settings
if ( $SettingName eq 'PreferencesGroups' ) {
# delete no longer needed column key
delete $OTRS5EffectiveValue->{Column};
# add new PreferenceGroup key from OTRS 6
$OTRS5EffectiveValue->{PreferenceGroup} = $OTRS6Setting{EffectiveValue}->{PreferenceGroup};
}
# Migrate Postmaster settings for
# PostMaster::PreFilterModule
# PostMaster::PreCreateFilterModule
# PostMaster::PostFilterModule
# PostMaster::CheckFollowUpModule
if (
$SettingName
=~ m{ \A PostMaster::(PreFilter|PreCreateFilter|PostFilter|CheckFollowUp)Module \z }xms
)
{
# update no longer existing module.
if (
$OTRS5EffectiveValue->{Module} eq
'Kernel::System::PostMaster::Filter::FollowUpArticleTypeCheck'
)
{
$OTRS5EffectiveValue->{Module}
= 'Kernel::System::PostMaster::Filter::FollowUpArticleVisibilityCheck';
}
# Define mapping for old to new keys.
my %Old2NewKeyMapping = (
'X-OTRS-ArticleType' => 'X-OTRS-IsVisibleForCustomer',
'X-OTRS-FollowUp-ArticleType' => 'X-OTRS-FollowUp-IsVisibleForCustomer',
'ArticleType' => 'IsVisibleForCustomer',
);
OLDKEY:
for my $OldKey ( sort keys %Old2NewKeyMapping ) {
my $NewKey = $Old2NewKeyMapping{$OldKey};
# Convert subentries below Match and Set.
AREA:
for my $Area (qw(Match Set)) {
next AREA if !IsHashRefWithData( $OTRS5EffectiveValue->{$Area} );
next AREA if !$OTRS5EffectiveValue->{$Area}->{$OldKey};
# Add the new key with the converted value from the old key.
$OTRS5EffectiveValue->{$Area}->{$NewKey}
= $ArticleTypeMapping{ $OTRS5EffectiveValue->{$Area}->{$OldKey} }->{Visible};
# Delete the old key.
delete $OTRS5EffectiveValue->{$Area}->{$OldKey};
}
# Convert direct entries.
next OLDKEY if !$OTRS5EffectiveValue->{$OldKey};
# Add the new key with the converted value from the old key.
$OTRS5EffectiveValue->{$NewKey}
= $ArticleTypeMapping{ $OTRS5EffectiveValue->{$OldKey} }->{Visible};
# Delete the old key.
delete $OTRS5EffectiveValue->{$OldKey};
}
}
# check if the setting value structure from OTRS 5 is still valid on OTRS6
my %Result = $SysConfigObject->SettingEffectiveValueCheck(
EffectiveValue => $OTRS5EffectiveValue,
XMLContentParsed => $OTRS6Setting{XMLContentParsed},
NoValidation => 1,
UserID => 1,
);
if ( !$Result{Success} ) {
push @UnsuccessfullSettings, $NewSettingKey;
next SETTINGKEYFIRSTLEVEL;
}
# update the setting.
%Result = $Self->_SettingUpdate(
Name => $NewSettingKey,
IsValid => 1,
EffectiveValue => $OTRS5EffectiveValue,
);
if ( !$Result{Success} ) {
push @UnsuccessfullSettings, $NewSettingKey;
next SETTINGKEYFIRSTLEVEL;
}
}
}
}
# setting has no subhashes in the name
# example: Cache::Module
else {
# skip TimeZone::Calendar settings (they are handled else where)
next SETTINGNAME if $SettingName =~ m{ \A TimeZone::Calendar[1-9] \z }xms;
# check and convert config name if it has been renamed in OTRS 6
# otherwise it will use the given old name
my $NewSettingName = $Self->_LookupNewConfigName(
OldName => $SettingName,
PackageLookupNewConfigName => $Param{PackageLookupNewConfigName},
);
# skip settings which are not in the given package settings
if ( %PackageSettingLookup && !$PackageSettingLookup{$NewSettingName} ) {
next SETTINGNAME;
}
# get the (default) setting from OTRS 6 for this setting name
my %OTRS6Setting = $SysConfigObject->SettingGet(
Name => $NewSettingName,
NoLog => 1,
);
# skip this setting if it has already been modified in the meantime
next SETTINGNAME if $OTRS6Setting{ModifiedID};
# skip this setting if it is a readonly setting
next SETTINGNAME if $OTRS6Setting{IsReadonly};
# Log if there is a setting that can not be found in OTRS 6 (might come from packages)
if ( !%OTRS6Setting ) {
push @MissingSettings, $NewSettingName;
next SETTINGNAME;
}
my $OTRS5EffectiveValue = $OTRS5Config{$SettingName};
# the ticket number generator random is dropped from OTRS 6, enforce that DateChecksum is set instead
if (
$NewSettingName eq 'Ticket::NumberGenerator'
&& $OTRS5EffectiveValue eq 'Kernel::System::Ticket::Number::Random'
)
{
$OTRS5EffectiveValue = 'Kernel::System::Ticket::Number::DateChecksum';
}
# check if the setting value structure from OTRS 5 is still valid on OTRS6
my %Result = $SysConfigObject->SettingEffectiveValueCheck(
EffectiveValue => $OTRS5EffectiveValue,
XMLContentParsed => $OTRS6Setting{XMLContentParsed},
NoValidation => 1,
UserID => 1,
);
if ( !$Result{Success} ) {
push @UnsuccessfullSettings, $NewSettingName;
next SETTINGNAME;
}
# update the setting.
%Result = $Self->_SettingUpdate(
Name => $NewSettingName,
IsValid => 1,
EffectiveValue => $OTRS5EffectiveValue,
);
if ( !$Result{Success} ) {
push @UnsuccessfullSettings, $NewSettingName;
next SETTINGNAME;
}
}
}
my $DisabledSettingsCount = 0;
# Set all settings which are disabled in OTRS 5 to disabled.
DISABLEDSETTINGNAME:
for my $DisabledSettingKey (@DisabledOTRS5Config) {
# Check and convert config name if it has been renamed in OTRS 6
# otherwise it will use the given old name.
my $NewSettingKey = $Self->_LookupNewConfigName(
OldName => $DisabledSettingKey,
PackageLookupNewConfigName => $Param{PackageLookupNewConfigName},
);
# Skip settings which are not in the given package settings.
if ( %PackageSettingLookup && !$PackageSettingLookup{$NewSettingKey} ) {
next DISABLEDSETTINGNAME;
}
# Try to get the default setting from OTRS 6 for the modified setting name.
my %OTRS6Setting = $SysConfigObject->SettingGet(
Name => $NewSettingKey,
NoLog => 1,
);
# Skip settings which already have been modified in the meantime.
next DISABLEDSETTINGNAME if $OTRS6Setting{ModifiedID};
# Skip this setting if it is a readonly setting.
next DISABLEDSETTINGNAME if $OTRS6Setting{IsReadonly};
# Skip this setting if it is a required setting.
next DISABLEDSETTINGNAME if $OTRS6Setting{IsRequired};
# Log if there is a setting that can not be found in OTRS 6 (might come from packages).
if ( !%OTRS6Setting ) {
push @MissingSettings, $NewSettingKey;
next DISABLEDSETTINGNAME;
}
# Disable the setting.
my %Result = $Self->_SettingUpdate(
Name => $NewSettingKey,
IsValid => 0,
);
if ( !$Result{Success} ) {
push @UnsuccessfullSettings, $NewSettingKey;
next DISABLEDSETTINGNAME;
}
$DisabledSettingsCount++;
}
# do not print the following status output if not wanted
return 1 if $Param{NoOutput};
my $AllSettingsCount = scalar keys %OTRS5Config;
print "\n";
print " - AllSettingsCount: " . $AllSettingsCount . "\n";
print " - DisabledCount: " . $DisabledSettingsCount . "\n";
print " - MissingCount: " . scalar @MissingSettings . "\n";
print " - UnsuccessfullCount: " . scalar @UnsuccessfullSettings . "\n\n";
if (@MissingSettings) {
print "\nMissing Settings: \n";
for my $Setting (@MissingSettings) {
print $Setting . "\n";
}
}
if (@UnsuccessfullSettings) {
print "\nUnsuccessfull Settings: \n";
for my $Setting (@UnsuccessfullSettings) {
print $Setting . "\n";
}
}
if ( $Param{ReturnMigratedSettingsCounts} ) {
return {
AllSettingsCount => $AllSettingsCount,
DisabledSettingsCount => $DisabledSettingsCount,
MissingSettings => \@MissingSettings,
UnsuccessfullSettings => \@UnsuccessfullSettings,
};
}
return 1;
}
=head2 NavigationLookupGet()
Get a list of all old Sub-Groups and the corresponding new navigation.
my %NavigationLookup = $SysConfigMigrationObject->NavigationLookupGet();
Returns:
%NavigationLookup = (
'Old::Subgroup' => 'New::Navigation',
# ...
);
=cut
sub NavigationLookupGet {
my ( $Self, %Param ) = @_;
return (
'CloudService::Admin::ModuleRegistration' => 'CloudService::Admin::ModuleRegistration',
'ConfigLog' => 'ConfigLog',
'ConfigSwitch' => 'ConfigSwitch',
'Core' => 'Core',
'Core::AppointmentCalendar::Event' => 'Core::Event::AppointmentCalendar',
'Core::Cache' => 'Core::Cache',
'Core::CustomerCompany' => 'Core::CustomerCompany',
'Core::CustomerUser' => 'Core::CustomerUser',
'Core::Daemon::ModuleRegistration' => 'Daemon::ModuleRegistration',
'Core::DynamicField' => 'Core::DynamicFields',
'Core::Fetchmail' => 'Core::Email',
'Core::FulltextSearch' => 'Core::Ticket::FulltextSearch',
'Core::LinkObject' => 'Core::LinkObject',
'Core::Log' => 'Core::Log',
'Core::MIME-Viewer' => 'Frontend::Agent::MIMEViewer',
'Core::MirrorDB' => 'Core::DB::Mirror',
'Core::OTRSBusiness' => 'Core::OTRSBusiness',
'Core::Package' => 'Core::Package',
'Core::PDF' => 'Core::PDF',
'Core::PerformanceLog' => 'Core::PerformanceLog',
'Core::PostMaster' => 'Core::Email::PostMaster',
'Core::Queue' => 'Core::Queue',
'Core::ReferenceData' => 'Core::ReferenceData',
'Core::Sendmail' => 'Core::Email',
'Core::Session' => 'Core::Session',
'Core::SOAP' => 'Core::SOAP',
'Core::Stats' => 'Core::Stats',
'Core::Ticket' => 'Core::Ticket',
'Core::TicketACL' => 'Core::Ticket::ACL',
'Core::TicketBulkAction' => 'Frontend::Agent::View::TicketBulk',
'Core::TicketDynamicFieldDefault' => 'Core::Ticket::DynamicFieldDefault',
'Core::TicketWatcher' => 'Core::Ticket',
'Core::Time' => 'Core::Time',
'Core::Time::Calendar1' => 'Core::Time::Calendar1',
'Core::Time::Calendar2' => 'Core::Time::Calendar2',
'Core::Time::Calendar3' => 'Core::Time::Calendar3',
'Core::Time::Calendar4' => 'Core::Time::Calendar4',
'Core::Time::Calendar5' => 'Core::Time::Calendar5',
'Core::Time::Calendar6' => 'Core::Time::Calendar6',
'Core::Time::Calendar7' => 'Core::Time::Calendar7',
'Core::Time::Calendar8' => 'Core::Time::Calendar8',
'Core::Time::Calendar9' => 'Core::Time::Calendar9',
'Core::Transition' => 'Core::ProcessManagement',
'Core::Web' => 'Frontend::Base',
'Core::WebUserAgent' => 'Core::WebUserAgent',
'Crypt::PGP' => 'Core::Crypt::PGP',
'Crypt::SMIME' => 'Core::Crypt::SMIME',
'CustomerInformationCenter' => 'Frontend::Agent::View::CustomerInformationCenter',
'Daemon::SchedulerCronTaskManager::Task' => 'Daemon::SchedulerCronTaskManager::Task',
'Daemon::SchedulerGenericAgentTaskManager' => 'Daemon::SchedulerGenericAgentTaskManager',
'Daemon::SchedulerGenericInterfaceTaskManager' => 'Daemon::SchedulerGenericInterfaceTaskManager',
'Daemon::SchedulerTaskWorker' => 'Daemon::SchedulerTaskWorker',
'DynamicFields::Driver::Registration' => 'Core::DynamicFields::DriverRegistration',
'DynamicFields::ObjectType::Registration' => 'Core::DynamicFields::ObjectTypeRegistration',
# 'Frontend::Admin' => 'Frontend::Admin',
'Frontend::Admin::AdminCustomerCompany' => 'Frontend::Admin::View::CustomerCompany',
'Frontend::Admin::AdminCustomerUser' => 'Frontend::Admin::View::CustomerUser',
'Frontend::Admin::AdminNotificationEvent' => 'Frontend::Admin::View::NotificationEvent',
'Frontend::Admin::AdminSelectBox' => 'Frontend::Admin::View::SelectBox',
# 'Frontend::Admin::ModuleRegistration' => 'Frontend::Admin::ModuleRegistration',
'Frontend::Admin::SearchRouter' => 'Frontend::Admin::ModuleRegistration::MainMenu::Search',
'Frontend::Agent' => 'Frontend::Agent',
'Frontend::Agent::Auth::TwoFactor' => 'Core::Auth::Agent::TwoFactor',
'Frontend::Agent::Dashboard' => 'Frontend::Agent::View::Dashboard',
'Frontend::Agent::Dashboard::EventsTicketCalendar' => 'Frontend::Agent::View::Dashboard::EventsTicketCalendar',
'Frontend::Agent::Dashboard::TicketFilters' => 'Frontend::Agent::View::Dashboard::TicketFilters',
'Frontend::Agent::LinkObject' => 'Frontend::Agent::LinkObject',
'Frontend::Agent::ModuleMetaHead' => 'Frontend::Agent',
'Frontend::Agent::ModuleNotify' => 'Frontend::Agent::FrontendNotification',
'Frontend::Agent::NavBarModule' => 'Frontend::Agent::ModuleRegistration',
'Frontend::Agent::Preferences' => 'Frontend::Agent::View::Preferences',
'Frontend::Agent::SearchRouter' => 'Frontend::Agent::ModuleRegistration::MainMenu::Search',
'Frontend::Agent::Stats' => 'Frontend::Agent::Stats',
'Frontend::Agent::Ticket::ArticleAttachmentModule' => 'Frontend::Agent::View::TicketZoom',
'Frontend::Agent::Ticket::ArticleComposeModule' => 'Frontend::Agent::ArticleComposeModule',
'Frontend::Agent::Ticket::ArticleViewModule' => 'Frontend::Agent::View::TicketZoom',
'Frontend::Agent::Ticket::ArticleViewModulePre' => 'Frontend::Agent::View::TicketZoom',
'Frontend::Agent::Ticket::MenuModule' => 'Frontend::Agent::View::TicketZoom::MenuModule',
'Frontend::Agent::Ticket::MenuModulePre' => 'Frontend::Agent::TicketOverview::MenuModule',
'Frontend::Agent::Ticket::OverviewMenuModule' => 'Frontend::Agent::TicketOverview::MenuModule',
'Frontend::Agent::Ticket::ViewBounce' => 'Frontend::Agent::View::TicketBounce',
'Frontend::Agent::Ticket::ViewBulk' => 'Frontend::Agent::View::TicketBulk',
'Frontend::Agent::Ticket::ViewClose' => 'Frontend::Agent::View::TicketClose',
'Frontend::Agent::Ticket::ViewCompose' => 'Frontend::Agent::View::TicketCompose',
'Frontend::Agent::Ticket::ViewCustomer' => 'Frontend::Agent::View::TicketCustomer',
'Frontend::Agent::Ticket::ViewEmailNew' => 'Frontend::Agent::View::TicketEmailNew',
'Frontend::Agent::Ticket::ViewEmailOutbound' => 'Frontend::Agent::View::TicketEmailOutbound',
'Frontend::Agent::Ticket::ViewEscalation' => 'Frontend::Agent::View::TicketEscalation',
'Frontend::Agent::Ticket::ViewForward' => 'Frontend::Agent::View::TicketForward',
'Frontend::Agent::Ticket::ViewFreeText' => 'Frontend::Agent::View::TicketFreeText',
'Frontend::Agent::Ticket::ViewHistory' => 'Frontend::Agent::View::TicketHistory',
'Frontend::Agent::Ticket::ViewLocked' => 'Frontend::Agent::View::TicketLocked',
'Frontend::Agent::Ticket::ViewMerge' => 'Frontend::Agent::View::TicketMerge',
'Frontend::Agent::Ticket::ViewMove' => 'Frontend::Agent::View::TicketMove',
'Frontend::Agent::Ticket::ViewNote' => 'Frontend::Agent::View::TicketNote',
'Frontend::Agent::Ticket::ViewOwner' => 'Frontend::Agent::View::TicketOwner',
'Frontend::Agent::Ticket::ViewPending' => 'Frontend::Agent::View::TicketPending',
'Frontend::Agent::Ticket::ViewPhoneInbound' => 'Frontend::Agent::View::TicketPhoneInbound',
'Frontend::Agent::Ticket::ViewPhoneNew' => 'Frontend::Agent::View::TicketPhoneNew',
'Frontend::Agent::Ticket::ViewPhoneOutbound' => 'Frontend::Agent::View::TicketPhoneOutbound',
'Frontend::Agent::Ticket::ViewPrint' => 'Frontend::Agent::View::TicketPrint',
'Frontend::Agent::Ticket::ViewPriority' => 'Frontend::Agent::View::TicketPriority',
'Frontend::Agent::Ticket::ViewProcess' => 'Frontend::Agent::View::TicketProcess',
'Frontend::Agent::Ticket::ViewQueue' => 'Frontend::Agent::View::TicketQueue',
'Frontend::Agent::Ticket::ViewResponsible' => 'Frontend::Agent::View::TicketResponsible',
'Frontend::Agent::Ticket::ViewSearch' => 'Frontend::Agent::View::TicketSearch',
'Frontend::Agent::Ticket::ViewService' => 'Frontend::Agent::View::TicketService',
'Frontend::Agent::Ticket::ViewStatus' => 'Frontend::Agent::View::TicketStatus',
'Frontend::Agent::Ticket::ViewWatch' => 'Frontend::Agent::View::TicketWatch',
'Frontend::Agent::Ticket::ViewZoom' => 'Frontend::Agent::View::TicketZoom',
'Frontend::Agent::TicketOverview' => 'Frontend::Agent::TicketOverview',
'Frontend::Agent::ToolBarModule' => 'Frontend::Agent::ToolBar',
'Frontend::Agent::ViewCustomerUserSearch' => 'Frontend::Agent::View::CustomerUserAddressBook',
'Frontend::Agent::CustomerInformationCenter' => 'Frontend::Agent::View::CustomerInformationCenter',
'Frontend::Agent::Stats' => 'Frontend::Agent::View::Stats',
'Frontend::Customer' => 'Frontend::Customer',
'Frontend::Customer::Auth' => 'Core::Auth::Customer',
'Frontend::Customer::Auth::TwoFactor' => 'Core::Auth::Customer::TwoFactor',
'Frontend::Customer::ModuleMetaHead' => 'Frontend::Customer',
'Frontend::Customer::ModuleNotify' => 'Frontend::Customer::FrontendNotification',
'Frontend::Customer::ModuleRegistration' => 'Frontend::Customer::ModuleRegistration',
'Frontend::Customer::NavBarModule' => 'Frontend::Customer::ModuleRegistration',
'Frontend::Customer::Preferences' => 'Frontend::Customer::View::Preferences',
'Frontend::Customer::Ticket::ViewNew' => 'Frontend::Customer::View::TicketMessage',
'Frontend::Customer::Ticket::ViewPrint' => 'Frontend::Customer::View::TicketPrint',
'Frontend::Customer::Ticket::ViewSearch' => 'Frontend::Customer::View::TicketSearch',
'Frontend::Customer::Ticket::ViewZoom' => 'Frontend::Customer::View::TicketZoom',
'Frontend::Customer::TicketOverview' => 'Frontend::Customer::View::TicketOverview',
'Frontend::Public' => 'Frontend::Public',
'Frontend::Public::ModuleRegistration' => 'Frontend::Public::ModuleRegistration',
'Frontend::Queue::Preferences' => 'Core::Queue',
'Frontend::Service::Preferences' => 'Core::Service',
'Frontend::SLA::Preferences' => 'Core::SLA',
'GenericInterface::Invoker::ModuleRegistration' => 'GenericInterface::Invoker::ModuleRegistration',
'GenericInterface::Mapping::ModuleRegistration' => 'GenericInterface::Mapping::ModuleRegistration',
'GenericInterface::Operation::ModuleRegistration' => 'GenericInterface::Operation::ModuleRegistration',
'GenericInterface::Operation::ResponseLoggingMaxSize' => 'GenericInterface::Operation::ResponseLoggingMaxSize',
'GenericInterface::Operation::TicketCreate' => 'GenericInterface::Operation::TicketCreate',
'GenericInterface::Operation::TicketSearch' => 'GenericInterface::Operation::TicketSearch',
'GenericInterface::Operation::TicketUpdate' => 'GenericInterface::Operation::TicketUpdate',
'GenericInterface::Transport::ModuleRegistration' => 'GenericInterface::Transport::ModuleRegistration',
'GenericInterface::Webservice' => 'GenericInterface::Webservice',
'SystemMaintenance' => 'Core::SystemMaintenance',
# Packages
'OutputFilter' => 'Frontend::Base::OutputFilter',
'Frontend::Customer::ModuleMetaHead' => 'Frontend::Customer',
'Frontend::Public::ModuleMetaHead' => 'Frontend::Public',
# OTRSBusiness
'Core::NotificationEvent' => 'Frontend::Agent::View::NotificationView',
'Core::NotificationView' => 'Frontend::Agent::View::NotificationView',
'Core::NotificationView::BulkAction' => 'Frontend::Agent::View::NotificationView',
'Frontend::Agent::NotificationView' => 'Frontend::Agent::View::NotificationView',
'Frontend' => 'Frontend::Base',
'Frontend::Admin::AdminContactWithData' => 'Frontend::Admin::View::ContactWithData',
);
}
=head1 PRIVATE INTERFACE
=head2 _LookupNewConfigName()
Helper function to lookup new config names for configuration settings
where the name has been changed from OTRS 5 to OTRS 6.
my $NewName = $SysConfigMigrationObject->_LookupNewConfigName(
OldName => 'CustomerCompany::EventModulePost###100-UpdateCustomerUsers',
);
Returns:
True on success or false on error.
=cut
sub _LookupNewConfigName {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{OldName} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need OldName!",
);
return;
}
# mapping table: old name -> new name
my %Old2NewName = (
'CustomerCompany::EventModulePost###100-UpdateCustomerUsers' =>
'CustomerCompany::EventModulePost###2000-UpdateCustomerUsers',
'CustomerCompany::EventModulePost###110-UpdateTickets' =>
'CustomerCompany::EventModulePost###2300-UpdateTickets',
'CustomerCompany::EventModulePost###1000-GenericInterface' =>
'CustomerCompany::EventModulePost###9900-GenericInterface',
'CustomerUser::EventModulePost###100-UpdateDynamicFieldObjectName' =>
'CustomerUser::EventModulePost###2000-UpdateDynamicFieldObjectName',
'CustomerUser::EventModulePost###100-UpdateSearchProfiles' =>
'CustomerUser::EventModulePost###2100-UpdateSearchProfiles',
'CustomerUser::EventModulePost###100-UpdateServiceMembership' =>
'CustomerUser::EventModulePost###2200-UpdateServiceMembership',
'CustomerUser::EventModulePost###1000-GenericInterface' =>
'CustomerUser::EventModulePost###9900-GenericInterface',
'CustomerUser::EventModulePost###120-UpdateTickets' =>
'CustomerUser::EventModulePost###2300-UpdateTickets',
'DynamicField::EventModulePost###1000-GenericInterface' =>
'DynamicField::EventModulePost###9900-GenericInterface',
'Frontend::NotifyModule###5-Ticket::TicketEscalation' =>
'Frontend::NotifyModule###5000-Ticket::TicketEscalation',
'Frontend::NotifyModule###100-CloudServicesDisabled' =>
'Frontend::NotifyModule###1000-CloudServicesDisabled',
'Frontend::NotifyModule###100-OTRSBusiness' =>
'Frontend::NotifyModule###1100-OTRSBusiness',
'Frontend::NotifyModule###200-UID-Check' =>
'Frontend::NotifyModule###2000-UID-Check',
'Frontend::NotifyModule###250-AgentSessionLimit' =>
'Frontend::NotifyModule###2500-AgentSessionLimit',
'Frontend::NotifyModule###300-ShowAgentOnline' =>
'Frontend::NotifyModule###3000-ShowAgentOnline',
'Frontend::NotifyModule###400-ShowCustomerOnline' =>
'Frontend::NotifyModule###4000-ShowCustomerOnline',
'Frontend::NotifyModule###500-OutofOffice-Check' =>
'Frontend::NotifyModule###5500-OutofOffice-Check',
'Frontend::NotifyModule###600-SystemMaintenance-Check' =>
'Frontend::NotifyModule###6000-SystemMaintenance-Check',
'Frontend::NotifyModule###700-AgentTimeZone-Check' =>
'Frontend::NotifyModule###7000-AgentTimeZone-Check',
'Frontend::NotifyModule###800-Daemon-Check' =>
'Frontend::NotifyModule###8000-Daemon-Check',
'Frontend::NotifyModule###900-Generic' =>
'Frontend::NotifyModule###9000-Generic',
'Frontend::ToolBarModule###1-Ticket::AgentTicketQueue' =>
'Frontend::ToolBarModule###110-Ticket::AgentTicketQueue',
'Frontend::ToolBarModule###2-Ticket::AgentTicketStatus' =>
'Frontend::ToolBarModule###120-Ticket::AgentTicketStatus',
'Frontend::ToolBarModule###3-Ticket::AgentTicketEscalation' =>
'Frontend::ToolBarModule###130-Ticket::AgentTicketEscalation',
'Frontend::ToolBarModule###4-Ticket::AgentTicketPhone' =>
'Frontend::ToolBarModule###140-Ticket::AgentTicketPhone',
'Frontend::ToolBarModule###5-Ticket::AgentTicketEmail' =>
'Frontend::ToolBarModule###150-Ticket::AgentTicketEmail',
'Frontend::ToolBarModule###6-Ticket::AgentTicketProcess' =>
'Frontend::ToolBarModule###160-Ticket::AgentTicketProcess',
'Frontend::ToolBarModule###7-Ticket::TicketResponsible' =>
'Frontend::ToolBarModule###170-Ticket::TicketResponsible',
'Frontend::ToolBarModule###8-Ticket::TicketWatcher' =>
'Frontend::ToolBarModule###180-Ticket::TicketWatcher',
'Frontend::ToolBarModule###9-Ticket::TicketLocked' =>
'Frontend::ToolBarModule###190-Ticket::TicketLocked',
'Frontend::ToolBarModule###10-Ticket::AgentTicketService' =>
'Frontend::ToolBarModule###200-Ticket::AgentTicketService',
'Frontend::ToolBarModule###11-Ticket::TicketSearchProfile' =>
'Frontend::ToolBarModule###210-Ticket::TicketSearchProfile',
'Frontend::ToolBarModule###12-Ticket::TicketSearchFulltext' =>,
'Frontend::ToolBarModule###220-Ticket::TicketSearchFulltext',
'Frontend::ToolBarModule###13-CICSearchCustomerID' =>
'Frontend::ToolBarModule###230-CICSearchCustomerID',
'Frontend::ToolBarModule###14-CICSearchCustomerUser' =>
'Frontend::ToolBarModule###240-CICSearchCustomerUser',
'Package::EventModulePost###1000-GenericInterface' =>
'Package::EventModulePost###9900-GenericInterface',
'Package::EventModulePost###99-SupportDataSend' =>
'Package::EventModulePost###9000-SupportDataSend',
'Queue::EventModulePost###1000-GenericInterface' =>
'Queue::EventModulePost###9900-GenericInterface',
'Queue::EventModulePost###130-UpdateQueue' =>
'Queue::EventModulePost###2300-UpdateQueue',
'Ticket::EventModulePost###100-ArchiveRestore' =>
'Ticket::EventModulePost###2300-ArchiveRestore',
'Ticket::EventModulePost###110-AcceleratorUpdate' =>
'Ticket::EventModulePost###2600-AcceleratorUpdate',
'Ticket::EventModulePost###120-ForceOwnerResetOnMove' =>
'Ticket::EventModulePost###2700-ForceOwnerResetOnMove',
'Ticket::EventModulePost###130-ForceStateChangeOnLock' =>
'Ticket::EventModulePost###2800-ForceStateChangeOnLock',
'Ticket::EventModulePost###140-ResponsibleAutoSet' =>
'Ticket::EventModulePost###3000-ResponsibleAutoSet',
'Ticket::EventModulePost###150-TicketPendingTimeReset' =>
'Ticket::EventModulePost###3300-TicketPendingTimeReset',
'Ticket::EventModulePost###500-NotificationEvent' =>
'Ticket::EventModulePost###7000-NotificationEvent',
'Ticket::EventModulePost###900-GenericAgent' =>
'Ticket::EventModulePost###9700-GenericAgent',
'Ticket::EventModulePost###910-EscalationIndex' =>
'Ticket::EventModulePost###6000-EscalationIndex',
'Ticket::EventModulePost###920-EscalationStopEvents' =>
'Ticket::EventModulePost###4300-EscalationStopEvents',
'Ticket::EventModulePost###930-ForceUnlockOnMove' =>
'Ticket::EventModulePost###3600-ForceUnlockOnMove',
'Ticket::EventModulePost###940-TicketArticleNewMessageUpdate' =>
'Ticket::EventModulePost###4000-TicketArticleNewMessageUpdate',
'Ticket::EventModulePost###950-DynamicFieldFromCustomerUser' =>
'Ticket::EventModulePost###4100-DynamicFieldFromCustomerUser',
'Ticket::EventModulePost###998-TicketProcessTransitions' =>
'Ticket::EventModulePost###9800-TicketProcessTransitions',
'Ticket::EventModulePost###999-GenericInterface' =>
'Ticket::EventModulePost###9900-GenericInterface',
'Ticket::EventModulePost###TicketDynamicFieldDefault' =>
'Ticket::EventModulePost###9600-TicketDynamicFieldDefault',
'Ticket::Frontend::ArticleComposeModule###1-SignEmail' =>
'Ticket::Frontend::ArticleComposeModule###2-SignEmail',
'Ticket::Frontend::ArticleComposeModule###2-CryptEmail' =>
'Ticket::Frontend::ArticleComposeModule###3-CryptEmail',
'Ticket::Frontend::ArticlePreViewModule###1-SMIME' =>
'Ticket::Frontend::ArticlePreViewModule###2-SMIME',
'PostMaster::PreCreateFilterModule###000-FollowUpArticleTypeCheck' =>
'PostMaster::PreCreateFilterModule###000-FollowUpArticleVisibilityCheck',
'Ticket::Frontend::AgentTicketSearch###Defaults###From' =>
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_From',
'Ticket::Frontend::AgentTicketSearch###Defaults###To' =>
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_To',
'Ticket::Frontend::AgentTicketSearch###Defaults###Cc' =>
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Cc',
'Ticket::Frontend::AgentTicketSearch###Defaults###Subject' =>
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Subject',
'Ticket::Frontend::AgentTicketSearch###Defaults###Body' =>
'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Body',
# Moved and renamed config setting from OTRSBusiness.xml to Framework.xml
'ChatEngine::AgentOnlineThreshold' => 'SessionAgentOnlineThreshold',
# Moved and renamed config setting from OTRSBusiness.xml to Framework.xml
'ChatEngine::CustomerOnlineThreshold' => 'SessionCustomerOnlineThreshold',
%{ $Param{PackageLookupNewConfigName} // {} },
);
# get the new name if found, otherwise use the given old name
my $NewName = $Old2NewName{ $Param{OldName} } || $Param{OldName};
return $NewName;
}
=head2 _MigrateFrontendModuleSetting()
Helper function to migrate a frontend module setting from OTRS 5 to OTRS 6.
my $NewName = $SysConfigMigrationObject->_MigrateFrontendModuleSetting(
FrontendSettingName => 'Frontend::Module',
FrontendModuleName => 'AgentTicketQueue',
OTRS5EffectiveValue => {
'Description' => 'Overview of all open Tickets.',
'Group' => [ 'users', 'admin' ],
'GroupRo' => [ 'stats' ],
'Loader' => {
'CSS' => [
'Core.AgentTicketQueue.css',
'Core.AllocationList.css'
],
'JavaScript' => [
'Core.UI.AllocationList.js',
'Core.Agent.TableFilters.js'
],
},
'NavBar' => [
{
'AccessKey' => 'o',
'Block' => '',
'Description' => 'Overview of all open Tickets. xxx xxx',
'Link' => 'Action=AgentTicketQueue',
'LinkOption' => '',
'Name' => 'Queue view',
'NavBar' => 'Ticket',
'Prio' => '100',
'Type' => ''
},
{
'AccessKey' => 't',
'Block' => 'ItemArea',
'Description' => 'xxx',
'Link' => 'Action=AgentTicketQueue',
'LinkOption' => '',
'Name' => 'Tickets',
'NavBar' => 'Ticket',
'Prio' => '200',
'Type' => 'Menu'
}
],
'NavBarName' => 'Ticket',
'Title' => 'QueueView',
},
OTRS6Setting => \%OTRS6Setting,
);
Returns:
True on success or false on error.
=cut
sub _MigrateFrontendModuleSetting {
my ( $Self, %Param ) = @_;
# check needed stuff
for my $Needed (qw(FrontendSettingName FrontendModuleName OTRS5EffectiveValue OTRS6Setting)) {
if ( !$Param{$Needed} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!",
);
return;
}
}
# get the group settings from OTRS 5 config
my @Group = @{ $Param{OTRS5EffectiveValue}->{Group} || [] };
my @GroupRo = @{ $Param{OTRS5EffectiveValue}->{GroupRo} || [] };
my $SysConfigObject = $Kernel::OM->Get('Kernel::System::SysConfig');
# ###########################################################################
# migrate the frontend module setting
# (it will contain only the registration,
# loader and navigation settings will be separate settings now)
# ###########################################################################
# set some attributes from OTRS 5
ATTRIBUTE:
for my $Attribute (qw(Description Title NavBarName)) {
next ATTRIBUTE if !$Param{OTRS5EffectiveValue}->{$Attribute};
$Param{OTRS6Setting}->{EffectiveValue}->{$Attribute} = $Param{OTRS5EffectiveValue}->{$Attribute};
}
# set group settings from OTRS 5
$Param{OTRS6Setting}->{EffectiveValue}->{Group} = \@Group;
$Param{OTRS6Setting}->{EffectiveValue}->{GroupRo} = \@GroupRo;
# check if the setting value structure from OTRS 5 is still valid on OTRS 6
my %Result = $SysConfigObject->SettingEffectiveValueCheck(
EffectiveValue => $Param{OTRS5EffectiveValue},
XMLContentParsed => $Param{OTRS6Setting}->{XMLContentParsed},
NoValidation => 1,
UserID => 1,
);
return if !$Result{Success};
# lock the setting
my $ExclusiveLockGUID = $SysConfigObject->SettingLock(
Name => $Param{OTRS6Setting}->{Name},
Force => 1,
UserID => 1,
);
# update the setting
%Result = $SysConfigObject->SettingUpdate(
Name => $Param{OTRS6Setting}->{Name},
IsValid => 1,
EffectiveValue => $Param{OTRS6Setting}->{EffectiveValue},
ExclusiveLockGUID => $ExclusiveLockGUID,
NoValidation => 1,
UserID => 1,
);
# unlock the setting again
$SysConfigObject->SettingUnlock(
Name => $Param{OTRS6Setting}->{Name},
);
return if !$Result{Success};
# ###########################################################################
# migrate the NavBarModule settings
# ###########################################################################
if ( $Param{OTRS5EffectiveValue}->{NavBarModule} ) {
my $NavBarModuleSettingName = 'Frontend::NavigationModule###' . $Param{FrontendModuleName};
# try to get the (default) setting from OTRS 6 for the NavBarModule setting
my %OTRS6NavBarModuleSetting = $SysConfigObject->SettingGet(
Name => $NavBarModuleSettingName,
NoLog => 1,
);
if (
%OTRS6NavBarModuleSetting
&& !$OTRS6NavBarModuleSetting{ModifiedID}
&& !$OTRS6NavBarModuleSetting{IsReadonly}
)
{
# set group settings from OTRS 5
$OTRS6NavBarModuleSetting{EffectiveValue}->{Group} = \@Group;
$OTRS6NavBarModuleSetting{EffectiveValue}->{GroupRo} = \@GroupRo;
# take NavBarModule settings from OTRS 5
for my $Attribute ( sort keys %{ $Param{OTRS5EffectiveValue}->{NavBarModule} } ) {
$OTRS6NavBarModuleSetting{EffectiveValue}->{$Attribute}
= $Param{OTRS5EffectiveValue}->{NavBarModule}->{$Attribute};
}
# lock the setting
my $ExclusiveLockGUID = $SysConfigObject->SettingLock(
Name => $NavBarModuleSettingName,
Force => 1,
UserID => 1,
);
# update the setting
my %Result = $SysConfigObject->SettingUpdate(
Name => $NavBarModuleSettingName,
IsValid => 1,
EffectiveValue => $OTRS6NavBarModuleSetting{EffectiveValue},
ExclusiveLockGUID => $ExclusiveLockGUID,
NoValidation => 1,
UserID => 1,
);
# unlock the setting again
$SysConfigObject->SettingUnlock(
Name => $NavBarModuleSettingName,
);
return if !$Result{Success};
}
}
# ###########################################################################
# migrate the NavBar settings
# ###########################################################################
# Skip navbar items if name is empty.
my @OTRS5NavBar = grep {
defined $_->{Name} && length $_->{Name}
} @{ $Param{OTRS5EffectiveValue}->{NavBar} || [] };
if (@OTRS5NavBar) {
# get all OTRS 6 default settings
my @DefaultSettings = $SysConfigObject->ConfigurationList();
# search for OTRS 6 NavBar settings
#
# this will find settings like:
# Frontend::Navigation###
# CustomerFrontend::Navigation###
# PublicFrontend::Navigation###
#
$Param{FrontendSettingName} =~ s{Frontend::Module}{Frontend::Navigation}gsmx;
my $Search = $Param{FrontendSettingName} . '###' . $Param{FrontendModuleName} . '###';
my @SearchResult = grep { $_->{Name} =~ m{$Search} } @DefaultSettings;
if ( scalar @SearchResult == 1 ) {
# try to get the (default) setting from OTRS 6 for the NavBar setting
my %OTRS6NavBarSetting = $SysConfigObject->SettingGet(
Name => $SearchResult[0]->{Name},
NoLog => 1,
);
return if !%OTRS6NavBarSetting;
# skip this setting if it has already been modified in the meantime
return 1 if $OTRS6NavBarSetting{ModifiedID};
# skip this setting if it is a readonly setting
return 1 if $OTRS6NavBarSetting{IsReadonly};
$OTRS6NavBarSetting{EffectiveValue} = [];
for my $OTRS5NavBarItem (@OTRS5NavBar) {
if ( !$OTRS5NavBarItem->{Group} ) {
$OTRS5NavBarItem->{Group} = \@Group;
}
if ( !$OTRS5NavBarItem->{GroupRo} ) {
$OTRS5NavBarItem->{GroupRo} = \@GroupRo;
}
push @{ $OTRS6NavBarSetting{EffectiveValue} }, $OTRS5NavBarItem;
}
# Save the updated effective value for the current setting.
my %Result = $Self->_SettingUpdate(
Name => $SearchResult[0]->{Name},
EffectiveValue => $OTRS6NavBarSetting{EffectiveValue},
IsValid => 1,
UserID => 1,
);
return if !$Result{Success};
}
}
# No NavBar entries exists in OTRS 5 config for the frontend modulel, so we disable all nav bar settings
# for this frontend navigation.
else {
# get all OTRS 6 default settings
my @DefaultSettings = $SysConfigObject->ConfigurationList();
# search for OTRS 6 NavBar settings
#
# this will find settings like:
# Frontend::Navigation###
# CustomerFrontend::Navigation###
# PublicFrontend::Navigation###
#
$Param{FrontendSettingName} =~ s{Frontend::Module}{Frontend::Navigation}gsmx;
my $Search = $Param{FrontendSettingName} . '###' . $Param{FrontendModuleName} . '###';
my @SearchResult = grep { $_->{Name} =~ m{$Search} } @DefaultSettings;
NAVBARSETTING:
for my $NavBarSetting (@SearchResult) {
my $NavBarSettingName = $NavBarSetting->{Name};
# try to get the (default) setting from OTRS 6 for the NavBar setting
my %OTRS6NavBarSetting = $SysConfigObject->SettingGet(
Name => $NavBarSettingName,
NoLog => 1,
);
next NAVBARSETTING if !%OTRS6NavBarSetting;
# skip this setting if it is already invalid
next NAVBARSETTING if !$OTRS6NavBarSetting{IsValid};
# skip this setting if it has already been modified in the meantime
next NAVBARSETTING if $OTRS6NavBarSetting{ModifiedID};
# skip this setting if it is a readonly setting
next NAVBARSETTING if $OTRS6NavBarSetting{IsReadonly};
# skip this setting if it is a required setting
next NAVBARSETTING if $OTRS6NavBarSetting{IsRequired};
# Disable the setting.
my %Result = $Self->_SettingUpdate(
Name => $NavBarSettingName,
IsValid => 0,
);
return if !$Result{Success};
}
}
return 1;
}
=head2 _SettingUpdate()
This method locks provided settings(by force), updates them and unlock the setting.
my %Result = $SysConfigMigrationObject->_SettingUpdate(
Name => 'Setting::Name',
IsValid => 1, # (optional) 1 or 0, modified 0
EffectiveValue => $SettingEffectiveValue, # (optional)
);
Returns:
%Result = (
Success => 1, # or false in case of an error
Error => undef, # error message
);
=cut
sub _SettingUpdate {
my ( $Self, %Param ) = @_;
return if !$Param{Name};
my $SysConfigObject = $Kernel::OM->Get('Kernel::System::SysConfig');
# lock the setting
my $ExclusiveLockGUID = $SysConfigObject->SettingLock(
Name => $Param{Name},
Force => 1,
UserID => 1,
);
# Disable the setting.
my %Result = $SysConfigObject->SettingUpdate(
Name => $Param{Name},
IsValid => $Param{IsValid},
EffectiveValue => $Param{EffectiveValue},
ExclusiveLockGUID => $ExclusiveLockGUID,
NoValidation => 1,
UserID => 1,
);
# unlock the setting again
$SysConfigObject->SettingUnlock(
Name => $Param{Name},
);
return %Result;
}
1;
=head1 TERMS AND CONDITIONS
This software is part of the OTRS project (L<https://otrs.org/>).
This software comes with ABSOLUTELY NO WARRANTY. For details, see
the enclosed file COPYING for license information (GPL). If you
did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
=cut