# --
# 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 => '
...
',
Name => 'Framework',
);
Returns:
$Result = '
...
';
=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{", $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{^(} ) {
$Setting =~ s{- }{
- }gsmx;
}
# Check if FrontendModuleReg.
if ( $Setting =~ m{} ) {
# Extract Loader and delete.
my $Loader;
if ( $Setting =~ s{\s+(.*?)$}{}gsmx ) {
$Loader = $1;
}
# Extract NavBar and delete
my $NavBar;
if ( $Setting =~ s{\s+(.*)$}{}gsmx ) {
$NavBar = "\n$1\n";
}
# Extract NavBarModule and delete
my $NavBarModule;
if ( $Setting =~ s{\s+(.*?)$}{}gsmx ) {
$NavBarModule = $1;
}
# Extract FrontendModuleReg and delete.
$Setting =~ s{(.*?)}{}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>}{
- }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{(.*?)
}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+).*?$}{$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, "",
"- \n";
$ArrayItems .= sprintf "%-*s%s", 24, "",
"\n";
for my $ArrayItem ( @{ $GroupItems{$Key} } ) {
if ($ArrayItem) {
$ArrayItems .= sprintf "%-*s%s", 28, "",
"
- $ArrayItem
\n";
}
}
$ArrayItems .= sprintf "%-*s%s", 24, "",
"\n";
$ArrayItems .= sprintf "%-*s%s", 20, "",
" ";
$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{- \n";
$MissingTag .= sprintf "%-*s%s", 24, "",
"\n";
$MissingTag .= sprintf "%-*s%s", 24, "",
"\n";
$MissingTag .= sprintf "%-*s%s", 20, "",
"
\n";
# prepend
$FrontendModuleReg = $MissingTag .= $FrontendModuleReg;
}
}
# check if NavBarName exists
if ( $FrontendModuleReg !~ m{ \n";
$FrontendModuleReg .= sprintf "%-*s", 16, "";
}
my $FirstCharacter = substr $FrontendModuleReg, 0, 1;
if ( $FirstCharacter ne "\n" ) {
$FrontendModuleReg = "\n$FrontendModuleReg";
}
my $Value = "\n";
$Value .= sprintf "%-*s%s", 12, "", "- \n";
$Value .= sprintf "%-*s%s", 16, "", "";
$Value .= $FrontendModuleReg;
$Value .= "\n";
$Value .= sprintf "%-*s%s", 12, "", "
\n";
$Value .= sprintf "%-*s%s", 8, "", "";
$Setting =~ s{.*?}{$Value}gsmx;
# Put Loader stuff in a separated setting.
if (
$Loader
&& $Setting =~ m{}gsmx
)
{
my $LoaderSetting = sprintf "%-*s%s", 4, "", "";
my $LoaderName = ( $InitToLoaderMapping{$Init} // '005-' )
. $Param{Name};
$LoaderSetting =~ s{Name=".*?\#\#\#(.*?)" (.*?)>}{Name="Loader::Module::$1###$LoaderName"$2>}gsmx;
$LoaderSetting .= sprintf(
"\n%-*s%s",
8,
"",
"Loader module registration for the agent interface."
);
if ( $Setting =~ m{(.*?)} ) {
my $NavigationStr = $NavigationLookup{$1} || $1;
$NavigationStr .= "::Loader";
$LoaderSetting .= sprintf( "\n%-*s%s", 8, "", "$NavigationStr" );
}
$LoaderSetting .= sprintf( "\n%-*s%s", 8, "", "" );
$LoaderSetting .= sprintf( "\n%-*s%s", 12, "", "" );
my @LoaderLines = split( "\n", $Loader );
my ( @CSS, @JS );
# Check for CSS and JS content.
for my $Line (@LoaderLines) {
if ( $Line =~ m{(.*?)} ) {
push @CSS, $1;
}
if ( $Line =~ m{(.*?)} ) {
push @JS, $1;
}
}
if ( scalar @CSS ) {
$LoaderSetting .= sprintf( "\n%-*s%s", 16, "", "- " );
$LoaderSetting .= sprintf( "\n%-*s%s", 20, "", "" );
}
for my $CSSItem (@CSS) {
$LoaderSetting .= sprintf( "\n%-*s%s", 24, "", "
- $CSSItem
" );
}
if ( scalar @CSS ) {
$LoaderSetting .= sprintf( "\n%-*s%s", 20, "", "" );
$LoaderSetting .= sprintf( "\n%-*s%s", 16, "", " " );
}
if ( scalar @JS ) {
$LoaderSetting .= sprintf( "\n%-*s%s", 16, "", "- " );
$LoaderSetting .= sprintf( "\n%-*s%s", 20, "", "" );
}
for my $JSItem (@JS) {
$LoaderSetting .= sprintf( "\n%-*s%s", 24, "", "
- $JSItem
" );
}
if ( scalar @JS ) {
$LoaderSetting .= sprintf( "\n%-*s%s", 20, "", "" );
$LoaderSetting .= sprintf( "\n%-*s%s", 16, "", " " );
}
$LoaderSetting .= sprintf( "\n%-*s%s", 12, "", "" );
$LoaderSetting .= sprintf( "\n%-*s%s", 8, "", "" );
$LoaderSetting .= sprintf( "\n%-*s%s", 4, "", "" );
$Setting .= "\n" . $LoaderSetting;
}
if ( $NavBar && $Setting =~ m{}gsmx ) {
my $Name = $1;
my $Options = $2;
my @NavBars = split m{<\/NavBar>\s+?\n";
$Navigation .= sprintf "%-*s%s", 8, "",
"Main menu item registration.";
if ( $Setting =~ m{(.*?)} ) {
my $NavigationStr = $NavigationLookup{$1} || $1;
$NavigationStr .= "::MainMenu";
$Navigation .= sprintf( "\n%-*s%s", 8, "", "$NavigationStr" );
}
$Navigation .= sprintf( "\n%-*s%s", 8, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 12, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 16, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 20, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 20, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 16, "", "" );
for my $NavBarItem (@NavBars) {
$Navigation .= sprintf( "\n%-*s%s", 16, "", "- " );
$Navigation .= sprintf( "\n%-*s%s", 20, "", "" );
for my $NavBarTag (qw(Group GroupRo)) {
my @Items;
while ( $NavBarItem =~ s{<$NavBarTag>(.*?)<\/$NavBarTag}{}smx ) {
push @Items, $1;
}
$Navigation .= sprintf( "\n%-*s%s", 24, "", "
- " );
$Navigation .= sprintf( "\n%-*s%s", 28, "", "" );
for my $Value (@Items) {
$Navigation .= sprintf( "\n%-*s%s", 32, "", "
- $Value
" );
}
if (
!scalar @Items
&& $GroupItems{$NavBarTag}
)
{
# take group items from FrontendModuleReg
for my $Value ( @{ $GroupItems{$NavBarTag} } ) {
if ($Value) {
$Navigation .= sprintf( "\n%-*s%s", 32, "", "- $Value
" );
}
}
}
$Navigation .= sprintf( "\n%-*s%s", 28, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 24, "", " " );
}
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, "",
"- $Value
",
);
}
$Navigation .= sprintf( "\n%-*s%s", 20, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 16, "", " " );
}
$Navigation .= sprintf( "\n%-*s%s", 12, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 8, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 4, "", "\n" ); # We rename ConfigItems later
$Setting .= "\n" . $Navigation;
}
elsif ( !$NavBar && $Setting =~ m{}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, "", "\n";
$Navigation .= sprintf "%-*s%s", 8, "",
"Main menu item registration.";
if ( $Setting =~ m{(.*?)} ) {
my $NavigationStr = $NavigationLookup{$1} || $1;
$NavigationStr .= "::MainMenu";
$Navigation .= sprintf( "\n%-*s%s", 8, "", "$NavigationStr" );
}
$Navigation .= sprintf( "\n%-*s%s", 8, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 12, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 16, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 20, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 20, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 16, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 12, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 8, "", "" );
$Navigation .= sprintf( "\n%-*s%s", 4, "", "\n" ); # We rename ConfigItems later
$Setting .= "\n" . $Navigation;
}
}
if ( $NavBarModule && $Setting =~ m{}gsmx ) {
# FrontendNavigationModule
my $Name = $1;
my $Options = $2;
$Name =~ s{Frontend::Module}{Frontend::NavigationModule}gsmx;
my $NavigationModule = sprintf "%-*s%s", 4, "", "\n";
$NavigationModule .= sprintf "%-*s%s", 8, "",
"Admin area navigation for the agent interface.";
if ( $Setting =~ m{(.*?)} ) {
my $NavigationStr = $NavigationLookup{$1} || $1;
$NavigationStr .= '::AdminOverview';
$NavigationModule .= sprintf( "\n%-*s%s", 8, "", "$NavigationStr" );
}
$NavigationModule .= sprintf( "\n%-*s%s", 8, "", "" );
$NavigationModule .= sprintf( "\n%-*s%s", 12, "", "" );
for my $NavBarTag (qw(Group GroupRo)) {
my @Items;
while ( $NavBarModule =~ s{<$NavBarTag>(.*?)<\/$NavBarTag}{}smx ) {
push @Items, $1;
}
$NavigationModule .= sprintf( "\n%-*s%s", 16, "", "- " );
$NavigationModule .= sprintf( "\n%-*s%s", 20, "", "" );
for my $Value (@Items) {
$NavigationModule .= sprintf( "\n%-*s%s", 24, "", "
- $Value
" );
}
if (
!scalar @Items
&& $GroupItems{$NavBarTag}
)
{
# take group items from FrontendModuleReg
for my $Value ( @{ $GroupItems{$NavBarTag} } ) {
if ($Value) {
$NavigationModule .= sprintf( "\n%-*s%s", 24, "", "- $Value
" );
}
}
}
$NavigationModule .= sprintf( "\n%-*s%s", 20, "", "" );
$NavigationModule .= sprintf( "\n%-*s%s", 16, "", " " );
}
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, "",
"- $Value
",
);
}
$NavigationModule .= sprintf( "\n%-*s%s", 12, "", "" );
$NavigationModule .= sprintf( "\n%-*s%s", 8, "", "" );
$NavigationModule .= sprintf( "\n%-*s%s", 4, "", "\n" ); # We rename ConfigItems later
$Setting .= "\n" . $NavigationModule;
}
}
# Rename Regex to ValueRegex.
$Setting =~ s{^(\s+.*?$ValidateModule}gsm ) {
# Remove ValidateModule tag.
$Setting =~ s{^\s+.*?::$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{(.*?)}
{- $2
}gsmx;
}
}
# Update file path.
$Setting =~ s{(.*?)<\/String>}
{- $2
}gsmx;
# Update file directory.
$Setting =~ s{(.*?)<\/String>}
{- $2
}gsmx;
# Replace No/Yes drop-down with Checkbox.
$Setting =~ s{
^(\s+) # match space
No< # match No
.*? Key="1" .*?>Yes # match Yes
\s+?? # match end of option
}
{$1- $2
}gsmx;
$Setting =~ s{
^(\s+) # match space
No< # match No
.*? Key="1" .*?>Yes # match Yes
\s+?? # match end of option
}
{$1- 0
}gsmx;
# Replace Yes/No drop-down with Checkbox
$Setting =~ s{
^(\s+) # match space
Yes< # match Yes
.*? Key="0" .*?>No # match No
\s+? # match end of option
}
{$1- $2
}gsmx;
$Setting =~ s{
^(\s+) # match space
Yes< # match Yes
.*? Key="0" .*?>No # match No
\s+? # match end of option
}
{$1- 0
}gsmx;
# Check if this Setting contains Option with Items.
if ( $Setting =~ m{}gsm ) {
my @Items = split( '', $Setting );
for my $Item (@Items) {
# Set the ValueType 'Option' tag to the main item.
$Item =~ s{- (.*?)$}{
- $3}gsmx;
# Convert Options to children Item.
$Item =~ s{ to
$Item =~ s{}{ }gsmx;
}
$Setting = join( '', @Items );
}
elsif ( $Setting =~ m{}
{- $SelectedID
}gsmx;
}
# Update WorkingHours.
if ( $Setting =~ m{TimeWorkingHours} ) {
my @Days = split( "", $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+)}{$1- }gsmx ) {
if ($1) {
$SpaceString = $1;
}
}
# Set Day ValueType tag.
$Day =~ s{}{
- }gsmx;
# Set Hour ValueType tag.
$Day =~ s{(\d+)}{
- $1
}gsmx;
# Add block closure tag on the last item.
if ( $Day eq $Days[-1] ) {
$Day .= " \n$SpaceString ";
}
}
my $DaysString = join( '', @Days );
$Setting =~ s{.*?.*?}{$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>}{- }gsmx;
$Setting =~ s{$Type>}{
}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\n" .
"\t\t\t\t\n";
for my $DFoption (@DFoptions) {
## nofilter(TidyAll::Plugin::OTRS::Perl::Translatable)
$ReplacementString
.= "\t\t\t\t\t- $DFoption
\n";
$DFCount++;
}
$ReplacementString .= "\t\t\t\t\n" .
"\t\t\t\n";
}
if ($ReplacementString) {
# DynamicFields
$Setting =~ s{
Name=(.*?)\#\#\#(|FollowUp|ProcessWidget|SearchOverview|SearchCSV)DynamicField\"(.*?)
(\s+)(\s+)<\/Hash>
}{Name=$1$Hashtag$2DynamicField"$3$ReplacementString}gsmx;
# DefaultColumns
$ReplacementString =~ s{\n\t\t\t\n}{\n\t\n};
$ReplacementString =~ s{\n}{\n\t\t};
$ReplacementString =~ s{\t\t\t\n}{};
$ReplacementString .= "\t\t- 2
";
my $DefaultColumnsHashtag = $Hashtag . 'DefaultColumns';
$Setting =~ s{
Name=(.*?)\#\#\#DefaultColumns\"(.*?)
(\s+)(\s+)- 2
}{Name=$1$DefaultColumnsHashtag"$2$ReplacementString}gsmx;
$Setting =~ s{
Name=(.*?)DefaultOverviewColumns\"(.*?)
(\s+)(\s+)- 2
}{Name=$1DefaultOverviewColumns"$2$ReplacementString}gsmx;
# AgentCustomerInformationCenter-||DashboardBackend
my $BackendReplacement = "- " .
$ReplacementString . "\n";
$BackendReplacement =~ s{\n\t}{\n\t\t\t}gsmx;
$Setting =~ s{
Name=\"(DashboardBackend|AgentCustomerInformationCenter::Backend)\#\#\#(.*?)\"(.*?)
- (\s+)(\s+)
- 2
}
{Name="$1$Hashtag$2"$3$BackendReplacement}gsmx;
if ( $Setting =~ m{Name=\"LinkObject::ComplexTable\#\#\#Ticket\"} ) {
my $LinkBackendReplace = $BackendReplacement;
$LinkBackendReplace =~ s{DefaultItem>(\s+)- \n\t\t\t\t\t\t
- 2
}{- 1
}gsmx;
$Setting =~ s{
- (\s+)(\s+)
- 1
}
{$LinkBackendReplace}gsmx;
}
# Fill dropdowns with existing values.
$Setting =~ s{<\/DefaultItem>(\s*?)- (0|1|2)<}
{<\/DefaultItem>$1\t\t
- <}gsmx;
# Only alter right after and before the closing the hash
my $DropdownItems;
if ( $Setting =~ m{<\/DefaultItem>(.+)<\/Hash>\s+^[\s]}smx ) {
$DropdownItems = $1;
while (
$DropdownItems =~ m{"(0|1|2)"><\/Item>(\s*)- (0|1|2)<}
)
{
if ( $2 ne 'Default' ) {
$DropdownItems =~ s{><\/Item>(\s*)
- (0|1|2)<}
{>
$1- <}gsmx;
}
}
$DropdownItems =~ s{><\/Item>(\s*)
- <}
{>
\n\t\t\t\t- $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{
- (.*?)
}{- $ArticleTypeMapping{$1}->{Visible}
}g;
$Setting
=~ s{- (.*?)
}{- $ArticleTypeMapping{$1}->{Visible}
}g;
$Setting
=~ s{- ]*>(.*?)
}{- $ArticleTypeMapping{$1}->{Visible}
}g;
$Setting
=~ s{- Kernel::System::PostMaster::Filter::FollowUpArticleTypeCheck
}{- Kernel::System::PostMaster::Filter::FollowUpArticleVisibilityCheck
}g;
}
# Remove Group.
$Setting =~ s{\s+(.*?)}{}gsmx;
# Update SubGroup to the Navigation.
$Setting =~ s{SubGroup>}{Navigation>}gsmx;
my @NavigationValues = $Setting =~ m{(.*?)}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{.*?}{$NavigationStr}gsmx;
}
}
# Update Setting to the Value.
$Setting =~ s{Setting>}{Value>}gsmx;
# # Add missing RegEx to all Numbers
$Setting =~ s{(\d+)$}
{- $1
}gsmx;
$Setting =~ s{(\d+)}
{- $1
}gsmx;
$Setting =~ s{(\d+?)}
{- $1
}gsmx;
$Setting =~ s{(\d+)}
{- $2
}gmsx;
# Update string and text-area to items with its corresponding ValueType.
$Setting =~ s{