1# --
2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/
3# --
4# This software comes with ABSOLUTELY NO WARRANTY. For details, see
5# the enclosed file COPYING for license information (GPL). If you
6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
7# --
8
9package Kernel::System::SysConfig::Migration;
10
11use strict;
12use warnings;
13
14use parent qw(scripts::DBUpdateTo6::Base);
15
16use List::Util qw(first);
17
18our @ObjectDependencies = (
19    'Kernel::System::Log',
20    'Kernel::System::Main',
21    'Kernel::System::SysConfig',
22);
23
24use Kernel::System::VariableCheck qw( :all );
25
26=head1 NAME
27
28Kernel::System::SysConfig::Migration - System configuration settings migration tools.
29
30=head1 PUBLIC INTERFACE
31
32=head2 new()
33
34Create an object. Do not use it directly, instead use:
35
36    use Kernel::System::ObjectManager;
37    local $Kernel::OM = Kernel::System::ObjectManager->new();
38    my $SysConfigMigrationObject = $Kernel::OM->Get('Kernel::System::SysConfig::Migration');
39
40=cut
41
42sub new {
43    my ( $Type, %Param ) = @_;
44
45    # allocate new hash for object
46    my $Self = {};
47    bless( $Self, $Type );
48
49    return $Self;
50}
51
52=head2 MigrateXMLStructure()
53
54Migrate XML file content from OTRS 5 to OTRS 6.
55
56    my $Result = $SysConfigMigrationObject->MigrateXMLStructure(
57        Content => '
58            <?xml version="1.0" encoding="utf-8" ?>
59            <otrs_config version="1.0" init="Framework">
60                ...
61            </otrs_config>',
62        Name => 'Framework',
63    );
64
65Returns:
66
67    $Result = '
68        <?xml version="1.0" encoding="utf-8" ?>
69        <otrs_config version="2.0" init="Framework">
70            ...
71        </otrs_config>';
72
73=cut
74
75sub MigrateXMLStructure {
76    my ( $Self, %Param ) = @_;
77
78    for my $Needed (qw(Content Name)) {
79        if ( !$Param{$Needed} ) {
80            $Kernel::OM->Get('Kernel::System::Log')->Log(
81                Priority => 'error',
82                Message  => "Need $Needed!",
83            );
84            return;
85        }
86    }
87
88    my $Init = "";
89    if ( $Param{Content} =~ m{<otrs_config.*?init="(.*?)"} ) {
90        $Init = $1;
91    }
92
93    # Stop if we don't have Init (configuration xml file is corrupt or invalid).
94    return if !$Init;
95
96    # Stop if its a configuration file is not from OTRS 5 or prior (OTRS 6 uses version 2.0).
97    return if !$Param{Content} =~ m{^<otrs_config.*?version="1.0"}gsmx;
98
99    # Split settings - prevent deleting some settings due to greedy RegEx. Each array item contains
100    #   only one setting.
101    my @Settings = split( "</ConfigItem>", $Param{Content} );
102
103    my %InitToLoaderMapping = (
104        Framework   => '001-',
105        Application => '002-',
106        Config      => '003-',
107        Changes     => '004-',
108    );
109
110    my %NavigationLookup = $Self->NavigationLookupGet();
111
112    my @Frontends;
113
114    SETTING:
115    for my $Setting (@Settings) {
116
117        # Stop the setting loop process if it's the ending tag.
118        last SETTING if $Setting =~ m/<\/otrs_config>/i;
119
120        # Update version (from 1.0 to 2.0).
121        $Setting =~ s{^(<otrs_config.*?version)="1.0"}{$1="2.0"}gsmx;
122        $Setting .= "</ConfigItem>";
123
124        # Update to preferences group
125        if ( $Setting =~ m{PreferencesGroups###} && $Setting =~ m{<Item Key="Column">} ) {
126            $Setting =~ s{<Item\s+Key="Column">}{<Item Key="PreferenceGroup">}gsmx;
127        }
128
129        # Check if FrontendModuleReg.
130        if ( $Setting =~ m{<FrontendModuleReg>} ) {
131
132            # Extract Loader and delete.
133            my $Loader;
134            if ( $Setting =~ s{\s+<Loader>(.*?)</Loader>$}{}gsmx ) {
135                $Loader = $1;
136            }
137
138            # Extract NavBar and delete
139            my $NavBar;
140
141            if ( $Setting =~ s{\s+<NavBar>(.*)</NavBar>$}{}gsmx ) {
142                $NavBar = "<NavBar>\n$1</NavBar>\n";
143            }
144
145            # Extract NavBarModule and delete
146            my $NavBarModule;
147            if ( $Setting =~ s{\s+<NavBarModule>(.*?)</NavBarModule>$}{}gsmx ) {
148                $NavBarModule = $1;
149            }
150
151            # Extract FrontendModuleReg and delete.
152            $Setting =~ s{<FrontendModuleReg>(.*?)</FrontendModuleReg>}{}gsmx;
153            my $FrontendModuleReg = $1;
154
155            # Split on new line.
156            my @Lines = split( "\n", $FrontendModuleReg );
157
158            LINE:
159            for my $Line (@Lines) {
160
161                my $Tag;
162
163                # Extract tag name.
164                if ( $Line =~ m{</(.*?)>} ) {
165                    $Tag = $1;
166                }
167
168                next LINE if !$Tag;
169
170                # Create Item to replace $Tag.
171                $Line =~ s{<$Tag(.*?)</$Tag>}{<Item Key="$Tag"$1</Item>}gsmx;
172            }
173
174            $FrontendModuleReg = join( "\n", @Lines );
175
176            my %GroupItems;
177
178            @Lines = split( "\n", $FrontendModuleReg );
179            my @OutputLines;
180
181            LINE:
182            for my $Line (@Lines) {
183                next LINE if !$Line;
184
185                $Line =~ m{Item Key="(.*?)"};
186                my $ItemKey = $1 || '';
187
188                if ( $ItemKey eq 'Group' || $ItemKey eq 'GroupRo' ) {
189                    $Line =~ m{<Item.*?>(.*?)</Item>}gsmg;
190                    my $Value = $1;
191
192                    if ( $GroupItems{$ItemKey} ) {
193                        push @{ $GroupItems{$ItemKey} }, $Value;
194
195                        # Skip this line.
196                        next LINE;
197                    }
198                    else {
199                        $GroupItems{$ItemKey} = [$Value];
200
201                        # Put Placeholder.
202                        $Line =~ s{^(\s+)<Item.*?</Item>.*?$}{$1 PLACEHOLDER_$ItemKey _END}gsmx;
203                    }
204                }
205
206                $Line = "    $Line";
207                push @OutputLines, $Line;
208            }
209
210            $FrontendModuleReg = join( "\n", @OutputLines );
211            my $FirstItem = 1;
212
213            for my $Key ( sort keys %GroupItems ) {
214
215                if ( ref $GroupItems{$Key} eq 'ARRAY' ) {
216                    my $ArrayItems = '';
217                    if ($FirstItem) {
218                        $ArrayItems .= "\n";
219                    }
220
221                    $ArrayItems .= sprintf "%-*s%s", 20, "",
222                        "<Item Key=\"$Key\">\n";
223                    $ArrayItems .= sprintf "%-*s%s", 24, "",
224                        "<Array>\n";
225
226                    for my $ArrayItem ( @{ $GroupItems{$Key} } ) {
227                        if ($ArrayItem) {
228                            $ArrayItems .= sprintf "%-*s%s", 28, "",
229                                "<Item>$ArrayItem</Item>\n";
230                        }
231                    }
232                    $ArrayItems .= sprintf "%-*s%s", 24, "",
233                        "</Array>\n";
234                    $ArrayItems .= sprintf "%-*s%s", 20, "",
235                        "</Item>";
236
237                    $FrontendModuleReg =~ s{^\s+PLACEHOLDER_$Key\s_END.*?$}{$ArrayItems}gsmx;
238                }
239                $FirstItem = 0;
240            }
241
242            # Make sure each FrontendModuleReg has Group and GroupRo items
243            for my $GroupTag (qw(GroupRo Group)) {
244                if ( $FrontendModuleReg !~ m{<Item Key="$GroupTag"} ) {
245
246                    my $MissingTag = sprintf "%-*s%s", 20, "",
247                        "<Item Key=\"$GroupTag\">\n";
248
249                    $MissingTag .= sprintf "%-*s%s", 24, "",
250                        "<Array>\n";
251                    $MissingTag .= sprintf "%-*s%s", 24, "",
252                        "</Array>\n";
253                    $MissingTag .= sprintf "%-*s%s", 20, "",
254                        "</Item>\n";
255
256                    # prepend
257                    $FrontendModuleReg = $MissingTag .= $FrontendModuleReg;
258                }
259            }
260
261            # check if NavBarName exists
262            if ( $FrontendModuleReg !~ m{<Item Key="NavBarName"} ) {
263                $FrontendModuleReg .= sprintf "%-*s%s", 4, "",
264                    "<Item Key=\"NavBarName\"></Item>\n";
265                $FrontendModuleReg .= sprintf "%-*s", 16, "";
266            }
267
268            my $FirstCharacter = substr $FrontendModuleReg, 0, 1;
269            if ( $FirstCharacter ne "\n" ) {
270                $FrontendModuleReg = "\n$FrontendModuleReg";
271            }
272
273            my $Value = "<Value>\n";
274            $Value .= sprintf "%-*s%s", 12, "", "<Item ValueType=\"FrontendRegistration\">\n";
275            $Value .= sprintf "%-*s%s", 16, "", "<Hash>";
276            $Value .= $FrontendModuleReg;
277            $Value .= "</Hash>\n";
278            $Value .= sprintf "%-*s%s", 12, "", "</Item>\n";
279            $Value .= sprintf "%-*s%s", 8,  "", "</Value>";
280
281            $Setting =~ s{<Setting>.*?</Setting>}{$Value}gsmx;
282
283            # Put Loader stuff in a separated setting.
284            if (
285                $Loader
286                && $Setting =~ m{<ConfigItem\s+Name="(.*?)"(.*?)>}gsmx
287                )
288            {
289                my $LoaderSetting = sprintf "%-*s%s", 4, "", "<ConfigItem Name=\"$1\"$2>";
290
291                my $LoaderName = ( $InitToLoaderMapping{$Init} // '005-' )
292                    . $Param{Name};
293
294                $LoaderSetting =~ s{Name=".*?\#\#\#(.*?)" (.*?)>}{Name="Loader::Module::$1###$LoaderName"$2>}gsmx;
295
296                $LoaderSetting .= sprintf(
297                    "\n%-*s%s",
298                    8,
299                    "",
300                    "<Description Translatable=\"1\">Loader module registration for the agent interface.</Description>"
301                );
302
303                if ( $Setting =~ m{<SubGroup>(.*?)</SubGroup>} ) {
304                    my $NavigationStr = $NavigationLookup{$1} || $1;
305
306                    $NavigationStr .= "::Loader";
307                    $LoaderSetting .= sprintf( "\n%-*s%s", 8, "", "<Navigation>$NavigationStr</Navigation>" );
308                }
309
310                $LoaderSetting .= sprintf( "\n%-*s%s", 8,  "", "<Value>" );
311                $LoaderSetting .= sprintf( "\n%-*s%s", 12, "", "<Hash>" );
312
313                my @LoaderLines = split( "\n", $Loader );
314                my ( @CSS, @JS );
315
316                # Check for CSS and JS content.
317                for my $Line (@LoaderLines) {
318                    if ( $Line =~ m{<CSS>(.*?)</CSS>} ) {
319                        push @CSS, $1;
320                    }
321
322                    if ( $Line =~ m{<JavaScript>(.*?)</JavaScript>} ) {
323                        push @JS, $1;
324                    }
325                }
326
327                if ( scalar @CSS ) {
328                    $LoaderSetting .= sprintf( "\n%-*s%s", 16, "", "<Item Key=\"CSS\">" );
329                    $LoaderSetting .= sprintf( "\n%-*s%s", 20, "", "<Array>" );
330                }
331
332                for my $CSSItem (@CSS) {
333                    $LoaderSetting .= sprintf( "\n%-*s%s", 24, "", "<Item>$CSSItem</Item>" );
334                }
335
336                if ( scalar @CSS ) {
337                    $LoaderSetting .= sprintf( "\n%-*s%s", 20, "", "</Array>" );
338                    $LoaderSetting .= sprintf( "\n%-*s%s", 16, "", "</Item>" );
339                }
340
341                if ( scalar @JS ) {
342                    $LoaderSetting .= sprintf( "\n%-*s%s", 16, "", "<Item Key=\"JavaScript\">" );
343                    $LoaderSetting .= sprintf( "\n%-*s%s", 20, "", "<Array>" );
344                }
345
346                for my $JSItem (@JS) {
347                    $LoaderSetting .= sprintf( "\n%-*s%s", 24, "", "<Item>$JSItem</Item>" );
348                }
349
350                if ( scalar @JS ) {
351                    $LoaderSetting .= sprintf( "\n%-*s%s", 20, "", "</Array>" );
352                    $LoaderSetting .= sprintf( "\n%-*s%s", 16, "", "</Item>" );
353                }
354
355                $LoaderSetting .= sprintf( "\n%-*s%s", 12, "", "</Hash>" );
356                $LoaderSetting .= sprintf( "\n%-*s%s", 8,  "", "</Value>" );
357                $LoaderSetting .= sprintf( "\n%-*s%s", 4,  "", "</ConfigItem>" );
358
359                $Setting .= "\n" . $LoaderSetting;
360            }
361
362            if ( $NavBar && $Setting =~ m{<ConfigItem\s+Name="(.*?)"(.*?)>}gsmx ) {
363                my $Name    = $1;
364                my $Options = $2;
365
366                my @NavBars = split m{<\/NavBar>\s+?<NavBar}, $NavBar;
367
368                $Name =~ s{Frontend::Module}{Frontend::Navigation}gsmx;
369                $Name .= '###' . ( $InitToLoaderMapping{$Init} // '005-' ) . $Param{Name};
370
371                my $Navigation = sprintf "%-*s%s", 4, "", "<Setting Name=\"$Name\"$Options>\n";
372                $Navigation .= sprintf "%-*s%s", 8, "",
373                    "<Description Translatable=\"1\">Main menu item registration.</Description>";
374
375                if ( $Setting =~ m{<SubGroup>(.*?)</SubGroup>} ) {
376                    my $NavigationStr = $NavigationLookup{$1} || $1;
377                    $NavigationStr .= "::MainMenu";
378                    $Navigation    .= sprintf( "\n%-*s%s", 8, "", "<Navigation>$NavigationStr</Navigation>" );
379                }
380
381                $Navigation .= sprintf( "\n%-*s%s", 8,  "", "<Value>" );
382                $Navigation .= sprintf( "\n%-*s%s", 12, "", "<Array>" );
383                $Navigation .= sprintf( "\n%-*s%s", 16, "", "<DefaultItem ValueType=\"FrontendNavigation\">" );
384                $Navigation .= sprintf( "\n%-*s%s", 20, "", "<Hash>" );
385                $Navigation .= sprintf( "\n%-*s%s", 20, "", "</Hash>" );
386                $Navigation .= sprintf( "\n%-*s%s", 16, "", "</DefaultItem>" );
387
388                for my $NavBarItem (@NavBars) {
389
390                    $Navigation .= sprintf( "\n%-*s%s", 16, "", "<Item>" );
391                    $Navigation .= sprintf( "\n%-*s%s", 20, "", "<Hash>" );
392
393                    for my $NavBarTag (qw(Group GroupRo)) {
394                        my @Items;
395
396                        while ( $NavBarItem =~ s{<$NavBarTag>(.*?)<\/$NavBarTag}{}smx ) {
397                            push @Items, $1;
398                        }
399
400                        $Navigation .= sprintf( "\n%-*s%s", 24, "", "<Item Key=\"$NavBarTag\">" );
401                        $Navigation .= sprintf( "\n%-*s%s", 28, "", "<Array>" );
402
403                        for my $Value (@Items) {
404                            $Navigation .= sprintf( "\n%-*s%s", 32, "", "<Item>$Value</Item>" );
405                        }
406
407                        if (
408                            !scalar @Items
409                            && $GroupItems{$NavBarTag}
410                            )
411                        {
412                            # take group items from FrontendModuleReg
413                            for my $Value ( @{ $GroupItems{$NavBarTag} } ) {
414                                if ($Value) {
415                                    $Navigation .= sprintf( "\n%-*s%s", 32, "", "<Item>$Value</Item>" );
416                                }
417                            }
418                        }
419
420                        $Navigation .= sprintf( "\n%-*s%s", 28, "", "</Array>" );
421                        $Navigation .= sprintf( "\n%-*s%s", 24, "", "</Item>" );
422                    }
423
424                    for my $NavBarTag (qw(Description Name Link LinkOption NavBar Type Block AccessKey Prio)) {
425                        my $Value      = '';
426                        my $Attributes = '';
427
428                        if ( $NavBarItem =~ m{<$NavBarTag>(.*?)<\/$NavBarTag} ) {
429                            $Value = $1;
430                        }
431                        elsif ( $NavBarItem =~ m{<$NavBarTag\s(.*?)>(.*?)<\/$NavBarTag} ) {
432                            $Attributes = " $1";
433                            $Value      = $2;
434                        }
435                        $Navigation .= sprintf(
436                            "\n%-*s%s", 24, "",
437                            "<Item Key=\"$NavBarTag\"$Attributes>$Value</Item>",
438                        );
439                    }
440
441                    $Navigation .= sprintf( "\n%-*s%s", 20, "", "</Hash>" );
442                    $Navigation .= sprintf( "\n%-*s%s", 16, "", "</Item>" );
443                }
444
445                $Navigation .= sprintf( "\n%-*s%s", 12, "", "</Array>" );
446                $Navigation .= sprintf( "\n%-*s%s", 8,  "", "</Value>" );
447                $Navigation .= sprintf( "\n%-*s%s", 4,  "", "</ConfigItem>\n" );    # We rename ConfigItems later
448
449                $Setting .= "\n" . $Navigation;
450            }
451            elsif ( !$NavBar && $Setting =~ m{<ConfigItem\s+Name="(.*?)"(.*?)>}gsmx ) {
452                my $Name    = $1;
453                my $Options = $2;
454
455                my %NoDefaultNavigationSetting = (
456                    'CustomerFrontend::Module###AjaxAttachment'                             => 1,
457                    'CustomerFrontend::Module###CustomerAccept'                             => 1,
458                    'CustomerFrontend::Module###CustomerChatDownload'                       => 1,
459                    'CustomerFrontend::Module###CustomerDynamicFieldDatabaseDetailedSearch' => 1,
460                    'CustomerFrontend::Module###CustomerDynamicFieldDatabaseDetails'        => 1,
461                    'CustomerFrontend::Module###CustomerDynamicFieldDatabaseSearch'         => 1,
462                    'CustomerFrontend::Module###CustomerTicketArticleContent'               => 1,
463                    'CustomerFrontend::Module###CustomerTicketAttachment'                   => 1,
464                    'CustomerFrontend::Module###CustomerTicketPrint'                        => 1,
465                    'CustomerFrontend::Module###CustomerTicketZoom'                         => 1,
466                    'CustomerFrontend::Module###CustomerVideoChat'                          => 1,
467                    'CustomerFrontend::Module###Login'                                      => 1,
468                    'CustomerFrontend::Module###Logout'                                     => 1,
469                    'CustomerFrontend::Module###PictureUpload'                              => 1,
470                    'Frontend::Module###AdminAppointmentImport'                             => 1,
471                    'Frontend::Module###AdminDynamicFieldCheckbox'                          => 1,
472                    'Frontend::Module###AdminDynamicFieldContactWithData'                   => 1,
473                    'Frontend::Module###AdminDynamicFieldDatabase'                          => 1,
474                    'Frontend::Module###AdminDynamicFieldDateTime'                          => 1,
475                    'Frontend::Module###AdminDynamicFieldDropdown'                          => 1,
476                    'Frontend::Module###AdminDynamicFieldMultiselect'                       => 1,
477                    'Frontend::Module###AdminDynamicFieldText'                              => 1,
478                    'Frontend::Module###AdminDynamicFieldWebService'                        => 1,
479                    'Frontend::Module###AdminGenericInterfaceErrorHandlingDefault'          => 1,
480                    'Frontend::Module###AdminGenericInterfaceErrorHandlingRequestRetry'     => 1,
481                    'Frontend::Module###AdminGenericInterfaceInvokerDefault'                => 1,
482                    'Frontend::Module###AdminGenericInterfaceInvokerEvent'                  => 1,
483                    'Frontend::Module###AdminGenericInterfaceMappingSimple'                 => 1,
484                    'Frontend::Module###AdminGenericInterfaceMappingXSLT'                   => 1,
485                    'Frontend::Module###AdminGenericInterfaceOperationDefault'              => 1,
486                    'Frontend::Module###AdminGenericInterfaceTransportHTTPREST'             => 1,
487                    'Frontend::Module###AdminGenericInterfaceTransportHTTPSOAP'             => 1,
488                    'Frontend::Module###AdminGenericInterfaceWebserviceHistory'             => 1,
489                    'Frontend::Module###AdminInit'                                          => 1,
490                    'Frontend::Module###AdminProcessManagementActivity'                     => 1,
491                    'Frontend::Module###AdminProcessManagementActivityDialog'               => 1,
492                    'Frontend::Module###AdminProcessManagementPath'                         => 1,
493                    'Frontend::Module###AdminProcessManagementTransition'                   => 1,
494                    'Frontend::Module###AdminProcessManagementTransitionAction'             => 1,
495                    'Frontend::Module###AgentAppointmentEdit'                               => 1,
496                    'Frontend::Module###AgentAppointmentPluginSearch'                       => 1,
497                    'Frontend::Module###AgentChatAppend'                                    => 1,
498                    'Frontend::Module###AgentChatAvailability'                              => 1,
499                    'Frontend::Module###AgentChatDownload'                                  => 1,
500                    'Frontend::Module###AgentChatPopup'                                     => 1,
501                    'Frontend::Module###AgentChatPreview'                                   => 1,
502                    'Frontend::Module###AgentContactWithDataSearch'                         => 1,
503                    'Frontend::Module###AgentCustomerSearch'                                => 1,
504                    'Frontend::Module###AgentCustomerSearchSMS'                             => 1,
505                    'Frontend::Module###AgentCustomerUserAddressBook'                       => 1,
506                    'Frontend::Module###AgentCustomerUserInformationCenterSearch'           => 1,
507                    'Frontend::Module###AgentDaemonInfo'                                    => 1,
508                    'Frontend::Module###AgentDynamicFieldDatabaseDetailedSearch'            => 1,
509                    'Frontend::Module###AgentDynamicFieldDatabaseDetails'                   => 1,
510                    'Frontend::Module###AgentDynamicFieldDatabaseSearch'                    => 1,
511                    'Frontend::Module###AgentInfo'                                          => 1,
512                    'Frontend::Module###AgentHTMLReference'                                 => 1,
513                    'Frontend::Module###AgentOTRSBusiness'                                  => 1,
514                    'Frontend::Module###AgentSplitSelection'                                => 1,
515                    'Frontend::Module###AgentTicketArticleContent'                          => 1,
516                    'Frontend::Module###AgentTicketAttachment'                              => 1,
517                    'Frontend::Module###AgentTicketAttachmentView'                          => 1,
518                    'Frontend::Module###AgentTicketBounce'                                  => 1,
519                    'Frontend::Module###AgentTicketBulk'                                    => 1,
520                    'Frontend::Module###AgentTicketClose'                                   => 1,
521                    'Frontend::Module###AgentTicketCompose'                                 => 1,
522                    'Frontend::Module###AgentTicketCustomer'                                => 1,
523                    'Frontend::Module###AgentTicketEmailOutbound'                           => 1,
524                    'Frontend::Module###AgentTicketEmailResend'                             => 1,
525                    'Frontend::Module###AgentTicketForward'                                 => 1,
526                    'Frontend::Module###AgentTicketFreeText'                                => 1,
527                    'Frontend::Module###AgentTicketHistory'                                 => 1,
528                    'Frontend::Module###AgentTicketLock'                                    => 1,
529                    'Frontend::Module###AgentTicketMerge'                                   => 1,
530                    'Frontend::Module###AgentTicketMove'                                    => 1,
531                    'Frontend::Module###AgentTicketNote'                                    => 1,
532                    'Frontend::Module###AgentTicketOwner'                                   => 1,
533                    'Frontend::Module###AgentTicketPending'                                 => 1,
534                    'Frontend::Module###AgentTicketPhoneInbound'                            => 1,
535                    'Frontend::Module###AgentTicketPhoneOutbound'                           => 1,
536                    'Frontend::Module###AgentTicketPlain'                                   => 1,
537                    'Frontend::Module###AgentTicketPrint'                                   => 1,
538                    'Frontend::Module###AgentTicketPriority'                                => 1,
539                    'Frontend::Module###AgentTicketResponsible'                             => 1,
540                    'Frontend::Module###AgentTicketSMSOutbound'                             => 1,
541                    'Frontend::Module###AgentTicketWatcher'                                 => 1,
542                    'Frontend::Module###AgentTicketZoom'                                    => 1,
543                    'Frontend::Module###AgentUserSearch'                                    => 1,
544                    'Frontend::Module###AgentVideoChat'                                     => 1,
545                    'Frontend::Module###AgentZoom'                                          => 1,
546                    'Frontend::Module###AjaxAttachment'                                     => 1,
547                    'Frontend::Module###Login'                                              => 1,
548                    'Frontend::Module###Logout'                                             => 1,
549                    'Frontend::Module###PictureUpload'                                      => 1,
550                    'PublicFrontend::Module###PublicCalendar'                               => 1,
551                    'PublicFrontend::Module###PublicDefault'                                => 1,
552                    'PublicFrontend::Module###PublicRepository'                             => 1,
553                    'PublicFrontend::Module###PublicSupportDataCollector'                   => 1,
554                );
555
556                if ( !$NoDefaultNavigationSetting{$Name} ) {
557
558                    $Name =~ s{Frontend::Module}{Frontend::Navigation}gsmx;
559                    $Name .= '###' . ( $InitToLoaderMapping{$Init} // '005-' ) . $Param{Name};
560
561                    my $Navigation = sprintf "%-*s%s", 4, "", "<Setting Name=\"$Name\" Required=\"0\" Valid=\"0\">\n";
562                    $Navigation .= sprintf "%-*s%s", 8, "",
563                        "<Description Translatable=\"1\">Main menu item registration.</Description>";
564
565                    if ( $Setting =~ m{<SubGroup>(.*?)</SubGroup>} ) {
566                        my $NavigationStr = $NavigationLookup{$1} || $1;
567                        $NavigationStr .= "::MainMenu";
568                        $Navigation    .= sprintf( "\n%-*s%s", 8, "", "<Navigation>$NavigationStr</Navigation>" );
569                    }
570
571                    $Navigation .= sprintf( "\n%-*s%s", 8,  "", "<Value>" );
572                    $Navigation .= sprintf( "\n%-*s%s", 12, "", "<Array>" );
573                    $Navigation .= sprintf( "\n%-*s%s", 16, "", "<DefaultItem ValueType=\"FrontendNavigation\">" );
574                    $Navigation .= sprintf( "\n%-*s%s", 20, "", "<Hash>" );
575                    $Navigation .= sprintf( "\n%-*s%s", 20, "", "</Hash>" );
576                    $Navigation .= sprintf( "\n%-*s%s", 16, "", "</DefaultItem>" );
577                    $Navigation .= sprintf( "\n%-*s%s", 12, "", "</Array>" );
578                    $Navigation .= sprintf( "\n%-*s%s", 8,  "", "</Value>" );
579                    $Navigation .= sprintf( "\n%-*s%s", 4, "", "</ConfigItem>\n" );    # We rename ConfigItems later
580
581                    $Setting .= "\n" . $Navigation;
582                }
583            }
584
585            if ( $NavBarModule && $Setting =~ m{<ConfigItem\s+Name="(.*?)"(.*?)>}gsmx ) {
586
587                # FrontendNavigationModule
588
589                my $Name    = $1;
590                my $Options = $2;
591
592                $Name =~ s{Frontend::Module}{Frontend::NavigationModule}gsmx;
593
594                my $NavigationModule = sprintf "%-*s%s", 4, "", "<Setting Name=\"$Name\"$Options>\n";
595                $NavigationModule .= sprintf "%-*s%s", 8, "",
596                    "<Description Translatable=\"1\">Admin area navigation for the agent interface.</Description>";
597
598                if ( $Setting =~ m{<SubGroup>(.*?)</SubGroup>} ) {
599                    my $NavigationStr = $NavigationLookup{$1} || $1;
600
601                    $NavigationStr    .= '::AdminOverview';
602                    $NavigationModule .= sprintf( "\n%-*s%s", 8, "", "<Navigation>$NavigationStr</Navigation>" );
603                }
604
605                $NavigationModule .= sprintf( "\n%-*s%s", 8,  "", "<Value>" );
606                $NavigationModule .= sprintf( "\n%-*s%s", 12, "", "<Hash>" );
607
608                for my $NavBarTag (qw(Group GroupRo)) {
609                    my @Items;
610
611                    while ( $NavBarModule =~ s{<$NavBarTag>(.*?)<\/$NavBarTag}{}smx ) {
612                        push @Items, $1;
613                    }
614
615                    $NavigationModule .= sprintf( "\n%-*s%s", 16, "", "<Item Key=\"$NavBarTag\">" );
616                    $NavigationModule .= sprintf( "\n%-*s%s", 20, "", "<Array>" );
617
618                    for my $Value (@Items) {
619                        $NavigationModule .= sprintf( "\n%-*s%s", 24, "", "<Item>$Value</Item>" );
620                    }
621
622                    if (
623                        !scalar @Items
624                        && $GroupItems{$NavBarTag}
625                        )
626                    {
627                        # take group items from FrontendModuleReg
628                        for my $Value ( @{ $GroupItems{$NavBarTag} } ) {
629                            if ($Value) {
630                                $NavigationModule .= sprintf( "\n%-*s%s", 24, "", "<Item>$Value</Item>" );
631                            }
632                        }
633                    }
634
635                    $NavigationModule .= sprintf( "\n%-*s%s", 20, "", "</Array>" );
636                    $NavigationModule .= sprintf( "\n%-*s%s", 16, "", "</Item>" );
637                }
638
639                NAVBARTAG:
640                for my $NavBarTag (qw(Module Name Block Description IconBig IconSmall CssClass)) {
641                    my $Value      = '';
642                    my $Attributes = '';
643
644                    if ( $NavBarModule =~ m{<$NavBarTag>(.*?)<\/$NavBarTag} ) {
645                        $Value = $1;
646                    }
647                    elsif ( $NavBarModule =~ m{<$NavBarTag\s(.*?)>(.*?)<\/$NavBarTag} ) {
648                        $Attributes = " $1";
649                        $Value      = $2;
650                    }
651
652                    # special treatment for OTRSBusiness tile CssClass
653                    if ( $NavBarTag eq 'CssClass' ) {
654                        next NAVBARTAG if $Name ne 'Frontend::NavigationModule###AdminOTRSBusiness';
655                        $Value = 'OTRSBusiness';
656                    }
657
658                    $NavigationModule .= sprintf(
659                        "\n%-*s%s", 16, "",
660                        "<Item Key=\"$NavBarTag\"$Attributes>$Value</Item>",
661                    );
662                }
663
664                $NavigationModule .= sprintf( "\n%-*s%s", 12, "", "</Hash>" );
665                $NavigationModule .= sprintf( "\n%-*s%s", 8,  "", "</Value>" );
666                $NavigationModule .= sprintf( "\n%-*s%s", 4,  "", "</ConfigItem>\n" );    # We rename ConfigItems later
667
668                $Setting .= "\n" . $NavigationModule;
669            }
670        }
671
672        # Rename Regex to ValueRegex.
673        $Setting =~ s{^(\s+<String\s+)Regex="(.*?)"}{$1ValueRegex="$2"}gsmx;
674
675        # Check for known old validation modules.
676        for my $ValidateModule (qw(StateValidate PriorityValidate QueueValidate)) {
677
678            if ( $Setting =~ m{<ValidateModule>.*?$ValidateModule</ValidateModule>}gsm ) {
679
680                # Remove ValidateModule tag.
681                $Setting =~ s{^\s+<ValidateModule>.*?::$ValidateModule</ValidateModule>}{}gsmx;
682
683                my $Entity;
684                if ( $ValidateModule eq 'StateValidate' ) {
685                    $Entity = 'State';
686                }
687                elsif ( $ValidateModule eq 'PriorityValidate' ) {
688                    $Entity = 'Priority';
689                }
690                elsif ( $ValidateModule eq 'QueueValidate' ) {
691                    $Entity = 'Queue';
692                }
693
694                # Update string tag.
695                $Setting =~ s{<String(.*?)>(.*?)</String>}
696                    {<Item ValueType="Entity" ValueEntityType="$Entity"$1>$2</Item>}gsmx;
697            }
698        }
699
700        # Update file path.
701        $Setting =~ s{<String\s+ValueRegex="(.*?)"\s+Check="File".*?>(.*?)<\/String>}
702            {<Item ValueRegex="$1" ValueType="File">$2</Item>}gsmx;
703
704        # Update file directory.
705        $Setting =~ s{<String\s+ValueRegex="(.*?)"\s+Check="Directory".*?>(.*?)<\/String>}
706            {<Item ValueRegex="$1" ValueType="Directory">$2</Item>}gsmx;
707
708        # Replace No/Yes drop-down with Checkbox.
709        $Setting =~ s{
710                ^(\s+)                               # match space
711                <Option.*?SelectedID="(\d)"          # match SelectedID inside Option tag
712                .*? Key="0" .*?>No<                  # match No
713                .*? Key="1" .*?>Yes</Item>           # match Yes
714                \s+?</Option>?                       # match end of option
715            }
716            {$1<Item ValueType="Checkbox">$2</Item>}gsmx;
717        $Setting =~ s{
718                ^(\s+)                               # match space
719                <Option.*?SelectedID=""              # match empty SelectedID inside Option tag
720                .*? Key="0" .*?>No<                  # match No
721                .*? Key="1" .*?>Yes</Item>           # match Yes
722                \s+?</Option>?                       # match end of option
723            }
724            {$1<Item ValueType="Checkbox">0</Item>}gsmx;
725
726        # Replace Yes/No drop-down with Checkbox
727        $Setting =~ s{
728                    ^(\s+)                               # match space
729                    <Option.*?SelectedID="(\d)"          # match SelectedID inside Option tag
730                    .*? Key="1" .*?>Yes<                 # match Yes
731                    .*? Key="0" .*?>No</Item>            # match No
732                    \s+?</Option>                        # match end of option
733                }
734                {$1<Item ValueType="Checkbox">$2</Item>}gsmx;
735        $Setting =~ s{
736                    ^(\s+)                               # match space
737                    <Option.*?SelectedID=""              # match empty SelectedID inside Option tag
738                    .*? Key="1" .*?>Yes<                 # match Yes
739                    .*? Key="0" .*?>No</Item>            # match No
740                    \s+?</Option>                        # match end of option
741                }
742                {$1<Item ValueType="Checkbox">0</Item>}gsmx;
743
744        # Check if this Setting contains Option with Items.
745        if ( $Setting =~ m{<Option.*?<Item.*?</Option>}gsm ) {
746            my @Items = split( '</Item>', $Setting );
747
748            for my $Item (@Items) {
749
750                # Set the ValueType 'Option' tag to the main item.
751                $Item =~ s{<Item\s+Key="(.*?)"(.*?)>(.*?)$}{<Item ValueType="Option" Value="$1"$2>$3}gsmx;
752
753                # Convert Options to children Item.
754                $Item =~ s{<Option(.*?)>}{<Item ValueType="Select"$1>}gsmx;
755
756                # Convert </Option> to </Item>
757                $Item =~ s{</Option>}{</Item>}gsmx;
758            }
759
760            $Setting = join( '</Item>', @Items );
761        }
762        elsif ( $Setting =~ m{<Option\s+Location="(.*?)"\s+SelectedID="(.*?)".*?</Option>}gsm ) {
763            my ( $Location, $SelectedID ) = ( $1, $2 );
764
765            $Setting =~ s{<Option.*?</Option>}
766                {<Item ValueType="PerlModule" ValueFilter="$Location">$SelectedID</Item>}gsmx;
767        }
768
769        # Update WorkingHours.
770        if ( $Setting =~ m{TimeWorkingHours} ) {
771            my @Days = split( "</Day>", $Setting );
772            pop @Days;    # contains not needed item
773
774            my $WorkingHoursString = '';
775            my $SpaceString        = '';
776
777            for my $Day (@Days) {
778
779                # Check if this item contains string and update to WorkingHours ValueType.
780                if ( $Day =~ s{^(\s+)<TimeWorkingHours>}{$1<Item ValueType="WorkingHours">}gsmx ) {
781                    if ($1) {
782                        $SpaceString = $1;
783                    }
784                }
785
786                # Set Day ValueType tag.
787                $Day =~ s{<Day\s+Name="(.*?)">}{<Item ValueType="Day" ValueName="$1">}gsmx;
788
789                # Set Hour ValueType tag.
790                $Day =~ s{<Hour>(\d+)</Hour>}{<Item ValueType="Hour">$1</Item>}gsmx;
791
792                # Add block closure tag on the last item.
793                if ( $Day eq $Days[-1] ) {
794                    $Day .= "</Item>\n$SpaceString</Item>";
795                }
796            }
797
798            my $DaysString = join( '</Item>', @Days );
799
800            $Setting =~ s{.*?<TimeWorkingHours>.*?</TimeWorkingHours>}{$DaysString}gsmx;
801        }
802
803        # Update VacationDays.
804        if ( $Setting =~ m{<(TimeVacationDays.*?)>} ) {
805            my $Type = $1;
806
807            my $TypeNew;
808            if ( $Type eq 'TimeVacationDays' ) {
809                $TypeNew = "VacationDays";
810            }
811            else {
812                $TypeNew = "VacationDaysOneTime";
813            }
814
815            # Update item tags to the new format.
816            $Setting =~ s{Year=}{ValueYear=}gsmx;
817            $Setting =~ s{Month=}{ValueMonth=}gsmx;
818            $Setting =~ s{Day=}{ValueDay=}gsmx;
819
820            # Update TimeVacationDays tags.
821            $Setting =~ s{<$Type>}{<Item ValueType="$TypeNew">}gsmx;
822            $Setting =~ s{</$Type>}{</Item>}gsmx;
823        }
824
825        # Update DynamicField Settings
826        my $Hashtag = '###';
827        my @DFoptions;
828        if (
829            $Setting =~ m{Name=(.*?)\#\#\#(|FollowUp|ProcessWidget|SearchOverview|SearchCSV)DynamicField\"} ||
830            $Setting =~ m{Name=(.*?)(\#\#\#DefaultColumns|DefaultOverviewColumns)}                          ||
831            $Setting =~ m{Name=\"(AgentCustomerInformationCenter::Backend|DashboardBackend)\#\#\#}          ||
832            $Setting =~ m{Name=\"LinkObject::ComplexTable\#\#\#Ticket\"}
833            )
834        {
835
836            # 0 = Disabled, 1 = Enabled, 2 = Enabled and shown by default
837            if (
838                $Setting
839                =~ m{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sEnabled,\s2\s=\sEnabled\sand\sshown\sby\sdefault.}
840                )
841            {
842                @DFoptions = ( '0 - Disabled', '1 - Enabled', '2 - Enabled and shown by default' );
843                $Setting
844                    =~ s{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sEnabled,\s2\s=\sEnabled\sand\sshown\sby\sdefault.}{}gsmx;
845            }
846
847            # 0 = Disabled, 1 = Enabled, 2 = Enabled and required.
848            elsif (
849                $Setting =~ m{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sEnabled,\s2\s=\sEnabled\sand\srequired.}
850                )
851            {
852                @DFoptions = ( '0 - Disabled', '1 - Enabled', '2 - Enabled and required' );
853                $Setting
854                    =~ s{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sEnabled,\s2\s=\sEnabled\sand\srequired.}{}gsmx;
855            }
856
857            # 0 = Disabled, 1 = Available, 2 = Enabled by default.
858            elsif (
859                $Setting =~ m{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sAvailable,\s2\s=\sEnabled\sby\sdefault.} ||
860                $Setting =~ m{Name=\"DashboardBackend\#\#\#0140-RunningTicketProcess\"}
861                )
862            {
863                @DFoptions = ( '0 - Disabled', '1 - Available', '2 - Enabled by default' );
864                $Setting
865                    =~ s{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sAvailable,\s2\s=\sEnabled\sby\sdefault.}{}gmsx;
866            }
867
868            # 0 = Disabled, 1 = Enabled.
869            elsif (
870                $Setting =~ m{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sEnabled.}
871                )
872            {
873                @DFoptions = ( '0 - Disabled', '1 - Enabled' );
874                $Setting =~ s{\sPossible\ssettings:\s0\s=\sDisabled,\s1\s=\sEnabled.}{}gsmx;
875            }
876            my $ReplacementString;
877
878            my $DFCount = 0;
879            if (@DFoptions) {
880                $ReplacementString = "\n\t\t\t<Hash>\n" .
881                    "\t\t\t\t<DefaultItem ValueType=\"Select\">\n";
882                for my $DFoption (@DFoptions) {
883                    ## nofilter(TidyAll::Plugin::OTRS::Perl::Translatable)
884                    $ReplacementString
885                        .= "\t\t\t\t\t<Item ValueType=\"Option\" Value=\"$DFCount\" Translatable=\"1\">$DFoption</Item>\n";
886                    $DFCount++;
887                }
888                $ReplacementString .= "\t\t\t\t</DefaultItem>\n" .
889                    "\t\t\t</Hash>\n";
890            }
891
892            if ($ReplacementString) {
893
894                # DynamicFields
895                $Setting =~ s{
896                    Name=(.*?)\#\#\#(|FollowUp|ProcessWidget|SearchOverview|SearchCSV)DynamicField\"(.*?)
897                    <Setting>(\s+)<Hash>(\s+)<\/Hash>
898                }{Name=$1$Hashtag$2DynamicField"$3<Value>$ReplacementString}gsmx;
899
900                # DefaultColumns
901                $ReplacementString =~ s{\n\t\t\t<Hash>\n}{\n\t<Hash>\n};
902                $ReplacementString =~ s{\n}{\n\t\t};
903                $ReplacementString =~ s{\t\t\t</Hash>\n}{};
904                $ReplacementString .= "\t\t<Item Key=\"Age\">2</Item>";
905                my $DefaultColumnsHashtag = $Hashtag . 'DefaultColumns';
906
907                $Setting =~ s{
908                    Name=(.*?)\#\#\#DefaultColumns\"(.*?)
909                    <Setting>(\s+)<Hash>(\s+)<Item\sKey=\"Age\">2</Item>
910                }{Name=$1$DefaultColumnsHashtag"$2<Value>$ReplacementString}gsmx;
911
912                $Setting =~ s{
913                    Name=(.*?)DefaultOverviewColumns\"(.*?)
914                    <Setting>(\s+)<Hash>(\s+)<Item\sKey=\"Age\">2</Item>
915                }{Name=$1DefaultOverviewColumns"$2<Value>$ReplacementString}gsmx;
916
917                # AgentCustomerInformationCenter-||DashboardBackend
918                my $BackendReplacement = "<Item Key=\"DefaultColumns\">" .
919                    $ReplacementString . "\n";
920                $BackendReplacement =~ s{\n\t}{\n\t\t\t}gsmx;
921                $Setting =~ s{
922                    Name=\"(DashboardBackend|AgentCustomerInformationCenter::Backend)\#\#\#(.*?)\"(.*?)
923                    <Item\sKey=\"DefaultColumns\">(\s+)<Hash>(\s+)<Item\sKey=\"Age\">2</Item>
924                }
925                     {Name="$1$Hashtag$2"$3$BackendReplacement}gsmx;
926
927                if ( $Setting =~ m{Name=\"LinkObject::ComplexTable\#\#\#Ticket\"} ) {
928                    my $LinkBackendReplace = $BackendReplacement;
929                    $LinkBackendReplace =~ s{DefaultItem>(\s+)<Item\sKey}{DefaultItem>\n\t\t\t\t\t\t<Item Key}gsmx;
930                    $LinkBackendReplace =~ s{\t\t<Item\sKey=\"Age\">2</Item>}{<Item Key="Age">1</Item>}gsmx;
931                    $Setting            =~ s{
932                    <Item\sKey=\"DefaultColumns\">(\s+)<Hash>(\s+)<Item\sKey=\"Age\">1</Item>
933                    }
934                    {$LinkBackendReplace}gsmx;
935                }
936
937                # Fill dropdowns with existing values.
938                $Setting =~ s{<\/DefaultItem>(\s*?)<Item\sKey="(.*?)">(0|1|2)<}
939                {<\/DefaultItem>$1\t\t<Item Key="$2" SelectedID="$3"><}gsmx;
940
941                # Only alter <Items> right after </DefaultItem> and before the closing the hash </Hash>
942                my $DropdownItems;
943                if ( $Setting =~ m{<\/DefaultItem>(.+)<\/Hash>\s+^[\s]}smx ) {
944
945                    $DropdownItems = $1;
946
947                    while (
948                        $DropdownItems =~ m{"(0|1|2)"><\/Item>(\s*)<Item\sKey="(.*?)">(0|1|2)<}
949                        )
950                    {
951                        if ( $2 ne 'Default' ) {
952                            $DropdownItems =~ s{><\/Item>(\s*)<Item\sKey="(.*?)">(0|1|2)<}
953                            {></Item>$1<Item Key="$2" SelectedID="$3"><}gsmx;
954                        }
955                    }
956
957                    $DropdownItems =~ s{><\/Item>(\s*)<Item\sKey="Default"\sSelectedID="(0|1)"><}
958                        {></Item>\n\t\t\t\t<Item Key="Default">$2<}gsmx;
959                }
960
961                if ($DropdownItems) {
962                    $Setting =~ s{(<\/DefaultItem>).+(<\/Hash>\s+^[\s])}{$1$DropdownItems$2}msx;
963                }
964
965                # replace tab with spaces
966                $Setting =~ s{\t}{    }gsmx;
967
968                # FAQ.xml
969                # LinkObject::ComplexTable###FAQ
970
971                # ITSMTicket.xml
972                # Ticket::Frontend::AgentTicketAddtlITSMField###DynamicField
973                # Ticket::Frontend::AgentTicketDecision###DynamicField
974
975                # TicketITSMTicket.xml
976                # Ticket::Frontend::AgentTicketPhone###DynamicField
977                # Ticket::Frontend::AgentTicketEmail###DynamicField
978                # Ticket::Frontend::AgentTicketSearch###DynamicField
979                # Ticket::Frontend::AgentTicketZoom###DynamicField
980                # Ticket::Frontend::AgentTicketPriority###DynamicField
981                # Ticket::Frontend::AgentTicketClose###DynamicField
982                # Ticket::Frontend::AgentTicketCompose###DynamicField
983                # Ticket::Frontend::CustomerTicketZoom###DynamicField
984            }
985        }
986
987        # get the needed ArticleTypeMapping from a YML file
988        my $TaskConfig         = $Self->GetTaskConfig( Module => 'MigrateArticleData' );
989        my %ArticleTypeMapping = %{ $TaskConfig->{ArticleTypeMapping} };
990
991        # Migrate Postmaster settings for
992        #   PostMaster::PreFilterModule
993        #   PostMaster::PreCreateFilterModule
994        #   PostMaster::PostFilterModule
995        #   PostMaster::CheckFollowUpModule
996        if (
997            $Setting =~ m{ Name="PostMaster::(PreFilter|PreCreateFilter|PostFilter|CheckFollowUp)Module\#\#\# .+ }xms
998            )
999        {
1000            $Setting
1001                =~ s{<Item Key="X-OTRS-ArticleType">(.*?)</Item>}{<Item Key="X-OTRS-IsVisibleForCustomer">$ArticleTypeMapping{$1}->{Visible}</Item>}g;
1002            $Setting
1003                =~ s{<Item Key="X-OTRS-FollowUp-ArticleType">(.*?)</Item>}{<Item Key="X-OTRS-FollowUp-IsVisibleForCustomer">$ArticleTypeMapping{$1}->{Visible}</Item>}g;
1004            $Setting
1005                =~ s{<Item Key="ArticleType"[^>]*>(.*?)</Item>}{<Item Key="IsVisibleForCustomer" Translatable="1">$ArticleTypeMapping{$1}->{Visible}</Item>}g;
1006            $Setting
1007                =~ s{<Item Key="Module">Kernel::System::PostMaster::Filter::FollowUpArticleTypeCheck</Item>}{<Item Key="Module">Kernel::System::PostMaster::Filter::FollowUpArticleVisibilityCheck</Item>}g;
1008        }
1009
1010        # Remove Group.
1011        $Setting =~ s{\s+<Group>(.*?)</Group>}{}gsmx;
1012
1013        # Update SubGroup to the Navigation.
1014        $Setting =~ s{SubGroup>}{Navigation>}gsmx;
1015
1016        my @NavigationValues = $Setting =~ m{<Navigation>(.*?)</Navigation>}g;
1017        if ( scalar @NavigationValues ) {
1018            my $NavigationValue = $NavigationValues[0];
1019            my $NavigationStr   = $NavigationLookup{$NavigationValue} || $NavigationValue;
1020
1021            if (
1022                scalar @NavigationValues < 2
1023                || !grep { $NavigationStr eq $_ } (
1024                    'Frontend::Admin::ModuleRegistration',
1025                    'Frontend::Agent::ModuleRegistration',
1026                    'Frontend::Customer::ModuleRegistration',
1027                )
1028                )
1029            {
1030                $Setting =~ s{<Navigation>.*?</Navigation>}{<Navigation>$NavigationStr</Navigation>}gsmx;
1031            }
1032        }
1033
1034        # Update Setting to the Value.
1035        $Setting =~ s{Setting>}{Value>}gsmx;
1036
1037        # # Add missing RegEx to all Numbers
1038        $Setting =~ s{<String>(\d+)</String>$}
1039            {<Item ValueType="String" ValueRegex="^\\d+\$">$1</Item>}gsmx;
1040
1041        $Setting =~ s{<String\sValueRegex="">(\d+)</String>}
1042            {<Item ValueType="String" ValueRegex="^\\d+\$">$1</Item>}gsmx;
1043
1044        $Setting =~ s{<String\sValueRegex="\\d\+">(\d+?)</String>}
1045            {<Item ValueType="String" ValueRegex="^\\d+\$">$1</Item>}gsmx;
1046
1047        $Setting =~ s{<String\sValueRegex="\[(.*?)">(\d+)</String>}
1048            {<Item ValueType="String" ValueRegex="^[$1">$2</Item>}gmsx;
1049
1050        # Update string and text-area to items with its corresponding ValueType.
1051        $Setting =~ s{<TextArea(.*?)</TextArea>}{<Item ValueType="Textarea"$1</Item>}gsmx;
1052        $Setting =~ s{<String(.*?)</String>}{<Item ValueType="String"$1</Item>}gsmx;
1053
1054        # Convert password strings
1055        $Setting =~ s{<Item\sValueType="String"(.*?)Type="Password"(.*?)$}
1056            {<Item ValueType="Password"$2}gsmx;
1057        $Setting =~ s{<Item\sKey="Password">(.*?)$}
1058            {<Item Key="Password" ValueType="Password">$1}gsmx;
1059
1060        # Convert TicketType to Entity
1061        $Setting =~ s{<Item\sValueType="String"\sValueRegex=""(.*?)>Unclassified(.*?)$}
1062            {<Item ValueType="Entity" ValueEntityType="Type"$1>Unclassified$2}gsmx;
1063
1064        $Setting =~ m{<ConfigItem\sName="(.*?)"}gsmx;
1065        my $SettingName = $1;
1066
1067        my @SettingsUserModificationPossible = (
1068            'Frontend::Admin::AdminNotificationEvent###RichTextHeight',
1069            'Frontend::Admin::AdminNotificationEvent###RichTextWidth',
1070            'Frontend::CustomerUser::Item###1-GoogleMaps',
1071            'Frontend::CustomerUser::Item###15-OpenTickets',
1072            'Frontend::CustomerUser::Item###16-OpenTicketsForCustomerUserLogin',
1073            'Frontend::CustomerUser::Item###17-ClosedTickets',
1074            'Frontend::CustomerUser::Item###18-ClosedTicketsForCustomerUserLogin',
1075            'Frontend::CustomerUser::Item###2-Google',
1076            'Frontend::CustomerUser::Item###2-LinkedIn',
1077            'Frontend::CustomerUser::Item###3-XING',
1078            'Frontend::ToolBarModule###110-Ticket::AgentTicketQueue',
1079            'Frontend::ToolBarModule###120-Ticket::AgentTicketStatus',
1080            'Frontend::ToolBarModule###130-Ticket::AgentTicketEscalation',
1081            'Frontend::ToolBarModule###140-Ticket::AgentTicketPhone',
1082            'Frontend::ToolBarModule###150-Ticket::AgentTicketEmail',
1083            'Frontend::ToolBarModule###160-Ticket::AgentTicketProcess',
1084            'Frontend::ToolBarModule###210-Ticket::TicketSearchProfile',
1085            'Frontend::ToolBarModule###220-Ticket::TicketSearchFulltext',
1086            'Frontend::ToolBarModule###230-CICSearchCustomerID',
1087            'Frontend::ToolBarModule###240-CICSearchCustomerUser',
1088            'Ticket::Frontend::AgentTicketBounce###StateDefault',
1089            'Ticket::Frontend::AgentTicketBulk###ArticleTypeDefault',
1090            'Ticket::Frontend::AgentTicketBulk###Owner',
1091            'Ticket::Frontend::AgentTicketBulk###Priority',
1092            'Ticket::Frontend::AgentTicketBulk###PriorityDefault',
1093            'Ticket::Frontend::AgentTicketBulk###Responsible',
1094            'Ticket::Frontend::AgentTicketBulk###State',
1095            'Ticket::Frontend::AgentTicketBulk###StateDefault',
1096            'Ticket::Frontend::AgentTicketBulk###TicketType',
1097            'Ticket::Frontend::AgentTicketClose###ArticleTypeDefault',
1098            'Ticket::Frontend::AgentTicketClose###Body',
1099            'Ticket::Frontend::AgentTicketClose###InformAgent',
1100            'Ticket::Frontend::AgentTicketClose###InvolvedAgent',
1101            'Ticket::Frontend::AgentTicketClose###Note',
1102            'Ticket::Frontend::AgentTicketClose###NoteMandatory',
1103            'Ticket::Frontend::AgentTicketClose###Owner',
1104            'Ticket::Frontend::AgentTicketClose###OwnerMandatory',
1105            'Ticket::Frontend::AgentTicketClose###Priority',
1106            'Ticket::Frontend::AgentTicketClose###PriorityDefault',
1107            'Ticket::Frontend::AgentTicketClose###Queue',
1108            'Ticket::Frontend::AgentTicketClose###Responsible',
1109            'Ticket::Frontend::AgentTicketClose###ResponsibleMandatory',
1110            'Ticket::Frontend::AgentTicketClose###RichTextHeight',
1111            'Ticket::Frontend::AgentTicketClose###RichTextWidth',
1112            'Ticket::Frontend::AgentTicketClose###Service',
1113            'Ticket::Frontend::AgentTicketClose###ServiceMandatory',
1114            'Ticket::Frontend::AgentTicketClose###SLAMandatory',
1115            'Ticket::Frontend::AgentTicketClose###State',
1116            'Ticket::Frontend::AgentTicketClose###StateDefault',
1117            'Ticket::Frontend::AgentTicketClose###Subject',
1118            'Ticket::Frontend::AgentTicketClose###TicketType',
1119            'Ticket::Frontend::AgentTicketClose###Title',
1120            'Ticket::Frontend::AgentTicketCompose###DefaultArticleType',
1121            'Ticket::Frontend::AgentTicketCompose###StateDefault',
1122            'Ticket::Frontend::AgentTicketCustomer::CustomerIDReadOnly',
1123            'Ticket::Frontend::AgentTicketEmail::CustomerIDReadOnly',
1124            'Ticket::Frontend::AgentTicketEmail###ArticleType',
1125            'Ticket::Frontend::AgentTicketEmail###Body',
1126            'Ticket::Frontend::AgentTicketEmail###Priority',
1127            'Ticket::Frontend::AgentTicketEmail###RichTextHeight',
1128            'Ticket::Frontend::AgentTicketEmail###RichTextWidth',
1129            'Ticket::Frontend::AgentTicketEmail###ServiceMandatory',
1130            'Ticket::Frontend::AgentTicketEmail###SLAMandatory',
1131            'Ticket::Frontend::AgentTicketEmail###StateDefault',
1132            'Ticket::Frontend::AgentTicketEmail###Subject',
1133            'Ticket::Frontend::AgentTicketEmailOutbound###ArticleTypeDefault',
1134            'Ticket::Frontend::AgentTicketEmailOutbound###RichTextHeight',
1135            'Ticket::Frontend::AgentTicketEmailOutbound###RichTextWidth',
1136            'Ticket::Frontend::AgentTicketEmailOutbound###StateDefault',
1137            'Ticket::Frontend::AgentTicketEscalationView###Order::Default',
1138            'Ticket::Frontend::AgentTicketEscalationView###SortBy::Default',
1139            'Ticket::Frontend::AgentTicketForward###ArticleTypeDefault',
1140            'Ticket::Frontend::AgentTicketForward###RichTextHeight',
1141            'Ticket::Frontend::AgentTicketForward###RichTextWidth',
1142            'Ticket::Frontend::AgentTicketForward###StateDefault',
1143            'Ticket::Frontend::AgentTicketFreeText###ArticleTypeDefault',
1144            'Ticket::Frontend::AgentTicketFreeText###Body',
1145            'Ticket::Frontend::AgentTicketFreeText###InformAgent',
1146            'Ticket::Frontend::AgentTicketFreeText###InvolvedAgent',
1147            'Ticket::Frontend::AgentTicketFreeText###Note',
1148            'Ticket::Frontend::AgentTicketFreeText###NoteMandatory',
1149            'Ticket::Frontend::AgentTicketFreeText###Owner',
1150            'Ticket::Frontend::AgentTicketFreeText###OwnerMandatory',
1151            'Ticket::Frontend::AgentTicketFreeText###Priority',
1152            'Ticket::Frontend::AgentTicketFreeText###PriorityDefault',
1153            'Ticket::Frontend::AgentTicketFreeText###Queue',
1154            'Ticket::Frontend::AgentTicketFreeText###Responsible',
1155            'Ticket::Frontend::AgentTicketFreeText###ResponsibleMandatory',
1156            'Ticket::Frontend::AgentTicketFreeText###RichTextHeight',
1157            'Ticket::Frontend::AgentTicketFreeText###RichTextWidth',
1158            'Ticket::Frontend::AgentTicketFreeText###Service',
1159            'Ticket::Frontend::AgentTicketFreeText###ServiceMandatory',
1160            'Ticket::Frontend::AgentTicketFreeText###SLAMandatory',
1161            'Ticket::Frontend::AgentTicketFreeText###State',
1162            'Ticket::Frontend::AgentTicketFreeText###StateDefault',
1163            'Ticket::Frontend::AgentTicketFreeText###Subject',
1164            'Ticket::Frontend::AgentTicketFreeText###TicketType',
1165            'Ticket::Frontend::AgentTicketFreeText###Title',
1166            'Ticket::Frontend::AgentTicketLockedView###Order::Default',
1167            'Ticket::Frontend::AgentTicketLockedView###SortBy::Default',
1168            'Ticket::Frontend::AgentTicketMerge###RichTextHeight',
1169            'Ticket::Frontend::AgentTicketMerge###RichTextWidth',
1170            'Ticket::Frontend::AgentTicketMove###Body',
1171            'Ticket::Frontend::AgentTicketMove###NextScreen',
1172            'Ticket::Frontend::AgentTicketMove###Note',
1173            'Ticket::Frontend::AgentTicketMove###NoteMandatory',
1174            'Ticket::Frontend::AgentTicketMove###Priority',
1175            'Ticket::Frontend::AgentTicketMove###RichTextHeight',
1176            'Ticket::Frontend::AgentTicketMove###RichTextWidth',
1177            'Ticket::Frontend::AgentTicketMove###State',
1178            'Ticket::Frontend::AgentTicketMove###Subject',
1179            'Ticket::Frontend::AgentTicketNote###ArticleTypeDefault',
1180            'Ticket::Frontend::AgentTicketNote###Body',
1181            'Ticket::Frontend::AgentTicketNote###InformAgent',
1182            'Ticket::Frontend::AgentTicketNote###InvolvedAgent',
1183            'Ticket::Frontend::AgentTicketNote###Note',
1184            'Ticket::Frontend::AgentTicketNote###NoteMandatory',
1185            'Ticket::Frontend::AgentTicketNote###Owner',
1186            'Ticket::Frontend::AgentTicketNote###OwnerMandatory',
1187            'Ticket::Frontend::AgentTicketNote###Priority',
1188            'Ticket::Frontend::AgentTicketNote###PriorityDefault',
1189            'Ticket::Frontend::AgentTicketNote###Queue',
1190            'Ticket::Frontend::AgentTicketNote###Responsible',
1191            'Ticket::Frontend::AgentTicketNote###ResponsibleMandatory',
1192            'Ticket::Frontend::AgentTicketNote###RichTextHeight',
1193            'Ticket::Frontend::AgentTicketNote###RichTextWidth',
1194            'Ticket::Frontend::AgentTicketNote###Service',
1195            'Ticket::Frontend::AgentTicketNote###ServiceMandatory',
1196            'Ticket::Frontend::AgentTicketNote###SLAMandatory',
1197            'Ticket::Frontend::AgentTicketNote###State',
1198            'Ticket::Frontend::AgentTicketNote###StateDefault',
1199            'Ticket::Frontend::AgentTicketNote###Subject',
1200            'Ticket::Frontend::AgentTicketNote###TicketType',
1201            'Ticket::Frontend::AgentTicketNote###Title',
1202            'Ticket::Frontend::AgentTicketQueue###Blink',
1203            'Ticket::Frontend::AgentTicketQueue###HideEmptyQueues',
1204            'Ticket::Frontend::AgentTicketQueue###HighlightAge1',
1205            'Ticket::Frontend::AgentTicketQueue###HighlightAge2',
1206            'Ticket::Frontend::AgentTicketQueue###Order::Default',
1207            'Ticket::Frontend::AgentTicketQueue###QueueSort',
1208            'Ticket::Frontend::AgentTicketQueue###SortBy::Default',
1209            'Ticket::Frontend::AgentTicketSearch###Defaults###ArticleCreateTimePoint',
1210            'Ticket::Frontend::AgentTicketSearch###Defaults###ArticleCreateTimeSlot',
1211            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Body',
1212            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Cc',
1213            'Ticket::Frontend::AgentTicketSearch###Defaults###CustomerID',
1214            'Ticket::Frontend::AgentTicketSearch###Defaults###CustomerUserLogin',
1215            'Ticket::Frontend::AgentTicketSearch###Defaults###DynamicField',
1216            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_From',
1217            'Ticket::Frontend::AgentTicketSearch###Defaults###Fulltext',
1218            'Ticket::Frontend::AgentTicketSearch###Defaults###QueueIDs',
1219            'Ticket::Frontend::AgentTicketSearch###Defaults###SearchInArchive',
1220            'Ticket::Frontend::AgentTicketSearch###Defaults###StateIDs',
1221            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Subject',
1222            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketChangeTimePoint',
1223            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketChangeTimeSlot',
1224            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCloseTimePoint',
1225            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCloseTimeSlot',
1226            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCreateTimePoint',
1227            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCreateTimeSlot',
1228            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketEscalationTimePoint',
1229            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketEscalationTimeSlot',
1230            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketNumber',
1231            'Ticket::Frontend::AgentTicketSearch###Defaults###Title',
1232            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_To',
1233            'Ticket::Frontend::AgentTicketSearch###Order::Default',
1234            'Ticket::Frontend::AgentTicketSearch###SortBy::Default',
1235            'Ticket::Frontend::AgentTicketService###Order::Default',
1236            'Ticket::Frontend::AgentTicketService###SortBy::Default',
1237            'Ticket::Frontend::AgentTicketStatusView###Order::Default',
1238            'Ticket::Frontend::AgentTicketStatusView###SortBy::Default',
1239            'Ticket::Frontend::AgentTicketWatchView###Order::Default',
1240            'Ticket::Frontend::AgentTicketWatchView###SortBy::Default',
1241            'Ticket::Frontend::AgentTicketZoom###ProcessDisplay',
1242            'Ticket::Frontend::HTMLArticleHeightDefault',
1243            'Ticket::Frontend::HTMLArticleHeightMax',
1244            'Ticket::Frontend::MaxArticlesPerPage',
1245            'Ticket::Frontend::PendingDiffTime',
1246            'Ticket::Frontend::PlainView',
1247            'Ticket::Frontend::TicketArticleFilter',
1248            'Ticket::Frontend::ZoomCollectMeta',
1249            'Ticket::Frontend::ZoomExpandSort',
1250            'Ticket::Frontend::ZoomRichTextForce',
1251            'Ticket::UseArticleColors',
1252            'Ticket::ZoomTimeDisplay',
1253            'TimeInputFormat',
1254        );
1255
1256        if ( grep { $SettingName eq $_ } @SettingsUserModificationPossible ) {
1257            $Setting =~ s{(ConfigItem\sName=".*?")}{$1 UserModificationPossible="1"}gsmx;
1258        }
1259
1260        my @SettingsUserModificationActive = (
1261            'Frontend::ToolBarModule###110-Ticket::AgentTicketQueue',
1262            'Frontend::ToolBarModule###120-Ticket::AgentTicketStatus',
1263            'Frontend::ToolBarModule###130-Ticket::AgentTicketEscalation',
1264            'Frontend::ToolBarModule###140-Ticket::AgentTicketPhone',
1265            'Frontend::ToolBarModule###150-Ticket::AgentTicketEmail',
1266            'Frontend::ToolBarModule###160-Ticket::AgentTicketProcess',
1267            'Frontend::ToolBarModule###210-Ticket::TicketSearchProfile',
1268            'Frontend::ToolBarModule###230-CICSearchCustomerID',
1269            'Frontend::ToolBarModule###240-CICSearchCustomerUser',
1270            'Ticket::Frontend::AgentTicketEscalationView###Order::Default',
1271            'Ticket::Frontend::AgentTicketEscalationView###SortBy::Default',
1272            'Ticket::Frontend::AgentTicketLockedView###Order::Default',
1273            'Ticket::Frontend::AgentTicketLockedView###SortBy::Default',
1274            'Ticket::Frontend::AgentTicketMove###NextScreen',
1275            'Ticket::Frontend::AgentTicketQueue###Blink',
1276            'Ticket::Frontend::AgentTicketQueue###HideEmptyQueues',
1277            'Ticket::Frontend::AgentTicketQueue###Order::Default',
1278            'Ticket::Frontend::AgentTicketQueue###QueueSort',
1279            'Ticket::Frontend::AgentTicketQueue###SortBy::Default',
1280            'Ticket::Frontend::AgentTicketSearch###Defaults###ArticleCreateTimePoint',
1281            'Ticket::Frontend::AgentTicketSearch###Defaults###ArticleCreateTimeSlot',
1282            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Body',
1283            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Cc',
1284            'Ticket::Frontend::AgentTicketSearch###Defaults###CustomerID',
1285            'Ticket::Frontend::AgentTicketSearch###Defaults###CustomerUserLogin',
1286            'Ticket::Frontend::AgentTicketSearch###Defaults###DynamicField',
1287            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_From',
1288            'Ticket::Frontend::AgentTicketSearch###Defaults###Fulltext',
1289            'Ticket::Frontend::AgentTicketSearch###Defaults###QueueIDs',
1290            'Ticket::Frontend::AgentTicketSearch###Defaults###SearchInArchive',
1291            'Ticket::Frontend::AgentTicketSearch###Defaults###StateIDs',
1292            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Subject',
1293            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketChangeTimePoint',
1294            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketChangeTimeSlot',
1295            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCloseTimePoint',
1296            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCloseTimeSlot',
1297            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCreateTimePoint',
1298            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCreateTimeSlot',
1299            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketEscalationTimePoint',
1300            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketEscalationTimeSlot',
1301            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketNumber',
1302            'Ticket::Frontend::AgentTicketSearch###Defaults###Title',
1303            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_To',
1304            'Ticket::Frontend::AgentTicketSearch###Order::Default',
1305            'Ticket::Frontend::AgentTicketSearch###SortBy::Default',
1306            'Ticket::Frontend::AgentTicketService###Order::Default',
1307            'Ticket::Frontend::AgentTicketService###SortBy::Default',
1308            'Ticket::Frontend::AgentTicketStatusView###Order::Default',
1309            'Ticket::Frontend::AgentTicketStatusView###SortBy::Default',
1310            'Ticket::Frontend::AgentTicketWatchView###Order::Default',
1311            'Ticket::Frontend::AgentTicketWatchView###SortBy::Default',
1312            'Ticket::Frontend::PendingDiffTime',
1313            'Ticket::Frontend::ZoomExpandSort',
1314            'Ticket::ZoomTimeDisplay',
1315        );
1316
1317        if ( grep { $SettingName eq $_ } @SettingsUserModificationActive ) {
1318            $Setting =~ s{(ConfigItem\sName=".*?")}{$1 UserModificationActive="1"}gsmx;
1319        }
1320
1321        my @SettingsToDisable = (
1322            'PGP::Bin',
1323            'SMIME::Bin',
1324            'SMIME::CertPath',
1325            'SMIME::PrivatePath',
1326        );
1327
1328        if ( grep { $SettingName eq $_ } @SettingsToDisable ) {
1329            $Setting =~ s{(ConfigItem\sName=".*?"\sRequired=)"1"(\sValid=)"1"}{$1"0"$2"0"}gsmx;
1330        }
1331
1332        my %SettingsUserPreferencesGroup = (
1333            'Frontend::Admin::AdminNotificationEvent###RichTextHeight'                   => 'Advanced',
1334            'Frontend::Admin::AdminNotificationEvent###RichTextWidth'                    => 'Advanced',
1335            'Frontend::CustomerUser::Item###1-GoogleMaps'                                => 'Advanced',
1336            'Frontend::CustomerUser::Item###15-OpenTickets'                              => 'Advanced',
1337            'Frontend::CustomerUser::Item###16-OpenTicketsForCustomerUserLogin'          => 'Advanced',
1338            'Frontend::CustomerUser::Item###17-ClosedTickets'                            => 'Advanced',
1339            'Frontend::CustomerUser::Item###18-ClosedTicketsForCustomerUserLogin'        => 'Advanced',
1340            'Frontend::CustomerUser::Item###2-Google'                                    => 'Advanced',
1341            'Frontend::CustomerUser::Item###2-LinkedIn'                                  => 'Advanced',
1342            'Frontend::CustomerUser::Item###3-XING'                                      => 'Advanced',
1343            'Frontend::ToolBarModule###110-Ticket::AgentTicketQueue'                     => 'Advanced',
1344            'Frontend::ToolBarModule###120-Ticket::AgentTicketStatus'                    => 'Advanced',
1345            'Frontend::ToolBarModule###130-Ticket::AgentTicketEscalation'                => 'Advanced',
1346            'Frontend::ToolBarModule###140-Ticket::AgentTicketPhone'                     => 'Advanced',
1347            'Frontend::ToolBarModule###150-Ticket::AgentTicketEmail'                     => 'Advanced',
1348            'Frontend::ToolBarModule###160-Ticket::AgentTicketProcess'                   => 'Advanced',
1349            'Frontend::ToolBarModule###210-Ticket::TicketSearchProfile'                  => 'Advanced',
1350            'Frontend::ToolBarModule###220-Ticket::TicketSearchFulltext'                 => 'Advanced',
1351            'Frontend::ToolBarModule###230-CICSearchCustomerID'                          => 'Advanced',
1352            'Frontend::ToolBarModule###240-CICSearchCustomerUser'                        => 'Advanced',
1353            'Ticket::Frontend::AgentTicketBounce###StateDefault'                         => 'Advanced',
1354            'Ticket::Frontend::AgentTicketBulk###ArticleTypeDefault'                     => 'Advanced',
1355            'Ticket::Frontend::AgentTicketBulk###Owner'                                  => 'Advanced',
1356            'Ticket::Frontend::AgentTicketBulk###Priority'                               => 'Advanced',
1357            'Ticket::Frontend::AgentTicketBulk###PriorityDefault'                        => 'Advanced',
1358            'Ticket::Frontend::AgentTicketBulk###Responsible'                            => 'Advanced',
1359            'Ticket::Frontend::AgentTicketBulk###State'                                  => 'Advanced',
1360            'Ticket::Frontend::AgentTicketBulk###StateDefault'                           => 'Advanced',
1361            'Ticket::Frontend::AgentTicketBulk###TicketType'                             => 'Advanced',
1362            'Ticket::Frontend::AgentTicketClose###ArticleTypeDefault'                    => 'Advanced',
1363            'Ticket::Frontend::AgentTicketClose###Body'                                  => 'Advanced',
1364            'Ticket::Frontend::AgentTicketClose###InformAgent'                           => 'Advanced',
1365            'Ticket::Frontend::AgentTicketClose###InvolvedAgent'                         => 'Advanced',
1366            'Ticket::Frontend::AgentTicketClose###Note'                                  => 'Advanced',
1367            'Ticket::Frontend::AgentTicketClose###NoteMandatory'                         => 'Advanced',
1368            'Ticket::Frontend::AgentTicketClose###Owner'                                 => 'Advanced',
1369            'Ticket::Frontend::AgentTicketClose###OwnerMandatory'                        => 'Advanced',
1370            'Ticket::Frontend::AgentTicketClose###Priority'                              => 'Advanced',
1371            'Ticket::Frontend::AgentTicketClose###PriorityDefault'                       => 'Advanced',
1372            'Ticket::Frontend::AgentTicketClose###Queue'                                 => 'Advanced',
1373            'Ticket::Frontend::AgentTicketClose###Responsible'                           => 'Advanced',
1374            'Ticket::Frontend::AgentTicketClose###ResponsibleMandatory'                  => 'Advanced',
1375            'Ticket::Frontend::AgentTicketClose###RichTextHeight'                        => 'Advanced',
1376            'Ticket::Frontend::AgentTicketClose###RichTextWidth'                         => 'Advanced',
1377            'Ticket::Frontend::AgentTicketClose###Service'                               => 'Advanced',
1378            'Ticket::Frontend::AgentTicketClose###ServiceMandatory'                      => 'Advanced',
1379            'Ticket::Frontend::AgentTicketClose###SLAMandatory'                          => 'Advanced',
1380            'Ticket::Frontend::AgentTicketClose###State'                                 => 'Advanced',
1381            'Ticket::Frontend::AgentTicketClose###StateDefault'                          => 'Advanced',
1382            'Ticket::Frontend::AgentTicketClose###Subject'                               => 'Advanced',
1383            'Ticket::Frontend::AgentTicketClose###TicketType'                            => 'Advanced',
1384            'Ticket::Frontend::AgentTicketClose###Title'                                 => 'Advanced',
1385            'Ticket::Frontend::AgentTicketCompose###DefaultArticleType'                  => 'Advanced',
1386            'Ticket::Frontend::AgentTicketCompose###StateDefault'                        => 'Advanced',
1387            'Ticket::Frontend::AgentTicketCustomer::CustomerIDReadOnly'                  => 'Advanced',
1388            'Ticket::Frontend::AgentTicketEmail::CustomerIDReadOnly'                     => 'Advanced',
1389            'Ticket::Frontend::AgentTicketEmail###ArticleType'                           => 'Advanced',
1390            'Ticket::Frontend::AgentTicketEmail###Body'                                  => 'Advanced',
1391            'Ticket::Frontend::AgentTicketEmail###Priority'                              => 'Advanced',
1392            'Ticket::Frontend::AgentTicketEmail###RichTextHeight'                        => 'Advanced',
1393            'Ticket::Frontend::AgentTicketEmail###RichTextWidth'                         => 'Advanced',
1394            'Ticket::Frontend::AgentTicketEmail###ServiceMandatory'                      => 'Advanced',
1395            'Ticket::Frontend::AgentTicketEmail###SLAMandatory'                          => 'Advanced',
1396            'Ticket::Frontend::AgentTicketEmail###StateDefault'                          => 'Advanced',
1397            'Ticket::Frontend::AgentTicketEmail###Subject'                               => 'Advanced',
1398            'Ticket::Frontend::AgentTicketEmailOutbound###ArticleTypeDefault'            => 'Advanced',
1399            'Ticket::Frontend::AgentTicketEmailOutbound###RichTextHeight'                => 'Advanced',
1400            'Ticket::Frontend::AgentTicketEmailOutbound###RichTextWidth'                 => 'Advanced',
1401            'Ticket::Frontend::AgentTicketEmailOutbound###StateDefault'                  => 'Advanced',
1402            'Ticket::Frontend::AgentTicketEscalationView###Order::Default'               => 'Advanced',
1403            'Ticket::Frontend::AgentTicketEscalationView###SortBy::Default'              => 'Advanced',
1404            'Ticket::Frontend::AgentTicketForward###ArticleTypeDefault'                  => 'Advanced',
1405            'Ticket::Frontend::AgentTicketForward###RichTextHeight'                      => 'Advanced',
1406            'Ticket::Frontend::AgentTicketForward###RichTextWidth'                       => 'Advanced',
1407            'Ticket::Frontend::AgentTicketForward###StateDefault'                        => 'Advanced',
1408            'Ticket::Frontend::AgentTicketFreeText###ArticleTypeDefault'                 => 'Advanced',
1409            'Ticket::Frontend::AgentTicketFreeText###Body'                               => 'Advanced',
1410            'Ticket::Frontend::AgentTicketFreeText###InformAgent'                        => 'Advanced',
1411            'Ticket::Frontend::AgentTicketFreeText###InvolvedAgent'                      => 'Advanced',
1412            'Ticket::Frontend::AgentTicketFreeText###Note'                               => 'Advanced',
1413            'Ticket::Frontend::AgentTicketFreeText###NoteMandatory'                      => 'Advanced',
1414            'Ticket::Frontend::AgentTicketFreeText###Owner'                              => 'Advanced',
1415            'Ticket::Frontend::AgentTicketFreeText###OwnerMandatory'                     => 'Advanced',
1416            'Ticket::Frontend::AgentTicketFreeText###Priority'                           => 'Advanced',
1417            'Ticket::Frontend::AgentTicketFreeText###PriorityDefault'                    => 'Advanced',
1418            'Ticket::Frontend::AgentTicketFreeText###Queue'                              => 'Advanced',
1419            'Ticket::Frontend::AgentTicketFreeText###Responsible'                        => 'Advanced',
1420            'Ticket::Frontend::AgentTicketFreeText###ResponsibleMandatory'               => 'Advanced',
1421            'Ticket::Frontend::AgentTicketFreeText###RichTextHeight'                     => 'Advanced',
1422            'Ticket::Frontend::AgentTicketFreeText###RichTextWidth'                      => 'Advanced',
1423            'Ticket::Frontend::AgentTicketFreeText###Service'                            => 'Advanced',
1424            'Ticket::Frontend::AgentTicketFreeText###ServiceMandatory'                   => 'Advanced',
1425            'Ticket::Frontend::AgentTicketFreeText###SLAMandatory'                       => 'Advanced',
1426            'Ticket::Frontend::AgentTicketFreeText###State'                              => 'Advanced',
1427            'Ticket::Frontend::AgentTicketFreeText###StateDefault'                       => 'Advanced',
1428            'Ticket::Frontend::AgentTicketFreeText###Subject'                            => 'Advanced',
1429            'Ticket::Frontend::AgentTicketFreeText###TicketType'                         => 'Advanced',
1430            'Ticket::Frontend::AgentTicketFreeText###Title'                              => 'Advanced',
1431            'Ticket::Frontend::AgentTicketLockedView###Order::Default'                   => 'Advanced',
1432            'Ticket::Frontend::AgentTicketLockedView###SortBy::Default'                  => 'Advanced',
1433            'Ticket::Frontend::AgentTicketMerge###RichTextHeight'                        => 'Advanced',
1434            'Ticket::Frontend::AgentTicketMerge###RichTextWidth'                         => 'Advanced',
1435            'Ticket::Frontend::AgentTicketMove###Body'                                   => 'Advanced',
1436            'Ticket::Frontend::AgentTicketMove###NextScreen'                             => 'Advanced',
1437            'Ticket::Frontend::AgentTicketMove###Note'                                   => 'Advanced',
1438            'Ticket::Frontend::AgentTicketMove###NoteMandatory'                          => 'Advanced',
1439            'Ticket::Frontend::AgentTicketMove###Priority'                               => 'Advanced',
1440            'Ticket::Frontend::AgentTicketMove###RichTextHeight'                         => 'Advanced',
1441            'Ticket::Frontend::AgentTicketMove###RichTextWidth'                          => 'Advanced',
1442            'Ticket::Frontend::AgentTicketMove###State'                                  => 'Advanced',
1443            'Ticket::Frontend::AgentTicketMove###Subject'                                => 'Advanced',
1444            'Ticket::Frontend::AgentTicketNote###ArticleTypeDefault'                     => 'Advanced',
1445            'Ticket::Frontend::AgentTicketNote###Body'                                   => 'Advanced',
1446            'Ticket::Frontend::AgentTicketNote###InformAgent'                            => 'Advanced',
1447            'Ticket::Frontend::AgentTicketNote###InvolvedAgent'                          => 'Advanced',
1448            'Ticket::Frontend::AgentTicketNote###Note'                                   => 'Advanced',
1449            'Ticket::Frontend::AgentTicketNote###NoteMandatory'                          => 'Advanced',
1450            'Ticket::Frontend::AgentTicketNote###Owner'                                  => 'Advanced',
1451            'Ticket::Frontend::AgentTicketNote###OwnerMandatory'                         => 'Advanced',
1452            'Ticket::Frontend::AgentTicketNote###Priority'                               => 'Advanced',
1453            'Ticket::Frontend::AgentTicketNote###PriorityDefault'                        => 'Advanced',
1454            'Ticket::Frontend::AgentTicketNote###Queue'                                  => 'Advanced',
1455            'Ticket::Frontend::AgentTicketNote###Responsible'                            => 'Advanced',
1456            'Ticket::Frontend::AgentTicketNote###ResponsibleMandatory'                   => 'Advanced',
1457            'Ticket::Frontend::AgentTicketNote###RichTextHeight'                         => 'Advanced',
1458            'Ticket::Frontend::AgentTicketNote###RichTextWidth'                          => 'Advanced',
1459            'Ticket::Frontend::AgentTicketNote###Service'                                => 'Advanced',
1460            'Ticket::Frontend::AgentTicketNote###ServiceMandatory'                       => 'Advanced',
1461            'Ticket::Frontend::AgentTicketNote###SLAMandatory'                           => 'Advanced',
1462            'Ticket::Frontend::AgentTicketNote###State'                                  => 'Advanced',
1463            'Ticket::Frontend::AgentTicketNote###StateDefault'                           => 'Advanced',
1464            'Ticket::Frontend::AgentTicketNote###Subject'                                => 'Advanced',
1465            'Ticket::Frontend::AgentTicketNote###TicketType'                             => 'Advanced',
1466            'Ticket::Frontend::AgentTicketNote###Title'                                  => 'Advanced',
1467            'Ticket::Frontend::AgentTicketQueue###Blink'                                 => 'Advanced',
1468            'Ticket::Frontend::AgentTicketQueue###HideEmptyQueues'                       => 'Advanced',
1469            'Ticket::Frontend::AgentTicketQueue###HighlightAge1'                         => 'Advanced',
1470            'Ticket::Frontend::AgentTicketQueue###HighlightAge2'                         => 'Advanced',
1471            'Ticket::Frontend::AgentTicketQueue###Order::Default'                        => 'Advanced',
1472            'Ticket::Frontend::AgentTicketQueue###QueueSort'                             => 'Advanced',
1473            'Ticket::Frontend::AgentTicketQueue###SortBy::Default'                       => 'Advanced',
1474            'Ticket::Frontend::AgentTicketSearch###Defaults###ArticleCreateTimePoint'    => 'Advanced',
1475            'Ticket::Frontend::AgentTicketSearch###Defaults###ArticleCreateTimeSlot'     => 'Advanced',
1476            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Body'             => 'Advanced',
1477            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Cc'               => 'Advanced',
1478            'Ticket::Frontend::AgentTicketSearch###Defaults###CustomerID'                => 'Advanced',
1479            'Ticket::Frontend::AgentTicketSearch###Defaults###CustomerUserLogin'         => 'Advanced',
1480            'Ticket::Frontend::AgentTicketSearch###Defaults###DynamicField'              => 'Advanced',
1481            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_From'             => 'Advanced',
1482            'Ticket::Frontend::AgentTicketSearch###Defaults###Fulltext'                  => 'Advanced',
1483            'Ticket::Frontend::AgentTicketSearch###Defaults###QueueIDs'                  => 'Advanced',
1484            'Ticket::Frontend::AgentTicketSearch###Defaults###SearchInArchive'           => 'Advanced',
1485            'Ticket::Frontend::AgentTicketSearch###Defaults###StateIDs'                  => 'Advanced',
1486            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Subject'          => 'Advanced',
1487            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketChangeTimePoint'     => 'Advanced',
1488            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketChangeTimeSlot'      => 'Advanced',
1489            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCloseTimePoint'      => 'Advanced',
1490            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCloseTimeSlot'       => 'Advanced',
1491            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCreateTimePoint'     => 'Advanced',
1492            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketCreateTimeSlot'      => 'Advanced',
1493            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketEscalationTimePoint' => 'Advanced',
1494            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketEscalationTimeSlot'  => 'Advanced',
1495            'Ticket::Frontend::AgentTicketSearch###Defaults###TicketNumber'              => 'Advanced',
1496            'Ticket::Frontend::AgentTicketSearch###Defaults###Title'                     => 'Advanced',
1497            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_To'               => 'Advanced',
1498            'Ticket::Frontend::AgentTicketSearch###Order::Default'                       => 'Advanced',
1499            'Ticket::Frontend::AgentTicketSearch###SortBy::Default'                      => 'Advanced',
1500            'Ticket::Frontend::AgentTicketService###Order::Default'                      => 'Advanced',
1501            'Ticket::Frontend::AgentTicketService###SortBy::Default'                     => 'Advanced',
1502            'Ticket::Frontend::AgentTicketStatusView###Order::Default'                   => 'Advanced',
1503            'Ticket::Frontend::AgentTicketStatusView###SortBy::Default'                  => 'Advanced',
1504            'Ticket::Frontend::AgentTicketWatchView###Order::Default'                    => 'Advanced',
1505            'Ticket::Frontend::AgentTicketWatchView###SortBy::Default'                   => 'Advanced',
1506            'Ticket::Frontend::AgentTicketZoom###ProcessDisplay'                         => 'Advanced',
1507            'Ticket::Frontend::HTMLArticleHeightDefault'                                 => 'Advanced',
1508            'Ticket::Frontend::HTMLArticleHeightMax'                                     => 'Advanced',
1509            'Ticket::Frontend::MaxArticlesPerPage'                                       => 'Advanced',
1510            'Ticket::Frontend::PendingDiffTime'                                          => 'Advanced',
1511            'Ticket::Frontend::PlainView'                                                => 'Advanced',
1512            'Ticket::Frontend::TicketArticleFilter'                                      => 'Advanced',
1513            'Ticket::Frontend::ZoomCollectMeta'                                          => 'Advanced',
1514            'Ticket::Frontend::ZoomExpandSort'                                           => 'Advanced',
1515            'Ticket::Frontend::ZoomRichTextForce'                                        => 'Advanced',
1516            'Ticket::UseArticleColors'                                                   => 'Advanced',
1517            'Ticket::ZoomTimeDisplay'                                                    => 'Advanced',
1518            'TimeInputFormat'                                                            => 'Advanced',
1519        );
1520
1521        if ( $SettingsUserPreferencesGroup{$SettingName} ) {
1522            $Setting
1523                =~ s{(ConfigItem\sName=".*?")}{$1 UserPreferencesGroup="$SettingsUserPreferencesGroup{$SettingName}"}gsmx;
1524        }
1525
1526        if ( $Setting =~ m{Name=\"DashboardBackend\#\#\#} ) {
1527            $Setting =~ s{\n([ ]*)(<\/Hash>\n[ ]*<\/Value>)}{\n$1    <Item Key="Mandatory">0</Item>\n$1$2}xms;
1528        }
1529    }
1530
1531    my $Result = join( "", @Settings );
1532
1533    # Rename ConfigItem to Setting.
1534    $Result =~ s{<ConfigItem}{<Setting}gsmx;
1535    $Result =~ s{</ConfigItem}{</Setting}gsmx;
1536
1537    # Remove empty lines
1538    $Result =~ s{>\n\n\s}{>\n }gsmx;
1539
1540    # Remove white space at the end of the file
1541    $Result =~ s{</otrs_config>.*}{</otrs_config>}gsmx;
1542
1543    # Add new line at the end
1544    $Result .= "\n";
1545
1546    return $Result;
1547}
1548
1549=head2 MigrateConfigEffectiveValues()
1550
1551Migrate the configs effective values to the new format for OTRS 6.
1552
1553    my $Result = $SysConfigMigrationObject->MigrateConfigEffectiveValues(
1554        FileClass       => $FileClass,
1555        FilePath        => $FilePath,
1556        NoOutput        => 1,                                       # ( 0 | 1 ) optional, default 0.
1557                                                                    # if set to 1 no info output will be printed to the screen.
1558        PackageSettings => [                                        # (optional) only migrate the given package settings
1559            'Frontend::Module###AdminGeneralCatalog',
1560            'Frontend::NavigationModule###AdminGeneralCatalog',
1561            'GeneralCatalogPreferences###Comment2',
1562            'GeneralCatalogPreferences###Permissions',
1563            'Loader::Agent::CommonJS###100-GeneralCatalog'
1564        ],
1565        PackageLookupNewConfigName => {
1566            'Ticket::EventModulePost###999-GenericInterface' => 'Ticket::EventModulePost###9900-GenericInterface',
1567        },
1568        ReturnMigratedSettingsCounts => 1,                          # (optional) returns an array with counts of un/successful migrated settings
1569    );
1570
1571Returns:
1572
1573    $Result = 1;    # True on success or false on error.
1574                    # or
1575                    # if ReturnMigratedSettingsCounts parameter is set
1576    $Result =  {
1577        AllSettingsCount      => 1,
1578        MissingSettings       => [],
1579        UnsuccessfullSettings => [],
1580    };
1581
1582=cut
1583
1584sub MigrateConfigEffectiveValues {
1585    my ( $Self, %Param ) = @_;
1586
1587    for my $Needed (qw(FileClass FilePath)) {
1588        if ( !$Param{$Needed} ) {
1589            $Kernel::OM->Get('Kernel::System::Log')->Log(
1590                Priority => 'error',
1591                Message  => "Need $Needed!",
1592            );
1593            return;
1594        }
1595    }
1596
1597    my $SysConfigObject = $Kernel::OM->Get('Kernel::System::SysConfig');
1598
1599    my %OTRS5Config;
1600    delete $INC{ $Param{FilePath} };
1601    $Kernel::OM->Get('Kernel::System::Main')->Require( $Param{FileClass} );
1602    $Param{FileClass}->Load( \%OTRS5Config );
1603
1604    my $OTRS5ConfigFileContentList = $Kernel::OM->Get('Kernel::System::Main')->FileRead(
1605        Location => $Param{FilePath},
1606        Result   => 'ARRAY',
1607    );
1608
1609    my @DisabledOTRS5Config;
1610    for my $Line ( @{$OTRS5ConfigFileContentList} ) {
1611
1612        # Check if the line starts with a delete.
1613        if ( $Line =~ m{ \A delete[ ]\$Self->\{(.+)\};}xms ) {
1614            my $DisabledSettingString = $1;
1615            $DisabledSettingString =~ s{['"]}{}xmsg;
1616            $DisabledSettingString =~ s{\}->\{}{###}xmsg;
1617            push @DisabledOTRS5Config, $DisabledSettingString;
1618        }
1619    }
1620
1621    # get all OTRS 6 default settings
1622    my @DefaultSettings = $SysConfigObject->ConfigurationList();
1623
1624    # search for settings with ### in the name
1625    # my @SearchResult = grep /###/, sort values %DefaultSettings;
1626    my @SearchResult = grep { $_->{Name} =~ m{###} } @DefaultSettings;
1627
1628    # find all the setting which have sublevels and store them in a hash for OTRS 6
1629    my %SettingsWithSubLevelsOTRS6;
1630    for my $Setting (@SearchResult) {
1631
1632        my @SettingNameParts = split /###/, $Setting->{Name};
1633
1634        my $FirstLevelKey = shift @SettingNameParts;
1635        my $LastLevelKey  = pop @SettingNameParts;
1636
1637        if (
1638            @SettingNameParts
1639
1640            # Skip any setting with more than one sub-levels in hash key (unsupported in OTRS 5).
1641            && !defined $SettingsWithSubLevelsOTRS6{$FirstLevelKey}->{ $SettingNameParts[0] }
1642            )
1643        {
1644            $SettingsWithSubLevelsOTRS6{$FirstLevelKey}->{ $SettingNameParts[0] }->{$LastLevelKey} = 1;
1645        }
1646        else {
1647            $SettingsWithSubLevelsOTRS6{$FirstLevelKey}->{$LastLevelKey} = 1;
1648        }
1649    }
1650
1651    # get the needed ArticleTypeMapping from a YML file (needed for Postmaster filter settings later)
1652    my $TaskConfig         = $Self->GetTaskConfig( Module => 'MigrateArticleData' );
1653    my %ArticleTypeMapping = %{ $TaskConfig->{ArticleTypeMapping} };
1654
1655    # build a lookup hash of all given package settings
1656    my %PackageSettingLookup;
1657    if ( IsArrayRefWithData( $Param{PackageSettings} ) ) {
1658        %PackageSettingLookup = map { $_ => 1 } @{ $Param{PackageSettings} };
1659    }
1660
1661    # to store settings which do not exist in OTRS 6
1662    my @MissingSettings;
1663
1664    # to store unsuccessfull settings which could not be migrated
1665    my @UnsuccessfullSettings;
1666
1667    # Add an additional mapping for 2-Level settings, which have a renamed first part.
1668    if ( $Param{PackageLookupNewConfigName} ) {
1669
1670        my %AdditionalMapping;
1671        for my $OldName ( sort keys %{ $Param{PackageLookupNewConfigName} } ) {
1672            my $NewName = $Param{PackageLookupNewConfigName}->{$OldName};
1673
1674            $OldName =~ s{#.*\z}{}ms;
1675            $NewName =~ s{#.*\z}{}ms;
1676            $AdditionalMapping{$OldName} = $NewName;
1677        }
1678
1679        %{ $Param{PackageLookupNewConfigName} } = ( %{ $Param{PackageLookupNewConfigName} }, %AdditionalMapping );
1680    }
1681
1682    SETTINGNAME:
1683    for my $SettingName ( sort keys %OTRS5Config ) {
1684
1685        # skip loader common settings
1686        next SETTINGNAME if $SettingName eq 'Loader::Agent::CommonCSS';
1687        next SETTINGNAME if $SettingName eq 'Loader::Agent::CommonJS';
1688        next SETTINGNAME if $SettingName eq 'Loader::Customer::CommonCSS';
1689        next SETTINGNAME if $SettingName eq 'Loader::Customer::CommonJS';
1690
1691        # skip no longer existing sysconfig settings
1692        next SETTINGNAME if $SettingName eq 'CustomerPreferencesView';
1693        next SETTINGNAME if $SettingName eq 'DisableMSIFrameSecurityRestricted';
1694        next SETTINGNAME if $SettingName eq 'Frontend::AnimationEnabled';
1695        next SETTINGNAME if $SettingName eq 'LogModule::SysLog::LogSock';
1696        next SETTINGNAME if $SettingName eq 'PreferencesView';
1697        next SETTINGNAME if $SettingName eq 'Ticket::Frontend::ComposeExcludeCcRecipients';
1698        next SETTINGNAME if $SettingName eq 'TimeZoneUser';
1699        next SETTINGNAME if $SettingName eq 'TimeZoneUserBrowserAutoOffset';
1700        next SETTINGNAME if $SettingName eq 'Ticket::StorageModule';
1701        next SETTINGNAME if $SettingName eq 'Ticket::StorageModule::CheckAllBackends';
1702        next SETTINGNAME if $SettingName eq 'ArticleDir';
1703
1704        my $CheckSubLevels;
1705        if ( $SettingsWithSubLevelsOTRS6{$SettingName} ) {
1706            $CheckSubLevels = 1;
1707        }
1708        elsif (
1709            $Param{PackageLookupNewConfigName}
1710            && $Param{PackageLookupNewConfigName}->{$SettingName}
1711            && $SettingsWithSubLevelsOTRS6{ $Param{PackageLookupNewConfigName}->{$SettingName} }
1712            )
1713        {
1714            $CheckSubLevels = 1;
1715        }
1716
1717        # check if this OTRS5 setting has subhashes in the name
1718        if ($CheckSubLevels) {
1719
1720            SETTINGKEYFIRSTLEVEL:
1721            for my $SettingKeyFirstLevel ( sort keys %{ $OTRS5Config{$SettingName} } ) {
1722
1723                # there is a second level
1724                # example: Ticket::Frontend::AgentTicketZoom###Widgets###0100-TicketInformation
1725                if (
1726                    $SettingsWithSubLevelsOTRS6{$SettingName}->{$SettingKeyFirstLevel}
1727                    && IsHashRefWithData( $SettingsWithSubLevelsOTRS6{$SettingName}->{$SettingKeyFirstLevel} )
1728                    && IsHashRefWithData( $OTRS5Config{$SettingName}->{$SettingKeyFirstLevel} )
1729                    )
1730                {
1731
1732                    SETTINGKEYSECONDLEVEL:
1733                    for my $SettingKeySecondLevel (
1734                        sort keys %{ $OTRS5Config{$SettingName}->{$SettingKeyFirstLevel} }
1735                        )
1736                    {
1737
1738                        # get the effective value from the OTRS 5 config
1739                        my $OTRS5EffectiveValue
1740                            = $OTRS5Config{$SettingName}->{$SettingKeyFirstLevel}->{$SettingKeySecondLevel};
1741
1742                        # build the new setting key
1743                        my $NewSettingKey
1744                            = $SettingName . '###' . $SettingKeyFirstLevel . '###' . $SettingKeySecondLevel;
1745
1746                        # check and convert config name if it has been renamed in OTRS 6
1747                        # otherwise it will use the given old name
1748                        $NewSettingKey = $Self->_LookupNewConfigName(
1749                            OldName                    => $NewSettingKey,
1750                            PackageLookupNewConfigName => $Param{PackageLookupNewConfigName},
1751                        );
1752
1753                        # skip settings which are not in the given package settings
1754                        if ( %PackageSettingLookup && !$PackageSettingLookup{$NewSettingKey} ) {
1755                            next SETTINGKEYSECONDLEVEL;
1756                        }
1757
1758                        # try to get the default setting from OTRS 6 for the new setting name
1759                        my %OTRS6Setting = $SysConfigObject->SettingGet(
1760                            Name  => $NewSettingKey,
1761                            NoLog => 1,
1762                        );
1763
1764                        # skip settings which already have been modified in the meantime
1765                        next SETTINGKEYSECONDLEVEL if $OTRS6Setting{ModifiedID};
1766
1767                        # skip this setting if it is a readonly setting
1768                        next SETTINGKEYSECONDLEVEL if $OTRS6Setting{IsReadonly};
1769
1770                        # log if there is a setting that can not be found in OTRS 6 (might come from packages)
1771                        if ( !%OTRS6Setting ) {
1772                            push @MissingSettings, $NewSettingKey;
1773                            next SETTINGKEYSECONDLEVEL;
1774                        }
1775
1776                        # check if the setting value structure from OTRS 5 is still valid on OTRS6
1777                        my %Result = $SysConfigObject->SettingEffectiveValueCheck(
1778                            EffectiveValue   => $OTRS5EffectiveValue,
1779                            XMLContentParsed => $OTRS6Setting{XMLContentParsed},
1780                            NoValidation     => 1,
1781                            UserID           => 1,
1782                        );
1783
1784                        if ( !$Result{Success} ) {
1785                            push @UnsuccessfullSettings, $NewSettingKey;
1786                            next SETTINGKEYSECONDLEVEL;
1787                        }
1788
1789                        # update the setting.
1790                        %Result = $Self->_SettingUpdate(
1791                            Name           => $NewSettingKey,
1792                            IsValid        => 1,
1793                            EffectiveValue => $OTRS5EffectiveValue,
1794                        );
1795
1796                        if ( !$Result{Success} ) {
1797                            push @UnsuccessfullSettings, $NewSettingKey;
1798                            next SETTINGKEYSECONDLEVEL;
1799                        }
1800                    }
1801                }
1802
1803                # there is only one level
1804                # example: Ticket::Frontend::AgentTicketService###StripEmptyLines
1805                else {
1806
1807                    # get the effective value from the OTRS 5 config
1808                    my $OTRS5EffectiveValue = $OTRS5Config{$SettingName}->{$SettingKeyFirstLevel};
1809
1810                    # build the new setting key
1811                    my $NewSettingKey = $SettingName . '###' . $SettingKeyFirstLevel;
1812
1813                    # Skip not longer existing settings.
1814                    if ( $NewSettingKey eq 'Ticket::Frontend::OverviewSmall###ColumnHeader' ) {
1815                        next SETTINGKEYFIRSTLEVEL;
1816                    }
1817
1818                    # check and convert config name if it has been renamed in OTRS 6
1819                    # otherwise it will use the given old name
1820                    $NewSettingKey = $Self->_LookupNewConfigName(
1821                        OldName                    => $NewSettingKey,
1822                        PackageLookupNewConfigName => $Param{PackageLookupNewConfigName},
1823                    );
1824
1825                    # skip settings which are not in the given package settings
1826                    if ( %PackageSettingLookup && !$PackageSettingLookup{$NewSettingKey} ) {
1827                        next SETTINGKEYFIRSTLEVEL;
1828                    }
1829
1830                    # try to get the default setting from OTRS 6 for the modified setting name
1831                    my %OTRS6Setting = $SysConfigObject->SettingGet(
1832                        Name  => $NewSettingKey,
1833                        NoLog => 1,
1834                    );
1835
1836                    # skip settings which already have been modified in the meantime
1837                    next SETTINGKEYFIRSTLEVEL if $OTRS6Setting{ModifiedID};
1838
1839                    # skip this setting if it is a readonly setting
1840                    next SETTINGKEYFIRSTLEVEL if $OTRS6Setting{IsReadonly};
1841
1842                    # log if there is a setting that can not be found in OTRS 6 (might come from packages)
1843                    if ( !%OTRS6Setting ) {
1844                        push @MissingSettings, $NewSettingKey;
1845                        next SETTINGKEYFIRSTLEVEL;
1846                    }
1847
1848                    # migrate frontend module registrations
1849                    if (
1850                        $SettingName eq 'Frontend::Module'
1851                        || $SettingName eq 'CustomerFrontend::Module'
1852                        || $SettingName eq 'PublicFrontend::Module'
1853                        )
1854                    {
1855
1856                        # migrate (and split) the frontend module settings
1857                        my $Result = $Self->_MigrateFrontendModuleSetting(
1858                            FrontendSettingName => $SettingName,
1859                            FrontendModuleName  => $SettingKeyFirstLevel,
1860                            OTRS5EffectiveValue => $OTRS5EffectiveValue,
1861                            OTRS6Setting        => \%OTRS6Setting,
1862                        );
1863
1864                        # success
1865                        next SETTINGKEYFIRSTLEVEL if $Result;
1866
1867                        # error
1868                        push @UnsuccessfullSettings, $NewSettingKey;
1869                        next SETTINGKEYFIRSTLEVEL;
1870                    }
1871
1872                    # migrate preferences groups settings
1873                    if ( $SettingName eq 'PreferencesGroups' ) {
1874
1875                        # delete no longer needed column key
1876                        delete $OTRS5EffectiveValue->{Column};
1877
1878                        # add new PreferenceGroup key from OTRS 6
1879                        $OTRS5EffectiveValue->{PreferenceGroup} = $OTRS6Setting{EffectiveValue}->{PreferenceGroup};
1880                    }
1881
1882                    # Migrate Postmaster settings for
1883                    #   PostMaster::PreFilterModule
1884                    #   PostMaster::PreCreateFilterModule
1885                    #   PostMaster::PostFilterModule
1886                    #   PostMaster::CheckFollowUpModule
1887                    if (
1888                        $SettingName
1889                        =~ m{ \A PostMaster::(PreFilter|PreCreateFilter|PostFilter|CheckFollowUp)Module \z }xms
1890                        )
1891                    {
1892
1893                        # update no longer existing module.
1894                        if (
1895                            $OTRS5EffectiveValue->{Module} eq
1896                            'Kernel::System::PostMaster::Filter::FollowUpArticleTypeCheck'
1897                            )
1898                        {
1899                            $OTRS5EffectiveValue->{Module}
1900                                = 'Kernel::System::PostMaster::Filter::FollowUpArticleVisibilityCheck';
1901                        }
1902
1903                        # Define mapping for old to new keys.
1904                        my %Old2NewKeyMapping = (
1905                            'X-OTRS-ArticleType'          => 'X-OTRS-IsVisibleForCustomer',
1906                            'X-OTRS-FollowUp-ArticleType' => 'X-OTRS-FollowUp-IsVisibleForCustomer',
1907                            'ArticleType'                 => 'IsVisibleForCustomer',
1908                        );
1909
1910                        OLDKEY:
1911                        for my $OldKey ( sort keys %Old2NewKeyMapping ) {
1912
1913                            my $NewKey = $Old2NewKeyMapping{$OldKey};
1914
1915                            # Convert subentries below Match and Set.
1916                            AREA:
1917                            for my $Area (qw(Match Set)) {
1918                                next AREA if !IsHashRefWithData( $OTRS5EffectiveValue->{$Area} );
1919                                next AREA if !$OTRS5EffectiveValue->{$Area}->{$OldKey};
1920
1921                                # Add the new key with the converted value from the old key.
1922                                $OTRS5EffectiveValue->{$Area}->{$NewKey}
1923                                    = $ArticleTypeMapping{ $OTRS5EffectiveValue->{$Area}->{$OldKey} }->{Visible};
1924
1925                                # Delete the old key.
1926                                delete $OTRS5EffectiveValue->{$Area}->{$OldKey};
1927                            }
1928
1929                            # Convert direct entries.
1930                            next OLDKEY if !$OTRS5EffectiveValue->{$OldKey};
1931
1932                            # Add the new key with the converted value from the old key.
1933                            $OTRS5EffectiveValue->{$NewKey}
1934                                = $ArticleTypeMapping{ $OTRS5EffectiveValue->{$OldKey} }->{Visible};
1935
1936                            # Delete the old key.
1937                            delete $OTRS5EffectiveValue->{$OldKey};
1938                        }
1939                    }
1940
1941                    # check if the setting value structure from OTRS 5 is still valid on OTRS6
1942                    my %Result = $SysConfigObject->SettingEffectiveValueCheck(
1943                        EffectiveValue   => $OTRS5EffectiveValue,
1944                        XMLContentParsed => $OTRS6Setting{XMLContentParsed},
1945                        NoValidation     => 1,
1946                        UserID           => 1,
1947                    );
1948
1949                    if ( !$Result{Success} ) {
1950                        push @UnsuccessfullSettings, $NewSettingKey;
1951                        next SETTINGKEYFIRSTLEVEL;
1952                    }
1953
1954                    # update the setting.
1955                    %Result = $Self->_SettingUpdate(
1956                        Name           => $NewSettingKey,
1957                        IsValid        => 1,
1958                        EffectiveValue => $OTRS5EffectiveValue,
1959                    );
1960
1961                    if ( !$Result{Success} ) {
1962                        push @UnsuccessfullSettings, $NewSettingKey;
1963                        next SETTINGKEYFIRSTLEVEL;
1964                    }
1965                }
1966            }
1967        }
1968
1969        # setting has no subhashes in the name
1970        # example: Cache::Module
1971        else {
1972
1973            # skip TimeZone::Calendar settings (they are handled else where)
1974            next SETTINGNAME if $SettingName =~ m{ \A TimeZone::Calendar[1-9] \z }xms;
1975
1976            # check and convert config name if it has been renamed in OTRS 6
1977            # otherwise it will use the given old name
1978            my $NewSettingName = $Self->_LookupNewConfigName(
1979                OldName                    => $SettingName,
1980                PackageLookupNewConfigName => $Param{PackageLookupNewConfigName},
1981            );
1982
1983            # skip settings which are not in the given package settings
1984            if ( %PackageSettingLookup && !$PackageSettingLookup{$NewSettingName} ) {
1985                next SETTINGNAME;
1986            }
1987
1988            # get the (default) setting from OTRS 6 for this setting name
1989            my %OTRS6Setting = $SysConfigObject->SettingGet(
1990                Name  => $NewSettingName,
1991                NoLog => 1,
1992            );
1993
1994            # skip this setting if it has already been modified in the meantime
1995            next SETTINGNAME if $OTRS6Setting{ModifiedID};
1996
1997            # skip this setting if it is a readonly setting
1998            next SETTINGNAME if $OTRS6Setting{IsReadonly};
1999
2000            # Log if there is a setting that can not be found in OTRS 6 (might come from packages)
2001            if ( !%OTRS6Setting ) {
2002                push @MissingSettings, $NewSettingName;
2003                next SETTINGNAME;
2004            }
2005
2006            my $OTRS5EffectiveValue = $OTRS5Config{$SettingName};
2007
2008            # the ticket number generator random is dropped from OTRS 6, enforce that DateChecksum is set instead
2009            if (
2010                $NewSettingName eq 'Ticket::NumberGenerator'
2011                && $OTRS5EffectiveValue eq 'Kernel::System::Ticket::Number::Random'
2012                )
2013            {
2014                $OTRS5EffectiveValue = 'Kernel::System::Ticket::Number::DateChecksum';
2015            }
2016
2017            # check if the setting value structure from OTRS 5 is still valid on OTRS6
2018            my %Result = $SysConfigObject->SettingEffectiveValueCheck(
2019                EffectiveValue   => $OTRS5EffectiveValue,
2020                XMLContentParsed => $OTRS6Setting{XMLContentParsed},
2021                NoValidation     => 1,
2022                UserID           => 1,
2023            );
2024
2025            if ( !$Result{Success} ) {
2026
2027                push @UnsuccessfullSettings, $NewSettingName;
2028                next SETTINGNAME;
2029            }
2030
2031            # update the setting.
2032            %Result = $Self->_SettingUpdate(
2033                Name           => $NewSettingName,
2034                IsValid        => 1,
2035                EffectiveValue => $OTRS5EffectiveValue,
2036            );
2037
2038            if ( !$Result{Success} ) {
2039                push @UnsuccessfullSettings, $NewSettingName;
2040                next SETTINGNAME;
2041            }
2042        }
2043    }
2044
2045    my $DisabledSettingsCount = 0;
2046
2047    # Set all settings which are disabled in OTRS 5 to disabled.
2048    DISABLEDSETTINGNAME:
2049    for my $DisabledSettingKey (@DisabledOTRS5Config) {
2050
2051        # Check and convert config name if it has been renamed in OTRS 6
2052        #   otherwise it will use the given old name.
2053        my $NewSettingKey = $Self->_LookupNewConfigName(
2054            OldName                    => $DisabledSettingKey,
2055            PackageLookupNewConfigName => $Param{PackageLookupNewConfigName},
2056        );
2057
2058        # Skip settings which are not in the given package settings.
2059        if ( %PackageSettingLookup && !$PackageSettingLookup{$NewSettingKey} ) {
2060            next DISABLEDSETTINGNAME;
2061        }
2062
2063        # Try to get the default setting from OTRS 6 for the modified setting name.
2064        my %OTRS6Setting = $SysConfigObject->SettingGet(
2065            Name  => $NewSettingKey,
2066            NoLog => 1,
2067        );
2068
2069        # Skip settings which already have been modified in the meantime.
2070        next DISABLEDSETTINGNAME if $OTRS6Setting{ModifiedID};
2071
2072        # Skip this setting if it is a readonly setting.
2073        next DISABLEDSETTINGNAME if $OTRS6Setting{IsReadonly};
2074
2075        # Skip this setting if it is a required setting.
2076        next DISABLEDSETTINGNAME if $OTRS6Setting{IsRequired};
2077
2078        # Log if there is a setting that can not be found in OTRS 6 (might come from packages).
2079        if ( !%OTRS6Setting ) {
2080            push @MissingSettings, $NewSettingKey;
2081            next DISABLEDSETTINGNAME;
2082        }
2083
2084        # Disable the setting.
2085        my %Result = $Self->_SettingUpdate(
2086            Name    => $NewSettingKey,
2087            IsValid => 0,
2088        );
2089
2090        if ( !$Result{Success} ) {
2091            push @UnsuccessfullSettings, $NewSettingKey;
2092            next DISABLEDSETTINGNAME;
2093        }
2094
2095        $DisabledSettingsCount++;
2096    }
2097
2098    # do not print the following status output if not wanted
2099    return 1 if $Param{NoOutput};
2100
2101    my $AllSettingsCount = scalar keys %OTRS5Config;
2102
2103    print "\n";
2104    print "        - AllSettingsCount: " . $AllSettingsCount . "\n";
2105    print "        - DisabledCount: " . $DisabledSettingsCount . "\n";
2106    print "        - MissingCount: " . scalar @MissingSettings . "\n";
2107    print "        - UnsuccessfullCount: " . scalar @UnsuccessfullSettings . "\n\n";
2108
2109    if (@MissingSettings) {
2110        print "\nMissing Settings: \n";
2111        for my $Setting (@MissingSettings) {
2112            print $Setting . "\n";
2113        }
2114    }
2115
2116    if (@UnsuccessfullSettings) {
2117        print "\nUnsuccessfull Settings: \n";
2118        for my $Setting (@UnsuccessfullSettings) {
2119            print $Setting . "\n";
2120        }
2121    }
2122
2123    if ( $Param{ReturnMigratedSettingsCounts} ) {
2124        return {
2125            AllSettingsCount      => $AllSettingsCount,
2126            DisabledSettingsCount => $DisabledSettingsCount,
2127            MissingSettings       => \@MissingSettings,
2128            UnsuccessfullSettings => \@UnsuccessfullSettings,
2129        };
2130    }
2131
2132    return 1;
2133}
2134
2135=head2 NavigationLookupGet()
2136
2137Get a list of all old Sub-Groups and the corresponding new navigation.
2138
2139    my %NavigationLookup = $SysConfigMigrationObject->NavigationLookupGet();
2140
2141Returns:
2142
2143    %NavigationLookup = (
2144        'Old::Subgroup' => 'New::Navigation',
2145        # ...
2146    );
2147
2148=cut
2149
2150sub NavigationLookupGet {
2151    my ( $Self, %Param ) = @_;
2152
2153    return (
2154        'CloudService::Admin::ModuleRegistration'      => 'CloudService::Admin::ModuleRegistration',
2155        'ConfigLog'                                    => 'ConfigLog',
2156        'ConfigSwitch'                                 => 'ConfigSwitch',
2157        'Core'                                         => 'Core',
2158        'Core::AppointmentCalendar::Event'             => 'Core::Event::AppointmentCalendar',
2159        'Core::Cache'                                  => 'Core::Cache',
2160        'Core::CustomerCompany'                        => 'Core::CustomerCompany',
2161        'Core::CustomerUser'                           => 'Core::CustomerUser',
2162        'Core::Daemon::ModuleRegistration'             => 'Daemon::ModuleRegistration',
2163        'Core::DynamicField'                           => 'Core::DynamicFields',
2164        'Core::Fetchmail'                              => 'Core::Email',
2165        'Core::FulltextSearch'                         => 'Core::Ticket::FulltextSearch',
2166        'Core::LinkObject'                             => 'Core::LinkObject',
2167        'Core::Log'                                    => 'Core::Log',
2168        'Core::MIME-Viewer'                            => 'Frontend::Agent::MIMEViewer',
2169        'Core::MirrorDB'                               => 'Core::DB::Mirror',
2170        'Core::OTRSBusiness'                           => 'Core::OTRSBusiness',
2171        'Core::Package'                                => 'Core::Package',
2172        'Core::PDF'                                    => 'Core::PDF',
2173        'Core::PerformanceLog'                         => 'Core::PerformanceLog',
2174        'Core::PostMaster'                             => 'Core::Email::PostMaster',
2175        'Core::Queue'                                  => 'Core::Queue',
2176        'Core::ReferenceData'                          => 'Core::ReferenceData',
2177        'Core::Sendmail'                               => 'Core::Email',
2178        'Core::Session'                                => 'Core::Session',
2179        'Core::SOAP'                                   => 'Core::SOAP',
2180        'Core::Stats'                                  => 'Core::Stats',
2181        'Core::Ticket'                                 => 'Core::Ticket',
2182        'Core::TicketACL'                              => 'Core::Ticket::ACL',
2183        'Core::TicketBulkAction'                       => 'Frontend::Agent::View::TicketBulk',
2184        'Core::TicketDynamicFieldDefault'              => 'Core::Ticket::DynamicFieldDefault',
2185        'Core::TicketWatcher'                          => 'Core::Ticket',
2186        'Core::Time'                                   => 'Core::Time',
2187        'Core::Time::Calendar1'                        => 'Core::Time::Calendar1',
2188        'Core::Time::Calendar2'                        => 'Core::Time::Calendar2',
2189        'Core::Time::Calendar3'                        => 'Core::Time::Calendar3',
2190        'Core::Time::Calendar4'                        => 'Core::Time::Calendar4',
2191        'Core::Time::Calendar5'                        => 'Core::Time::Calendar5',
2192        'Core::Time::Calendar6'                        => 'Core::Time::Calendar6',
2193        'Core::Time::Calendar7'                        => 'Core::Time::Calendar7',
2194        'Core::Time::Calendar8'                        => 'Core::Time::Calendar8',
2195        'Core::Time::Calendar9'                        => 'Core::Time::Calendar9',
2196        'Core::Transition'                             => 'Core::ProcessManagement',
2197        'Core::Web'                                    => 'Frontend::Base',
2198        'Core::WebUserAgent'                           => 'Core::WebUserAgent',
2199        'Crypt::PGP'                                   => 'Core::Crypt::PGP',
2200        'Crypt::SMIME'                                 => 'Core::Crypt::SMIME',
2201        'CustomerInformationCenter'                    => 'Frontend::Agent::View::CustomerInformationCenter',
2202        'Daemon::SchedulerCronTaskManager::Task'       => 'Daemon::SchedulerCronTaskManager::Task',
2203        'Daemon::SchedulerGenericAgentTaskManager'     => 'Daemon::SchedulerGenericAgentTaskManager',
2204        'Daemon::SchedulerGenericInterfaceTaskManager' => 'Daemon::SchedulerGenericInterfaceTaskManager',
2205        'Daemon::SchedulerTaskWorker'                  => 'Daemon::SchedulerTaskWorker',
2206        'DynamicFields::Driver::Registration'          => 'Core::DynamicFields::DriverRegistration',
2207        'DynamicFields::ObjectType::Registration'      => 'Core::DynamicFields::ObjectTypeRegistration',
2208
2209        # 'Frontend::Admin'                                  => 'Frontend::Admin',
2210        'Frontend::Admin::AdminCustomerCompany'   => 'Frontend::Admin::View::CustomerCompany',
2211        'Frontend::Admin::AdminCustomerUser'      => 'Frontend::Admin::View::CustomerUser',
2212        'Frontend::Admin::AdminNotificationEvent' => 'Frontend::Admin::View::NotificationEvent',
2213        'Frontend::Admin::AdminSelectBox'         => 'Frontend::Admin::View::SelectBox',
2214
2215        # 'Frontend::Admin::ModuleRegistration'              => 'Frontend::Admin::ModuleRegistration',
2216        'Frontend::Admin::SearchRouter'                    => 'Frontend::Admin::ModuleRegistration::MainMenu::Search',
2217        'Frontend::Agent'                                  => 'Frontend::Agent',
2218        'Frontend::Agent::Auth::TwoFactor'                 => 'Core::Auth::Agent::TwoFactor',
2219        'Frontend::Agent::Dashboard'                       => 'Frontend::Agent::View::Dashboard',
2220        'Frontend::Agent::Dashboard::EventsTicketCalendar' => 'Frontend::Agent::View::Dashboard::EventsTicketCalendar',
2221        'Frontend::Agent::Dashboard::TicketFilters'        => 'Frontend::Agent::View::Dashboard::TicketFilters',
2222        'Frontend::Agent::LinkObject'                      => 'Frontend::Agent::LinkObject',
2223        'Frontend::Agent::ModuleMetaHead'                  => 'Frontend::Agent',
2224        'Frontend::Agent::ModuleNotify'                    => 'Frontend::Agent::FrontendNotification',
2225        'Frontend::Agent::NavBarModule'                    => 'Frontend::Agent::ModuleRegistration',
2226        'Frontend::Agent::Preferences'                     => 'Frontend::Agent::View::Preferences',
2227        'Frontend::Agent::SearchRouter'                    => 'Frontend::Agent::ModuleRegistration::MainMenu::Search',
2228        'Frontend::Agent::Stats'                           => 'Frontend::Agent::Stats',
2229        'Frontend::Agent::Ticket::ArticleAttachmentModule' => 'Frontend::Agent::View::TicketZoom',
2230        'Frontend::Agent::Ticket::ArticleComposeModule'    => 'Frontend::Agent::ArticleComposeModule',
2231        'Frontend::Agent::Ticket::ArticleViewModule'       => 'Frontend::Agent::View::TicketZoom',
2232        'Frontend::Agent::Ticket::ArticleViewModulePre'    => 'Frontend::Agent::View::TicketZoom',
2233        'Frontend::Agent::Ticket::MenuModule'              => 'Frontend::Agent::View::TicketZoom::MenuModule',
2234        'Frontend::Agent::Ticket::MenuModulePre'           => 'Frontend::Agent::TicketOverview::MenuModule',
2235        'Frontend::Agent::Ticket::OverviewMenuModule'      => 'Frontend::Agent::TicketOverview::MenuModule',
2236        'Frontend::Agent::Ticket::ViewBounce'              => 'Frontend::Agent::View::TicketBounce',
2237        'Frontend::Agent::Ticket::ViewBulk'                => 'Frontend::Agent::View::TicketBulk',
2238        'Frontend::Agent::Ticket::ViewClose'               => 'Frontend::Agent::View::TicketClose',
2239        'Frontend::Agent::Ticket::ViewCompose'             => 'Frontend::Agent::View::TicketCompose',
2240        'Frontend::Agent::Ticket::ViewCustomer'            => 'Frontend::Agent::View::TicketCustomer',
2241        'Frontend::Agent::Ticket::ViewEmailNew'            => 'Frontend::Agent::View::TicketEmailNew',
2242        'Frontend::Agent::Ticket::ViewEmailOutbound'       => 'Frontend::Agent::View::TicketEmailOutbound',
2243        'Frontend::Agent::Ticket::ViewEscalation'          => 'Frontend::Agent::View::TicketEscalation',
2244        'Frontend::Agent::Ticket::ViewForward'             => 'Frontend::Agent::View::TicketForward',
2245        'Frontend::Agent::Ticket::ViewFreeText'            => 'Frontend::Agent::View::TicketFreeText',
2246        'Frontend::Agent::Ticket::ViewHistory'             => 'Frontend::Agent::View::TicketHistory',
2247        'Frontend::Agent::Ticket::ViewLocked'              => 'Frontend::Agent::View::TicketLocked',
2248        'Frontend::Agent::Ticket::ViewMerge'               => 'Frontend::Agent::View::TicketMerge',
2249        'Frontend::Agent::Ticket::ViewMove'                => 'Frontend::Agent::View::TicketMove',
2250        'Frontend::Agent::Ticket::ViewNote'                => 'Frontend::Agent::View::TicketNote',
2251        'Frontend::Agent::Ticket::ViewOwner'               => 'Frontend::Agent::View::TicketOwner',
2252        'Frontend::Agent::Ticket::ViewPending'             => 'Frontend::Agent::View::TicketPending',
2253        'Frontend::Agent::Ticket::ViewPhoneInbound'        => 'Frontend::Agent::View::TicketPhoneInbound',
2254        'Frontend::Agent::Ticket::ViewPhoneNew'            => 'Frontend::Agent::View::TicketPhoneNew',
2255        'Frontend::Agent::Ticket::ViewPhoneOutbound'       => 'Frontend::Agent::View::TicketPhoneOutbound',
2256        'Frontend::Agent::Ticket::ViewPrint'               => 'Frontend::Agent::View::TicketPrint',
2257        'Frontend::Agent::Ticket::ViewPriority'            => 'Frontend::Agent::View::TicketPriority',
2258        'Frontend::Agent::Ticket::ViewProcess'             => 'Frontend::Agent::View::TicketProcess',
2259        'Frontend::Agent::Ticket::ViewQueue'               => 'Frontend::Agent::View::TicketQueue',
2260        'Frontend::Agent::Ticket::ViewResponsible'         => 'Frontend::Agent::View::TicketResponsible',
2261        'Frontend::Agent::Ticket::ViewSearch'              => 'Frontend::Agent::View::TicketSearch',
2262        'Frontend::Agent::Ticket::ViewService'             => 'Frontend::Agent::View::TicketService',
2263        'Frontend::Agent::Ticket::ViewStatus'              => 'Frontend::Agent::View::TicketStatus',
2264        'Frontend::Agent::Ticket::ViewWatch'               => 'Frontend::Agent::View::TicketWatch',
2265        'Frontend::Agent::Ticket::ViewZoom'                => 'Frontend::Agent::View::TicketZoom',
2266        'Frontend::Agent::TicketOverview'                  => 'Frontend::Agent::TicketOverview',
2267        'Frontend::Agent::ToolBarModule'                   => 'Frontend::Agent::ToolBar',
2268        'Frontend::Agent::ViewCustomerUserSearch'          => 'Frontend::Agent::View::CustomerUserAddressBook',
2269        'Frontend::Agent::CustomerInformationCenter'       => 'Frontend::Agent::View::CustomerInformationCenter',
2270        'Frontend::Agent::Stats'                           => 'Frontend::Agent::View::Stats',
2271        'Frontend::Customer'                               => 'Frontend::Customer',
2272        'Frontend::Customer::Auth'                         => 'Core::Auth::Customer',
2273        'Frontend::Customer::Auth::TwoFactor'              => 'Core::Auth::Customer::TwoFactor',
2274        'Frontend::Customer::ModuleMetaHead'               => 'Frontend::Customer',
2275        'Frontend::Customer::ModuleNotify'                 => 'Frontend::Customer::FrontendNotification',
2276        'Frontend::Customer::ModuleRegistration'           => 'Frontend::Customer::ModuleRegistration',
2277        'Frontend::Customer::NavBarModule'                 => 'Frontend::Customer::ModuleRegistration',
2278        'Frontend::Customer::Preferences'                  => 'Frontend::Customer::View::Preferences',
2279        'Frontend::Customer::Ticket::ViewNew'              => 'Frontend::Customer::View::TicketMessage',
2280        'Frontend::Customer::Ticket::ViewPrint'            => 'Frontend::Customer::View::TicketPrint',
2281        'Frontend::Customer::Ticket::ViewSearch'           => 'Frontend::Customer::View::TicketSearch',
2282        'Frontend::Customer::Ticket::ViewZoom'             => 'Frontend::Customer::View::TicketZoom',
2283        'Frontend::Customer::TicketOverview'               => 'Frontend::Customer::View::TicketOverview',
2284        'Frontend::Public'                                 => 'Frontend::Public',
2285        'Frontend::Public::ModuleRegistration'             => 'Frontend::Public::ModuleRegistration',
2286        'Frontend::Queue::Preferences'                     => 'Core::Queue',
2287        'Frontend::Service::Preferences'                   => 'Core::Service',
2288        'Frontend::SLA::Preferences'                       => 'Core::SLA',
2289        'GenericInterface::Invoker::ModuleRegistration'    => 'GenericInterface::Invoker::ModuleRegistration',
2290        'GenericInterface::Mapping::ModuleRegistration'    => 'GenericInterface::Mapping::ModuleRegistration',
2291        'GenericInterface::Operation::ModuleRegistration'  => 'GenericInterface::Operation::ModuleRegistration',
2292        'GenericInterface::Operation::ResponseLoggingMaxSize' => 'GenericInterface::Operation::ResponseLoggingMaxSize',
2293        'GenericInterface::Operation::TicketCreate'           => 'GenericInterface::Operation::TicketCreate',
2294        'GenericInterface::Operation::TicketSearch'           => 'GenericInterface::Operation::TicketSearch',
2295        'GenericInterface::Operation::TicketUpdate'           => 'GenericInterface::Operation::TicketUpdate',
2296        'GenericInterface::Transport::ModuleRegistration'     => 'GenericInterface::Transport::ModuleRegistration',
2297        'GenericInterface::Webservice'                        => 'GenericInterface::Webservice',
2298        'SystemMaintenance'                                   => 'Core::SystemMaintenance',
2299
2300        # Packages
2301        'OutputFilter'                       => 'Frontend::Base::OutputFilter',
2302        'Frontend::Customer::ModuleMetaHead' => 'Frontend::Customer',
2303        'Frontend::Public::ModuleMetaHead'   => 'Frontend::Public',
2304
2305        # OTRSBusiness
2306        'Core::NotificationEvent'               => 'Frontend::Agent::View::NotificationView',
2307        'Core::NotificationView'                => 'Frontend::Agent::View::NotificationView',
2308        'Core::NotificationView::BulkAction'    => 'Frontend::Agent::View::NotificationView',
2309        'Frontend::Agent::NotificationView'     => 'Frontend::Agent::View::NotificationView',
2310        'Frontend'                              => 'Frontend::Base',
2311        'Frontend::Admin::AdminContactWithData' => 'Frontend::Admin::View::ContactWithData',
2312    );
2313}
2314
2315=head1 PRIVATE INTERFACE
2316
2317=head2 _LookupNewConfigName()
2318
2319Helper function to lookup new config names for configuration settings
2320where the name has been changed from OTRS 5 to OTRS 6.
2321
2322    my $NewName = $SysConfigMigrationObject->_LookupNewConfigName(
2323        OldName => 'CustomerCompany::EventModulePost###100-UpdateCustomerUsers',
2324    );
2325
2326Returns:
2327
2328    True on success or false on error.
2329
2330=cut
2331
2332sub _LookupNewConfigName {
2333    my ( $Self, %Param ) = @_;
2334
2335    # check needed stuff
2336    if ( !$Param{OldName} ) {
2337        $Kernel::OM->Get('Kernel::System::Log')->Log(
2338            Priority => 'error',
2339            Message  => "Need OldName!",
2340        );
2341        return;
2342    }
2343
2344    # mapping table: old name -> new name
2345    my %Old2NewName = (
2346        'CustomerCompany::EventModulePost###100-UpdateCustomerUsers' =>
2347            'CustomerCompany::EventModulePost###2000-UpdateCustomerUsers',
2348
2349        'CustomerCompany::EventModulePost###110-UpdateTickets' =>
2350            'CustomerCompany::EventModulePost###2300-UpdateTickets',
2351
2352        'CustomerCompany::EventModulePost###1000-GenericInterface' =>
2353            'CustomerCompany::EventModulePost###9900-GenericInterface',
2354
2355        'CustomerUser::EventModulePost###100-UpdateDynamicFieldObjectName' =>
2356            'CustomerUser::EventModulePost###2000-UpdateDynamicFieldObjectName',
2357
2358        'CustomerUser::EventModulePost###100-UpdateSearchProfiles' =>
2359            'CustomerUser::EventModulePost###2100-UpdateSearchProfiles',
2360
2361        'CustomerUser::EventModulePost###100-UpdateServiceMembership' =>
2362            'CustomerUser::EventModulePost###2200-UpdateServiceMembership',
2363
2364        'CustomerUser::EventModulePost###1000-GenericInterface' =>
2365            'CustomerUser::EventModulePost###9900-GenericInterface',
2366
2367        'CustomerUser::EventModulePost###120-UpdateTickets' =>
2368            'CustomerUser::EventModulePost###2300-UpdateTickets',
2369
2370        'DynamicField::EventModulePost###1000-GenericInterface' =>
2371            'DynamicField::EventModulePost###9900-GenericInterface',
2372
2373        'Frontend::NotifyModule###5-Ticket::TicketEscalation' =>
2374            'Frontend::NotifyModule###5000-Ticket::TicketEscalation',
2375
2376        'Frontend::NotifyModule###100-CloudServicesDisabled' =>
2377            'Frontend::NotifyModule###1000-CloudServicesDisabled',
2378
2379        'Frontend::NotifyModule###100-OTRSBusiness' =>
2380            'Frontend::NotifyModule###1100-OTRSBusiness',
2381
2382        'Frontend::NotifyModule###200-UID-Check' =>
2383            'Frontend::NotifyModule###2000-UID-Check',
2384
2385        'Frontend::NotifyModule###250-AgentSessionLimit' =>
2386            'Frontend::NotifyModule###2500-AgentSessionLimit',
2387
2388        'Frontend::NotifyModule###300-ShowAgentOnline' =>
2389            'Frontend::NotifyModule###3000-ShowAgentOnline',
2390
2391        'Frontend::NotifyModule###400-ShowCustomerOnline' =>
2392            'Frontend::NotifyModule###4000-ShowCustomerOnline',
2393
2394        'Frontend::NotifyModule###500-OutofOffice-Check' =>
2395            'Frontend::NotifyModule###5500-OutofOffice-Check',
2396
2397        'Frontend::NotifyModule###600-SystemMaintenance-Check' =>
2398            'Frontend::NotifyModule###6000-SystemMaintenance-Check',
2399
2400        'Frontend::NotifyModule###700-AgentTimeZone-Check' =>
2401            'Frontend::NotifyModule###7000-AgentTimeZone-Check',
2402
2403        'Frontend::NotifyModule###800-Daemon-Check' =>
2404            'Frontend::NotifyModule###8000-Daemon-Check',
2405
2406        'Frontend::NotifyModule###900-Generic' =>
2407            'Frontend::NotifyModule###9000-Generic',
2408
2409        'Frontend::ToolBarModule###1-Ticket::AgentTicketQueue' =>
2410            'Frontend::ToolBarModule###110-Ticket::AgentTicketQueue',
2411
2412        'Frontend::ToolBarModule###2-Ticket::AgentTicketStatus' =>
2413            'Frontend::ToolBarModule###120-Ticket::AgentTicketStatus',
2414
2415        'Frontend::ToolBarModule###3-Ticket::AgentTicketEscalation' =>
2416            'Frontend::ToolBarModule###130-Ticket::AgentTicketEscalation',
2417
2418        'Frontend::ToolBarModule###4-Ticket::AgentTicketPhone' =>
2419            'Frontend::ToolBarModule###140-Ticket::AgentTicketPhone',
2420
2421        'Frontend::ToolBarModule###5-Ticket::AgentTicketEmail' =>
2422            'Frontend::ToolBarModule###150-Ticket::AgentTicketEmail',
2423
2424        'Frontend::ToolBarModule###6-Ticket::AgentTicketProcess' =>
2425            'Frontend::ToolBarModule###160-Ticket::AgentTicketProcess',
2426
2427        'Frontend::ToolBarModule###7-Ticket::TicketResponsible' =>
2428            'Frontend::ToolBarModule###170-Ticket::TicketResponsible',
2429
2430        'Frontend::ToolBarModule###8-Ticket::TicketWatcher' =>
2431            'Frontend::ToolBarModule###180-Ticket::TicketWatcher',
2432
2433        'Frontend::ToolBarModule###9-Ticket::TicketLocked' =>
2434            'Frontend::ToolBarModule###190-Ticket::TicketLocked',
2435
2436        'Frontend::ToolBarModule###10-Ticket::AgentTicketService' =>
2437            'Frontend::ToolBarModule###200-Ticket::AgentTicketService',
2438
2439        'Frontend::ToolBarModule###11-Ticket::TicketSearchProfile' =>
2440            'Frontend::ToolBarModule###210-Ticket::TicketSearchProfile',
2441
2442        'Frontend::ToolBarModule###12-Ticket::TicketSearchFulltext' =>,
2443        'Frontend::ToolBarModule###220-Ticket::TicketSearchFulltext',
2444
2445        'Frontend::ToolBarModule###13-CICSearchCustomerID' =>
2446            'Frontend::ToolBarModule###230-CICSearchCustomerID',
2447
2448        'Frontend::ToolBarModule###14-CICSearchCustomerUser' =>
2449            'Frontend::ToolBarModule###240-CICSearchCustomerUser',
2450
2451        'Package::EventModulePost###1000-GenericInterface' =>
2452            'Package::EventModulePost###9900-GenericInterface',
2453
2454        'Package::EventModulePost###99-SupportDataSend' =>
2455            'Package::EventModulePost###9000-SupportDataSend',
2456
2457        'Queue::EventModulePost###1000-GenericInterface' =>
2458            'Queue::EventModulePost###9900-GenericInterface',
2459
2460        'Queue::EventModulePost###130-UpdateQueue' =>
2461            'Queue::EventModulePost###2300-UpdateQueue',
2462
2463        'Ticket::EventModulePost###100-ArchiveRestore' =>
2464            'Ticket::EventModulePost###2300-ArchiveRestore',
2465
2466        'Ticket::EventModulePost###110-AcceleratorUpdate' =>
2467            'Ticket::EventModulePost###2600-AcceleratorUpdate',
2468
2469        'Ticket::EventModulePost###120-ForceOwnerResetOnMove' =>
2470            'Ticket::EventModulePost###2700-ForceOwnerResetOnMove',
2471
2472        'Ticket::EventModulePost###130-ForceStateChangeOnLock' =>
2473            'Ticket::EventModulePost###2800-ForceStateChangeOnLock',
2474
2475        'Ticket::EventModulePost###140-ResponsibleAutoSet' =>
2476            'Ticket::EventModulePost###3000-ResponsibleAutoSet',
2477
2478        'Ticket::EventModulePost###150-TicketPendingTimeReset' =>
2479            'Ticket::EventModulePost###3300-TicketPendingTimeReset',
2480
2481        'Ticket::EventModulePost###500-NotificationEvent' =>
2482            'Ticket::EventModulePost###7000-NotificationEvent',
2483
2484        'Ticket::EventModulePost###900-GenericAgent' =>
2485            'Ticket::EventModulePost###9700-GenericAgent',
2486
2487        'Ticket::EventModulePost###910-EscalationIndex' =>
2488            'Ticket::EventModulePost###6000-EscalationIndex',
2489
2490        'Ticket::EventModulePost###920-EscalationStopEvents' =>
2491            'Ticket::EventModulePost###4300-EscalationStopEvents',
2492
2493        'Ticket::EventModulePost###930-ForceUnlockOnMove' =>
2494            'Ticket::EventModulePost###3600-ForceUnlockOnMove',
2495
2496        'Ticket::EventModulePost###940-TicketArticleNewMessageUpdate' =>
2497            'Ticket::EventModulePost###4000-TicketArticleNewMessageUpdate',
2498
2499        'Ticket::EventModulePost###950-DynamicFieldFromCustomerUser' =>
2500            'Ticket::EventModulePost###4100-DynamicFieldFromCustomerUser',
2501
2502        'Ticket::EventModulePost###998-TicketProcessTransitions' =>
2503            'Ticket::EventModulePost###9800-TicketProcessTransitions',
2504
2505        'Ticket::EventModulePost###999-GenericInterface' =>
2506            'Ticket::EventModulePost###9900-GenericInterface',
2507
2508        'Ticket::EventModulePost###TicketDynamicFieldDefault' =>
2509            'Ticket::EventModulePost###9600-TicketDynamicFieldDefault',
2510
2511        'Ticket::Frontend::ArticleComposeModule###1-SignEmail' =>
2512            'Ticket::Frontend::ArticleComposeModule###2-SignEmail',
2513
2514        'Ticket::Frontend::ArticleComposeModule###2-CryptEmail' =>
2515            'Ticket::Frontend::ArticleComposeModule###3-CryptEmail',
2516
2517        'Ticket::Frontend::ArticlePreViewModule###1-SMIME' =>
2518            'Ticket::Frontend::ArticlePreViewModule###2-SMIME',
2519
2520        'PostMaster::PreCreateFilterModule###000-FollowUpArticleTypeCheck' =>
2521            'PostMaster::PreCreateFilterModule###000-FollowUpArticleVisibilityCheck',
2522
2523        'Ticket::Frontend::AgentTicketSearch###Defaults###From' =>
2524            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_From',
2525
2526        'Ticket::Frontend::AgentTicketSearch###Defaults###To' =>
2527            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_To',
2528
2529        'Ticket::Frontend::AgentTicketSearch###Defaults###Cc' =>
2530            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Cc',
2531
2532        'Ticket::Frontend::AgentTicketSearch###Defaults###Subject' =>
2533            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Subject',
2534
2535        'Ticket::Frontend::AgentTicketSearch###Defaults###Body' =>
2536            'Ticket::Frontend::AgentTicketSearch###Defaults###MIMEBase_Body',
2537
2538        # Moved and renamed config setting from OTRSBusiness.xml to Framework.xml
2539        'ChatEngine::AgentOnlineThreshold' => 'SessionAgentOnlineThreshold',
2540
2541        # Moved and renamed config setting from OTRSBusiness.xml to Framework.xml
2542        'ChatEngine::CustomerOnlineThreshold' => 'SessionCustomerOnlineThreshold',
2543
2544        %{ $Param{PackageLookupNewConfigName} // {} },
2545    );
2546
2547    # get the new name if found, otherwise use the given old name
2548    my $NewName = $Old2NewName{ $Param{OldName} } || $Param{OldName};
2549
2550    return $NewName;
2551}
2552
2553=head2 _MigrateFrontendModuleSetting()
2554
2555Helper function to migrate a frontend module setting from OTRS 5 to OTRS 6.
2556
2557    my $NewName = $SysConfigMigrationObject->_MigrateFrontendModuleSetting(
2558        FrontendSettingName => 'Frontend::Module',
2559        FrontendModuleName  => 'AgentTicketQueue',
2560        OTRS5EffectiveValue => {
2561            'Description' => 'Overview of all open Tickets.',
2562            'Group' => [ 'users', 'admin' ],
2563            'GroupRo' => [ 'stats' ],
2564            'Loader' => {
2565                'CSS' => [
2566                    'Core.AgentTicketQueue.css',
2567                    'Core.AllocationList.css'
2568                ],
2569                'JavaScript' => [
2570                  'Core.UI.AllocationList.js',
2571                  'Core.Agent.TableFilters.js'
2572                ],
2573            },
2574            'NavBar' => [
2575                {
2576                  'AccessKey' => 'o',
2577                  'Block' => '',
2578                  'Description' => 'Overview of all open Tickets. xxx xxx',
2579                  'Link' => 'Action=AgentTicketQueue',
2580                  'LinkOption' => '',
2581                  'Name' => 'Queue view',
2582                  'NavBar' => 'Ticket',
2583                  'Prio' => '100',
2584                  'Type' => ''
2585                },
2586                {
2587                  'AccessKey' => 't',
2588                  'Block' => 'ItemArea',
2589                  'Description' => 'xxx',
2590                  'Link' => 'Action=AgentTicketQueue',
2591                  'LinkOption' => '',
2592                  'Name' => 'Tickets',
2593                  'NavBar' => 'Ticket',
2594                  'Prio' => '200',
2595                  'Type' => 'Menu'
2596                }
2597              ],
2598            'NavBarName' => 'Ticket',
2599            'Title' => 'QueueView',
2600        },
2601        OTRS6Setting => \%OTRS6Setting,
2602    );
2603
2604Returns:
2605
2606    True on success or false on error.
2607
2608=cut
2609
2610sub _MigrateFrontendModuleSetting {
2611    my ( $Self, %Param ) = @_;
2612
2613    # check needed stuff
2614    for my $Needed (qw(FrontendSettingName FrontendModuleName OTRS5EffectiveValue OTRS6Setting)) {
2615        if ( !$Param{$Needed} ) {
2616            $Kernel::OM->Get('Kernel::System::Log')->Log(
2617                Priority => 'error',
2618                Message  => "Need $Needed!",
2619            );
2620            return;
2621        }
2622    }
2623
2624    # get the group settings from OTRS 5 config
2625    my @Group   = @{ $Param{OTRS5EffectiveValue}->{Group}   || [] };
2626    my @GroupRo = @{ $Param{OTRS5EffectiveValue}->{GroupRo} || [] };
2627
2628    my $SysConfigObject = $Kernel::OM->Get('Kernel::System::SysConfig');
2629
2630    # ###########################################################################
2631    # migrate the frontend module setting
2632    # (it will contain only the registration,
2633    # loader and navigation settings will be separate settings now)
2634    # ###########################################################################
2635
2636    # set some attributes from OTRS 5
2637    ATTRIBUTE:
2638    for my $Attribute (qw(Description Title NavBarName)) {
2639        next ATTRIBUTE if !$Param{OTRS5EffectiveValue}->{$Attribute};
2640        $Param{OTRS6Setting}->{EffectiveValue}->{$Attribute} = $Param{OTRS5EffectiveValue}->{$Attribute};
2641    }
2642
2643    # set group settings from OTRS 5
2644    $Param{OTRS6Setting}->{EffectiveValue}->{Group}   = \@Group;
2645    $Param{OTRS6Setting}->{EffectiveValue}->{GroupRo} = \@GroupRo;
2646
2647    # check if the setting value structure from OTRS 5 is still valid on OTRS 6
2648    my %Result = $SysConfigObject->SettingEffectiveValueCheck(
2649        EffectiveValue   => $Param{OTRS5EffectiveValue},
2650        XMLContentParsed => $Param{OTRS6Setting}->{XMLContentParsed},
2651        NoValidation     => 1,
2652        UserID           => 1,
2653    );
2654
2655    return if !$Result{Success};
2656
2657    # lock the setting
2658    my $ExclusiveLockGUID = $SysConfigObject->SettingLock(
2659        Name   => $Param{OTRS6Setting}->{Name},
2660        Force  => 1,
2661        UserID => 1,
2662    );
2663
2664    # update the setting
2665    %Result = $SysConfigObject->SettingUpdate(
2666        Name              => $Param{OTRS6Setting}->{Name},
2667        IsValid           => 1,
2668        EffectiveValue    => $Param{OTRS6Setting}->{EffectiveValue},
2669        ExclusiveLockGUID => $ExclusiveLockGUID,
2670        NoValidation      => 1,
2671        UserID            => 1,
2672    );
2673
2674    # unlock the setting again
2675    $SysConfigObject->SettingUnlock(
2676        Name => $Param{OTRS6Setting}->{Name},
2677    );
2678
2679    return if !$Result{Success};
2680
2681    # ###########################################################################
2682    # migrate the NavBarModule settings
2683    # ###########################################################################
2684    if ( $Param{OTRS5EffectiveValue}->{NavBarModule} ) {
2685
2686        my $NavBarModuleSettingName = 'Frontend::NavigationModule###' . $Param{FrontendModuleName};
2687
2688        # try to get the (default) setting from OTRS 6 for the NavBarModule setting
2689        my %OTRS6NavBarModuleSetting = $SysConfigObject->SettingGet(
2690            Name  => $NavBarModuleSettingName,
2691            NoLog => 1,
2692        );
2693
2694        if (
2695            %OTRS6NavBarModuleSetting
2696            && !$OTRS6NavBarModuleSetting{ModifiedID}
2697            && !$OTRS6NavBarModuleSetting{IsReadonly}
2698            )
2699        {
2700
2701            # set group settings from OTRS 5
2702            $OTRS6NavBarModuleSetting{EffectiveValue}->{Group}   = \@Group;
2703            $OTRS6NavBarModuleSetting{EffectiveValue}->{GroupRo} = \@GroupRo;
2704
2705            # take NavBarModule settings from OTRS 5
2706            for my $Attribute ( sort keys %{ $Param{OTRS5EffectiveValue}->{NavBarModule} } ) {
2707                $OTRS6NavBarModuleSetting{EffectiveValue}->{$Attribute}
2708                    = $Param{OTRS5EffectiveValue}->{NavBarModule}->{$Attribute};
2709            }
2710
2711            # lock the setting
2712            my $ExclusiveLockGUID = $SysConfigObject->SettingLock(
2713                Name   => $NavBarModuleSettingName,
2714                Force  => 1,
2715                UserID => 1,
2716            );
2717
2718            # update the setting
2719            my %Result = $SysConfigObject->SettingUpdate(
2720                Name              => $NavBarModuleSettingName,
2721                IsValid           => 1,
2722                EffectiveValue    => $OTRS6NavBarModuleSetting{EffectiveValue},
2723                ExclusiveLockGUID => $ExclusiveLockGUID,
2724                NoValidation      => 1,
2725                UserID            => 1,
2726            );
2727
2728            # unlock the setting again
2729            $SysConfigObject->SettingUnlock(
2730                Name => $NavBarModuleSettingName,
2731            );
2732
2733            return if !$Result{Success};
2734        }
2735    }
2736
2737    # ###########################################################################
2738    # migrate the NavBar settings
2739    # ###########################################################################
2740
2741    # Skip navbar items if name is empty.
2742    my @OTRS5NavBar = grep {
2743        defined $_->{Name} && length $_->{Name}
2744    } @{ $Param{OTRS5EffectiveValue}->{NavBar} || [] };
2745
2746    if (@OTRS5NavBar) {
2747
2748        # get all OTRS 6 default settings
2749        my @DefaultSettings = $SysConfigObject->ConfigurationList();
2750
2751        # search for OTRS 6 NavBar settings
2752        #
2753        # this will find settings like:
2754        #            Frontend::Navigation###
2755        #    CustomerFrontend::Navigation###
2756        #      PublicFrontend::Navigation###
2757        #
2758        $Param{FrontendSettingName} =~ s{Frontend::Module}{Frontend::Navigation}gsmx;
2759
2760        my $Search       = $Param{FrontendSettingName} . '###' . $Param{FrontendModuleName} . '###';
2761        my @SearchResult = grep { $_->{Name} =~ m{$Search} } @DefaultSettings;
2762
2763        if ( scalar @SearchResult == 1 ) {
2764
2765            # try to get the (default) setting from OTRS 6 for the NavBar setting
2766            my %OTRS6NavBarSetting = $SysConfigObject->SettingGet(
2767                Name  => $SearchResult[0]->{Name},
2768                NoLog => 1,
2769            );
2770
2771            return if !%OTRS6NavBarSetting;
2772
2773            # skip this setting if it has already been modified in the meantime
2774            return 1 if $OTRS6NavBarSetting{ModifiedID};
2775
2776            # skip this setting if it is a readonly setting
2777            return 1 if $OTRS6NavBarSetting{IsReadonly};
2778
2779            $OTRS6NavBarSetting{EffectiveValue} = [];
2780
2781            for my $OTRS5NavBarItem (@OTRS5NavBar) {
2782
2783                if ( !$OTRS5NavBarItem->{Group} ) {
2784                    $OTRS5NavBarItem->{Group} = \@Group;
2785                }
2786                if ( !$OTRS5NavBarItem->{GroupRo} ) {
2787                    $OTRS5NavBarItem->{GroupRo} = \@GroupRo;
2788                }
2789
2790                push @{ $OTRS6NavBarSetting{EffectiveValue} }, $OTRS5NavBarItem;
2791            }
2792
2793            # Save the updated effective value for the current setting.
2794            my %Result = $Self->_SettingUpdate(
2795                Name           => $SearchResult[0]->{Name},
2796                EffectiveValue => $OTRS6NavBarSetting{EffectiveValue},
2797                IsValid        => 1,
2798                UserID         => 1,
2799            );
2800
2801            return if !$Result{Success};
2802        }
2803    }
2804
2805    # No NavBar entries exists in OTRS 5 config for the frontend modulel, so we disable all nav bar settings
2806    #   for this frontend navigation.
2807    else {
2808
2809        # get all OTRS 6 default settings
2810        my @DefaultSettings = $SysConfigObject->ConfigurationList();
2811
2812        # search for OTRS 6 NavBar settings
2813        #
2814        # this will find settings like:
2815        #            Frontend::Navigation###
2816        #    CustomerFrontend::Navigation###
2817        #      PublicFrontend::Navigation###
2818        #
2819        $Param{FrontendSettingName} =~ s{Frontend::Module}{Frontend::Navigation}gsmx;
2820
2821        my $Search       = $Param{FrontendSettingName} . '###' . $Param{FrontendModuleName} . '###';
2822        my @SearchResult = grep { $_->{Name} =~ m{$Search} } @DefaultSettings;
2823
2824        NAVBARSETTING:
2825        for my $NavBarSetting (@SearchResult) {
2826            my $NavBarSettingName = $NavBarSetting->{Name};
2827
2828            # try to get the (default) setting from OTRS 6 for the NavBar setting
2829            my %OTRS6NavBarSetting = $SysConfigObject->SettingGet(
2830                Name  => $NavBarSettingName,
2831                NoLog => 1,
2832            );
2833
2834            next NAVBARSETTING if !%OTRS6NavBarSetting;
2835
2836            # skip this setting if it is already invalid
2837            next NAVBARSETTING if !$OTRS6NavBarSetting{IsValid};
2838
2839            # skip this setting if it has already been modified in the meantime
2840            next NAVBARSETTING if $OTRS6NavBarSetting{ModifiedID};
2841
2842            # skip this setting if it is a readonly setting
2843            next NAVBARSETTING if $OTRS6NavBarSetting{IsReadonly};
2844
2845            # skip this setting if it is a required setting
2846            next NAVBARSETTING if $OTRS6NavBarSetting{IsRequired};
2847
2848            # Disable the setting.
2849            my %Result = $Self->_SettingUpdate(
2850                Name    => $NavBarSettingName,
2851                IsValid => 0,
2852            );
2853
2854            return if !$Result{Success};
2855        }
2856    }
2857
2858    return 1;
2859}
2860
2861=head2 _SettingUpdate()
2862
2863This method locks provided settings(by force), updates them and unlock the setting.
2864
2865    my %Result = $SysConfigMigrationObject->_SettingUpdate(
2866        Name           => 'Setting::Name',
2867        IsValid        => 1,                         # (optional) 1 or 0, modified 0
2868        EffectiveValue => $SettingEffectiveValue,    # (optional)
2869    );
2870
2871Returns:
2872
2873    %Result = (
2874        Success => 1,        # or false in case of an error
2875        Error   => undef,    # error message
2876    );
2877
2878=cut
2879
2880sub _SettingUpdate {
2881    my ( $Self, %Param ) = @_;
2882
2883    return if !$Param{Name};
2884
2885    my $SysConfigObject = $Kernel::OM->Get('Kernel::System::SysConfig');
2886
2887    # lock the setting
2888    my $ExclusiveLockGUID = $SysConfigObject->SettingLock(
2889        Name   => $Param{Name},
2890        Force  => 1,
2891        UserID => 1,
2892    );
2893
2894    # Disable the setting.
2895    my %Result = $SysConfigObject->SettingUpdate(
2896        Name              => $Param{Name},
2897        IsValid           => $Param{IsValid},
2898        EffectiveValue    => $Param{EffectiveValue},
2899        ExclusiveLockGUID => $ExclusiveLockGUID,
2900        NoValidation      => 1,
2901        UserID            => 1,
2902    );
2903
2904    # unlock the setting again
2905    $SysConfigObject->SettingUnlock(
2906        Name => $Param{Name},
2907    );
2908
2909    return %Result;
2910}
2911
29121;
2913
2914=head1 TERMS AND CONDITIONS
2915
2916This software is part of the OTRS project (L<https://otrs.org/>).
2917
2918This software comes with ABSOLUTELY NO WARRANTY. For details, see
2919the enclosed file COPYING for license information (GPL). If you
2920did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
2921
2922=cut
2923