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