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::Modules::AgentDashboardCommon; 10## nofilter(TidyAll::Plugin::OTRS::Perl::DBObject) 11 12use strict; 13use warnings; 14 15use Kernel::Language qw(Translatable); 16use Kernel::System::VariableCheck qw(:all); 17 18our $ObjectManagerDisabled = 1; 19 20sub new { 21 my ( $Type, %Param ) = @_; 22 23 # allocate new hash for object 24 my $Self = {%Param}; 25 bless( $Self, $Type ); 26 27 return $Self; 28} 29 30sub Run { 31 my ( $Self, %Param ) = @_; 32 33 my $BackendConfigKey = 'DashboardBackend'; 34 my $MainMenuConfigKey = 'AgentDashboard::MainMenu'; 35 my $UserSettingsKey = 'UserDashboard'; 36 37 if ( $Self->{Action} eq 'AgentCustomerInformationCenter' ) { 38 $BackendConfigKey = 'AgentCustomerInformationCenter::Backend'; 39 $MainMenuConfigKey = 'AgentCustomerInformationCenter::MainMenu'; 40 $UserSettingsKey = 'UserCustomerInformationCenter'; 41 } 42 elsif ( $Self->{Action} eq 'AgentCustomerUserInformationCenter' ) { 43 $BackendConfigKey = 'AgentCustomerUserInformationCenter::Backend'; 44 $MainMenuConfigKey = 'AgentCustomerUserInformationCenter::MainMenu'; 45 $UserSettingsKey = 'UserCustomerUserInformationCenter'; 46 } 47 48 # get needed objects 49 my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); 50 my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); 51 52 # load backends 53 my $Config = $ConfigObject->Get($BackendConfigKey); 54 if ( !$Config ) { 55 return $LayoutObject->ErrorScreen( 56 Message => $LayoutObject->{LanguageObject}->Translate( 'No such config for %s', $BackendConfigKey ), 57 ); 58 } 59 60 # Get all configured statistics from the system that should be shown as a dashboard widget 61 # and register them dynamically in the configuration. 62 my @StatsIDs; 63 if ( $Self->{Action} eq 'AgentDashboard' ) { 64 65 my $StatsHash = $Kernel::OM->Get('Kernel::System::Stats')->StatsListGet( 66 UserID => $Self->{UserID}, 67 ); 68 69 if ( IsHashRefWithData($StatsHash) ) { 70 STATID: 71 for my $StatID ( sort keys %{$StatsHash} ) { 72 next STATID if !$StatsHash->{$StatID}->{ShowAsDashboardWidget}; 73 74 # check permissions 75 next STATID if !$StatsHash->{$StatID}->{Permission}; 76 next STATID if !IsArrayRefWithData( $StatsHash->{$StatID}->{Permission} ); 77 78 my @StatsPermissionGroupNames; 79 for my $GroupID ( @{ $StatsHash->{$StatID}->{Permission} } ) { 80 push @StatsPermissionGroupNames, 81 $Kernel::OM->Get('Kernel::System::Group')->GroupLookup( GroupID => $GroupID ); 82 } 83 my $StatsPermissionGroups = join( ';', @StatsPermissionGroupNames ); 84 85 # replace all line breaks with spaces (otherwise Translate() will not work correctly) 86 $StatsHash->{$StatID}->{Description} =~ s{\r?\n|\r}{ }msxg; 87 88 my $Description = $LayoutObject->{LanguageObject}->Translate( $StatsHash->{$StatID}->{Description} ); 89 90 my $Title = $LayoutObject->{LanguageObject}->Translate( $StatsHash->{$StatID}->{Title} ); 91 $Title = $LayoutObject->{LanguageObject}->Translate('Statistic') . ': ' 92 . $Title . ' (' 93 . $ConfigObject->Get('Stats::StatsHook') 94 . $StatsHash->{$StatID}->{StatNumber} . ')'; 95 96 $Config->{ ( $StatID + 1000 ) . '-Stats' } = { 97 'Block' => 'ContentLarge', 98 'Default' => 0, 99 'Module' => 'Kernel::Output::HTML::Dashboard::Stats', 100 'Title' => $Title, 101 'StatID' => $StatID, 102 'Description' => $Description, 103 'Group' => $StatsPermissionGroups, 104 }; 105 push @StatsIDs, $StatID; 106 } 107 108 # send data to JS 109 $LayoutObject->AddJSData( 110 Key => 'DashboardStatsIDs', 111 Value => \@StatsIDs 112 ); 113 } 114 } 115 116 # get needed objects 117 my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); 118 119 if ( $Self->{Action} eq 'AgentCustomerInformationCenter' ) { 120 121 $Self->{CustomerID} = $ParamObject->GetParam( Param => 'CustomerID' ); 122 123 # check CustomerID presence for all subactions that need it 124 if ( $Self->{Subaction} ne 'UpdatePosition' ) { 125 if ( !$Self->{CustomerID} ) { 126 127 $LayoutObject->AddJSOnDocumentComplete( 128 Code => 'Core.Agent.CustomerInformationCenterSearch.OpenSearchDialog();' 129 ); 130 131 my $Output = $LayoutObject->Header(); 132 $Output .= $LayoutObject->NavigationBar(); 133 $Output .= $LayoutObject->Footer(); 134 return $Output; 135 } 136 } 137 } 138 elsif ( $Self->{Action} eq 'AgentCustomerUserInformationCenter' ) { 139 140 $Self->{CustomerUserID} = $ParamObject->GetParam( Param => 'CustomerUserID' ); 141 142 # check CustomerUserID presence for all subactions that need it 143 if ( $Self->{Subaction} ne 'UpdatePosition' ) { 144 145 if ( !$Self->{CustomerUserID} ) { 146 147 $LayoutObject->AddJSOnDocumentComplete( 148 Code => 'Core.Agent.CustomerUserInformationCenterSearch.OpenSearchDialog();' 149 ); 150 151 my $Output = $LayoutObject->Header(); 152 $Output .= $LayoutObject->NavigationBar(); 153 $Output .= $LayoutObject->Footer(); 154 return $Output; 155 } 156 } 157 } 158 159 # get needed objects 160 my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField'); 161 my $SessionObject = $Kernel::OM->Get('Kernel::System::AuthSession'); 162 my $UserObject = $Kernel::OM->Get('Kernel::System::User'); 163 164 # update/close item 165 if ( $Self->{Subaction} eq 'UpdateRemove' ) { 166 167 # challenge token check for write action 168 $LayoutObject->ChallengeTokenCheck(); 169 170 my $Name = $ParamObject->GetParam( Param => 'Name' ); 171 my $Key = $UserSettingsKey . $Name; 172 173 # Mandatory widgets can't be removed. 174 if ( $Config->{$Name} && $Config->{$Name}->{Mandatory} ) { 175 176 return $LayoutObject->Redirect( 177 OP => "Action=$Self->{Action}", 178 ); 179 } 180 181 # update session 182 $SessionObject->UpdateSessionID( 183 SessionID => $Self->{SessionID}, 184 Key => $Key, 185 Value => 0, 186 ); 187 188 # update preferences 189 if ( !$ConfigObject->Get('DemoSystem') ) { 190 $UserObject->SetPreferences( 191 UserID => $Self->{UserID}, 192 Key => $Key, 193 Value => 0, 194 ); 195 } 196 197 my $URL = "Action=$Self->{Action}"; 198 if ( $Self->{CustomerID} ) { 199 $URL .= ";CustomerID=" . $LayoutObject->LinkEncode( $Self->{CustomerID} ); 200 } 201 if ( $Self->{CustomerUserID} ) { 202 $URL .= ";CustomerUserID=" . $LayoutObject->LinkEncode( $Self->{CustomerUserID} ); 203 } 204 205 return $LayoutObject->Redirect( 206 OP => $URL, 207 ); 208 } 209 210 # update preferences 211 elsif ( $Self->{Subaction} eq 'UpdatePreferences' ) { 212 213 # challenge token check for write action 214 $LayoutObject->ChallengeTokenCheck(); 215 216 my $Name = $ParamObject->GetParam( Param => 'Name' ); 217 218 # get preferences settings 219 my @PreferencesOnly = $Self->_Element( 220 Name => $Name, 221 Configs => $Config, 222 PreferencesOnly => 1, 223 ); 224 if ( !@PreferencesOnly ) { 225 $LayoutObject->FatalError( 226 Message => $LayoutObject->{LanguageObject}->Translate( 'No preferences for %s!', $Name ), 227 ); 228 } 229 230 # remember preferences 231 for my $Param (@PreferencesOnly) { 232 233 # get params 234 my $Value = $ParamObject->GetParam( Param => $Param->{Name} ); 235 236 # update runtime vars 237 $LayoutObject->{ $Param->{Name} } = $Value; 238 239 # update session 240 $SessionObject->UpdateSessionID( 241 SessionID => $Self->{SessionID}, 242 Key => $Param->{Name}, 243 Value => $Value, 244 ); 245 246 # update preferences 247 if ( !$ConfigObject->Get('DemoSystem') ) { 248 $UserObject->SetPreferences( 249 UserID => $Self->{UserID}, 250 Key => $Param->{Name}, 251 Value => $Value, 252 ); 253 } 254 } 255 256 # deliver new content page 257 my %ElementReload = $Self->_Element( 258 Name => $Name, 259 Configs => $Config, 260 AJAX => 1 261 ); 262 if ( !%ElementReload ) { 263 $LayoutObject->FatalError( 264 Message => $LayoutObject->{LanguageObject}->Translate( 'Can\'t get element data of %s!', $Name ), 265 ); 266 } 267 return $LayoutObject->Attachment( 268 ContentType => 'text/html', 269 Content => ${ $ElementReload{Content} }, 270 Type => 'inline', 271 NoCache => 1, 272 ); 273 } 274 275 # update settings 276 elsif ( $Self->{Subaction} eq 'UpdateSettings' ) { 277 278 # challenge token check for write action 279 $LayoutObject->ChallengeTokenCheck(); 280 281 my @Backends = $ParamObject->GetArray( Param => 'Backend' ); 282 for my $Name ( sort keys %{$Config} ) { 283 my $Active = 0; 284 BACKEND: 285 for my $Backend (@Backends) { 286 next BACKEND if $Backend ne $Name; 287 $Active = 1; 288 last BACKEND; 289 } 290 291 # Mandatory widgets can not be removed. 292 if ( $Config->{$Name}->{Mandatory} ) { 293 $Active = 1; 294 } 295 296 my $Key = $UserSettingsKey . $Name; 297 298 # update session 299 $SessionObject->UpdateSessionID( 300 SessionID => $Self->{SessionID}, 301 Key => $Key, 302 Value => $Active, 303 ); 304 305 # update preferences 306 if ( !$ConfigObject->Get('DemoSystem') ) { 307 $UserObject->SetPreferences( 308 UserID => $Self->{UserID}, 309 Key => $Key, 310 Value => $Active, 311 ); 312 } 313 } 314 315 my $URL = "Action=$Self->{Action}"; 316 if ( $Self->{CustomerID} ) { 317 $URL .= ";CustomerID=" . $LayoutObject->LinkEncode( $Self->{CustomerID} ); 318 } 319 if ( $Self->{CustomerUserID} ) { 320 $URL .= ";CustomerUserID=" . $LayoutObject->LinkEncode( $Self->{CustomerUserID} ); 321 } 322 323 return $LayoutObject->Redirect( 324 OP => $URL, 325 ); 326 } 327 328 # update position 329 elsif ( $Self->{Subaction} eq 'UpdatePosition' ) { 330 331 # challenge token check for write action 332 $LayoutObject->ChallengeTokenCheck(); 333 334 my @Backends = $ParamObject->GetArray( Param => 'Backend' ); 335 336 # get new order 337 my $Key = $UserSettingsKey . 'Position'; 338 my $Data = ''; 339 for my $Backend (@Backends) { 340 $Backend =~ s{ \A Dashboard (.+?) -box \z }{$1}gxms; 341 $Data .= $Backend . ';'; 342 } 343 344 # update session 345 $SessionObject->UpdateSessionID( 346 SessionID => $Self->{SessionID}, 347 Key => $Key, 348 Value => $Data, 349 ); 350 351 # update preferences 352 if ( !$ConfigObject->Get('DemoSystem') ) { 353 $UserObject->SetPreferences( 354 UserID => $Self->{UserID}, 355 Key => $Key, 356 Value => $Data, 357 ); 358 } 359 360 # send successful response 361 return $LayoutObject->Attachment( 362 ContentType => 'text/html', 363 Charset => $LayoutObject->{UserCharset}, 364 Content => '1', 365 ); 366 } 367 368 # deliver element 369 elsif ( $Self->{Subaction} eq 'Element' ) { 370 371 my $Name = $ParamObject->GetParam( Param => 'Name' ); 372 373 # get the column filters from the web request 374 my %ColumnFilter; 375 my %GetColumnFilter; 376 my %GetColumnFilterSelect; 377 378 COLUMNNAME: 379 for my $ColumnName ( 380 qw(Owner Responsible State Queue Priority Type Lock Service SLA CustomerID CustomerUserID) 381 ) 382 { 383 my $FilterValue = $ParamObject->GetParam( Param => 'ColumnFilter' . $ColumnName . $Name ) 384 || ''; 385 next COLUMNNAME if $FilterValue eq ''; 386 387 if ( $ColumnName eq 'CustomerID' ) { 388 push @{ $ColumnFilter{$ColumnName} }, $FilterValue; 389 push @{ $ColumnFilter{ $ColumnName . 'Raw' } }, $FilterValue; 390 } 391 elsif ( $ColumnName eq 'CustomerUserID' ) { 392 push @{ $ColumnFilter{CustomerUserLogin} }, $FilterValue; 393 push @{ $ColumnFilter{CustomerUserLoginRaw} }, $FilterValue; 394 } 395 else { 396 push @{ $ColumnFilter{ $ColumnName . 'IDs' } }, $FilterValue; 397 } 398 399 $GetColumnFilter{ $ColumnName . $Name } = $FilterValue; 400 $GetColumnFilterSelect{$ColumnName} = $FilterValue; 401 } 402 403 # get all dynamic fields 404 my $DynamicField = $DynamicFieldObject->DynamicFieldListGet( 405 Valid => 1, 406 ObjectType => ['Ticket'], 407 ); 408 409 DYNAMICFIELD: 410 for my $DynamicFieldConfig ( @{$DynamicField} ) { 411 next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig); 412 next DYNAMICFIELD if !$DynamicFieldConfig->{Name}; 413 414 my $FilterValue = $ParamObject->GetParam( 415 Param => 'ColumnFilterDynamicField_' . $DynamicFieldConfig->{Name} . $Name 416 ); 417 418 next DYNAMICFIELD if !defined $FilterValue; 419 next DYNAMICFIELD if $FilterValue eq ''; 420 421 $ColumnFilter{ 'DynamicField_' . $DynamicFieldConfig->{Name} } = { 422 Equals => $FilterValue, 423 }; 424 $GetColumnFilter{ 'DynamicField_' . $DynamicFieldConfig->{Name} . $Name } = $FilterValue; 425 $GetColumnFilterSelect{ 'DynamicField_' . $DynamicFieldConfig->{Name} } = $FilterValue; 426 } 427 428 my $SortBy = $ParamObject->GetParam( Param => 'SortBy' ); 429 my $OrderBy = $ParamObject->GetParam( Param => 'OrderBy' ); 430 431 my %Element = $Self->_Element( 432 Name => $Name, 433 Configs => $Config, 434 AJAX => 1, 435 SortBy => $SortBy, 436 OrderBy => $OrderBy, 437 ColumnFilter => \%ColumnFilter, 438 GetColumnFilter => \%GetColumnFilter, 439 GetColumnFilterSelect => \%GetColumnFilterSelect, 440 ); 441 442 if ( !%Element ) { 443 $LayoutObject->FatalError( 444 Message => $LayoutObject->{LanguageObject}->Translate( 'Can\'t get element data of %s!', $Name ), 445 ); 446 } 447 return $LayoutObject->Attachment( 448 ContentType => 'text/html', 449 Charset => $LayoutObject->{UserCharset}, 450 Content => ${ $Element{Content} }, 451 Type => 'inline', 452 NoCache => 1, 453 ); 454 } 455 456 # deliver element 457 elsif ( $Self->{Subaction} eq 'AJAXFilterUpdate' ) { 458 459 my $ElementChanged = $ParamObject->GetParam( Param => 'ElementChanged' ); 460 my ($Name) = $ElementChanged =~ m{ ( \d{4} - .*? ) \z }gxms; 461 my $Column = $ElementChanged; 462 $Column =~ s{ \A ColumnFilter }{}gxms; 463 $Column =~ s{ $Name }{}gxms; 464 465 my $FilterContent = $Self->_Element( 466 Name => $Name, 467 FilterContentOnly => 1, 468 FilterColumn => $Column, 469 ElementChanged => $ElementChanged, 470 Configs => $Config, 471 ); 472 473 if ( !$FilterContent ) { 474 $LayoutObject->FatalError( 475 Message => $LayoutObject->{LanguageObject}->Translate( 'Can\'t get filter content data of %s!', $Name ), 476 ); 477 } 478 479 return $LayoutObject->Attachment( 480 ContentType => 'application/json; charset=' . $LayoutObject->{Charset}, 481 Content => $FilterContent, 482 Type => 'inline', 483 NoCache => 1, 484 ); 485 486 } 487 488 # store last queue screen 489 $SessionObject->UpdateSessionID( 490 SessionID => $Self->{SessionID}, 491 Key => 'LastScreenOverview', 492 Value => $Self->{RequestedURL}, 493 ); 494 495 my %ContentBlockData; 496 497 if ( $Self->{Action} eq 'AgentCustomerInformationCenter' ) { 498 499 $ContentBlockData{CustomerID} = $Self->{CustomerID}; 500 501 # H1 title 502 $ContentBlockData{CustomerIDTitle} = $Self->{CustomerID}; 503 504 my %CustomerCompanyData = $Kernel::OM->Get('Kernel::System::CustomerCompany')->CustomerCompanyGet( 505 CustomerID => $Self->{CustomerID}, 506 ); 507 508 if ( $CustomerCompanyData{CustomerCompanyName} ) { 509 $ContentBlockData{CustomerIDTitle} = "$CustomerCompanyData{CustomerCompanyName} ($Self->{CustomerID})"; 510 } 511 } 512 elsif ( $Self->{Action} eq 'AgentCustomerUserInformationCenter' ) { 513 514 my %CustomerUserData = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerUserDataGet( 515 User => $Self->{CustomerUserID}, 516 ); 517 518 $ContentBlockData{CustomerUserID} = $Self->{CustomerUserID}; 519 520 # H1 title 521 $ContentBlockData{CustomerUserIDTitle} = "\"$CustomerUserData{UserFullname}\" <$CustomerUserData{UserEmail}>"; 522 523 } 524 525 # show dashboard 526 $LayoutObject->Block( 527 Name => 'Content', 528 Data => \%ContentBlockData, 529 ); 530 531 my $GroupObject = $Kernel::OM->Get('Kernel::System::Group'); 532 533 # get shown backends 534 my %Backends; 535 BACKEND: 536 for my $Name ( sort keys %{$Config} ) { 537 538 # check permissions 539 if ( $Config->{$Name}->{Group} ) { 540 my $PermissionOK = 0; 541 my @Groups = split /;/, $Config->{$Name}->{Group}; 542 GROUP: 543 for my $Group (@Groups) { 544 my $HasPermission = $GroupObject->PermissionCheck( 545 UserID => $Self->{UserID}, 546 GroupName => $Group, 547 Type => 'ro', 548 ); 549 if ($HasPermission) { 550 $PermissionOK = 1; 551 last GROUP; 552 } 553 } 554 next BACKEND if !$PermissionOK; 555 } 556 557 my $Key = $UserSettingsKey . $Name; 558 if ( defined $Self->{$Key} ) { 559 $Backends{$Name} = $Self->{$Key}; 560 } 561 else { 562 $Backends{$Name} = $Config->{$Name}->{Default}; 563 } 564 565 # Always show widgets with mandatory flag. 566 if ( $Config->{$Name}->{Mandatory} ) { 567 $Backends{$Name} = $Config->{$Name}->{Mandatory}; 568 } 569 } 570 571 # set order of plugins 572 my $Key = $UserSettingsKey . 'Position'; 573 my @Order; 574 my $Value = $Self->{$Key}; 575 576 if ($Value) { 577 @Order = split /;/, $Value; 578 579 # only use active backends 580 @Order = grep { $Config->{$_} } @Order; 581 } 582 if ( !@Order ) { 583 for my $Name ( sort keys %Backends ) { 584 push @Order, $Name; 585 } 586 } 587 588 # add not ordered plugins (e. g. new active) 589 NAME: 590 for my $Name ( sort keys %Backends ) { 591 my $Included = 0; 592 ITEM: 593 for my $Item (@Order) { 594 next ITEM if $Item ne $Name; 595 $Included = 1; 596 } 597 next NAME if $Included; 598 push @Order, $Name; 599 } 600 601 # get default columns 602 my $Columns = $Self->{Config}->{DefaultColumns} || $ConfigObject->Get('DefaultOverviewColumns') || {}; 603 604 # try every backend to load and execute it 605 my @ContainerNames; 606 NAME: 607 for my $Name (@Order) { 608 609 # get element data 610 my %Element = $Self->_Element( 611 Name => $Name, 612 Configs => $Config, 613 Backends => \%Backends, 614 ); 615 next NAME if !%Element; 616 617 # NameForm (to support IE, is not working with "-" in form names) 618 my $NameForm = $Name; 619 $NameForm =~ s{-}{}g; 620 621 my %JSData = ( 622 Name => $Name, 623 NameForm => $NameForm, 624 ); 625 626 push @ContainerNames, \%JSData; 627 628 # rendering 629 $LayoutObject->Block( 630 Name => $Element{Config}->{Block}, 631 Data => { 632 %{ $Element{Config} }, 633 Name => $Name, 634 NameForm => $NameForm, 635 Content => ${ $Element{Content} }, 636 CustomerID => $Self->{CustomerID} || '', 637 CustomerUserID => $Self->{CustomerUserID} || '', 638 }, 639 ); 640 641 # show refresh link if refreshing is available 642 if ( $Element{Config}->{CanRefresh} ) { 643 644 my $NameHTML = $Name; 645 $NameHTML =~ s{-}{_}xmsg; 646 647 # send data to JS 648 $LayoutObject->AddJSData( 649 Key => 'CanRefresh-' . $Name, 650 Value => { 651 Name => $Name, 652 NameHTML => $NameHTML, 653 } 654 ); 655 656 $LayoutObject->Block( 657 Name => $Element{Config}->{Block} . 'Refresh', 658 Data => { 659 %{ $Element{Config} }, 660 Name => $Name, 661 NameHTML => $NameHTML, 662 }, 663 ); 664 } 665 666 # Do not show the delete link if the widget is mandatory. 667 if ( !$Config->{$Name}->{Mandatory} ) { 668 669 $LayoutObject->Block( 670 Name => $Element{Config}->{Block} . 'Remove', 671 Data => { 672 %{ $Element{Config} }, 673 Name => $Name, 674 CustomerID => $Self->{CustomerID} || '', 675 CustomerUserID => $Self->{CustomerUserID} || '', 676 }, 677 ); 678 } 679 680 # if column is not a default column, add it for translation 681 for my $Column ( sort keys %{ $Element{Config}->{DefaultColumns} } ) { 682 if ( !defined $Columns->{$Column} ) { 683 $Columns->{$Column} = $Element{Config}->{DefaultColumns}->{$Column}; 684 } 685 } 686 687 # show settings link if preferences are available 688 if ( $Element{Preferences} && @{ $Element{Preferences} } ) { 689 $LayoutObject->Block( 690 Name => $Element{Config}->{Block} . 'Preferences', 691 Data => { 692 %{ $Element{Config} }, 693 Name => $Name, 694 NameForm => $NameForm, 695 }, 696 ); 697 PARAM: 698 for my $Param ( @{ $Element{Preferences} } ) { 699 700 # special parameters are added, which do not have a tt block, 701 # because the displayed fields are added with the output filter, 702 # so there is no need to call any block here 703 next PARAM if !$Param->{Block}; 704 705 $LayoutObject->Block( 706 Name => $Element{Config}->{Block} . 'PreferencesItem', 707 Data => { 708 %{ $Element{Config} }, 709 Name => $Name, 710 NameForm => $NameForm, 711 }, 712 ); 713 if ( $Param->{Block} eq 'Option' ) { 714 $Param->{Option} = $LayoutObject->BuildSelection( 715 Data => $Param->{Data}, 716 Name => $Param->{Name}, 717 SelectedID => $Param->{SelectedID}, 718 Translation => $Param->{Translation}, 719 Class => 'Modernize', 720 ); 721 } 722 $LayoutObject->Block( 723 Name => $Element{Config}->{Block} . 'PreferencesItem' . $Param->{Block}, 724 Data => { 725 %{ $Element{Config} }, 726 %{$Param}, 727 Data => $Self->{ $Param->{Name} }, 728 NamePref => $Param->{Name}, 729 Name => $Name, 730 NameForm => $NameForm, 731 }, 732 ); 733 } 734 } 735 736 # more link 737 if ( $Element{Config}->{Link} ) { 738 $LayoutObject->Block( 739 Name => $Element{Config}->{Block} . 'More', 740 Data => { 741 %{ $Element{Config} }, 742 }, 743 ); 744 } 745 } 746 747 # send data to JS 748 $LayoutObject->AddJSData( 749 Key => 'ContainerNames', 750 Value => \@ContainerNames, 751 ); 752 753 # build main menu 754 my $MainMenuConfig = $ConfigObject->Get($MainMenuConfigKey); 755 if ( IsHashRefWithData($MainMenuConfig) ) { 756 $LayoutObject->Block( Name => 'MainMenu' ); 757 758 for my $MainMenuItem ( sort keys %{$MainMenuConfig} ) { 759 760 $LayoutObject->Block( 761 Name => 'MainMenuItem', 762 Data => { 763 %{ $MainMenuConfig->{$MainMenuItem} }, 764 CustomerID => $Self->{CustomerID}, 765 CustomerUserID => $Self->{CustomerUserID}, 766 }, 767 ); 768 } 769 } 770 771 # add translations for the allocation lists for regular columns 772 if ( $Columns && IsHashRefWithData($Columns) ) { 773 774 COLUMN: 775 for my $Column ( sort keys %{$Columns} ) { 776 777 # dynamic fields will be translated in the next block 778 next COLUMN if $Column =~ m{ \A DynamicField_ }xms; 779 780 my $TranslatedWord = $Column; 781 if ( $Column eq 'EscalationTime' ) { 782 $TranslatedWord = Translatable('Service Time'); 783 } 784 elsif ( $Column eq 'EscalationResponseTime' ) { 785 $TranslatedWord = Translatable('First Response Time'); 786 } 787 elsif ( $Column eq 'EscalationSolutionTime' ) { 788 $TranslatedWord = Translatable('Solution Time'); 789 } 790 elsif ( $Column eq 'EscalationUpdateTime' ) { 791 $TranslatedWord = Translatable('Update Time'); 792 } 793 elsif ( $Column eq 'PendingTime' ) { 794 $TranslatedWord = Translatable('Pending till'); 795 } 796 elsif ( $Column eq 'CustomerCompanyName' ) { 797 $TranslatedWord = Translatable('Customer Name'); 798 } 799 elsif ( $Column eq 'CustomerID' ) { 800 $TranslatedWord = Translatable('Customer ID'); 801 } 802 elsif ( $Column eq 'CustomerName' ) { 803 $TranslatedWord = Translatable('Customer User Name'); 804 } 805 elsif ( $Column eq 'CustomerUserID' ) { 806 $TranslatedWord = Translatable('Customer User ID'); 807 } 808 809 # send data to JS 810 $LayoutObject->AddJSData( 811 Key => 'Column' . $Column, 812 Value => $LayoutObject->{LanguageObject}->Translate($TranslatedWord), 813 ); 814 815 } 816 } 817 818 # add translations for the allocation lists for dynamic field columns 819 my $ColumnsDynamicField = $DynamicFieldObject->DynamicFieldListGet( 820 Valid => 0, 821 ObjectType => ['Ticket'], 822 ); 823 824 if ( $ColumnsDynamicField && IsArrayRefWithData($ColumnsDynamicField) ) { 825 826 my $Counter = 0; 827 828 DYNAMICFIELD: 829 for my $DynamicField ( sort @{$ColumnsDynamicField} ) { 830 831 next DYNAMICFIELD if !$DynamicField; 832 833 $Counter++; 834 835 # send data to JS 836 $LayoutObject->AddJSData( 837 Key => 'ColumnDynamicField_' . $DynamicField->{Name}, 838 Value => $LayoutObject->{LanguageObject}->Translate( $DynamicField->{Label} ), 839 ); 840 } 841 } 842 843 my $Output = $LayoutObject->Header(); 844 $Output .= $LayoutObject->NavigationBar(); 845 $Output .= $LayoutObject->Output( 846 TemplateFile => $Self->{Action}, 847 Data => \%Param 848 ); 849 $Output .= $LayoutObject->Footer(); 850 return $Output; 851} 852 853sub _Element { 854 my ( $Self, %Param ) = @_; 855 856 my $Name = $Param{Name}; 857 my $Configs = $Param{Configs}; 858 my $Backends = $Param{Backends}; 859 my $SortBy = $Param{SortBy}; 860 my $OrderBy = $Param{OrderBy}; 861 my $ColumnFilter = $Param{ColumnFilter}; 862 my $GetColumnFilter = $Param{GetColumnFilter}; 863 my $GetColumnFilterSelect = $Param{GetColumnFilterSelect}; 864 865 my $GroupObject = $Kernel::OM->Get('Kernel::System::Group'); 866 867 # check permissions 868 if ( $Configs->{$Name}->{Group} ) { 869 my $PermissionOK = 0; 870 my @Groups = split /;/, $Configs->{$Name}->{Group}; 871 GROUP: 872 for my $Group (@Groups) { 873 my $HasPermission = $GroupObject->PermissionCheck( 874 UserID => $Self->{UserID}, 875 GroupName => $Group, 876 Type => 'ro', 877 ); 878 if ($HasPermission) { 879 $PermissionOK = 1; 880 last GROUP; 881 } 882 } 883 return if !$PermissionOK; 884 } 885 886 # get config object 887 my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); 888 889 # load backends 890 my $Module = $Configs->{$Name}->{Module}; 891 return if !$Kernel::OM->Get('Kernel::System::Main')->Require($Module); 892 my $Object = $Module->new( 893 %{$Self}, 894 Config => $Configs->{$Name}, 895 Name => $Name, 896 CustomerID => $Self->{CustomerID} || '', 897 CustomerUserID => $Self->{CustomerUserID} || '', 898 SortBy => $SortBy, 899 OrderBy => $OrderBy, 900 ColumnFilter => $ColumnFilter, 901 GetColumnFilter => $GetColumnFilter, 902 GetColumnFilterSelect => $GetColumnFilterSelect, 903 ); 904 905 # get module config 906 my %Config = $Object->Config(); 907 908 # Perform the actual data fetching and computation on the slave db, if configured 909 local $Kernel::System::DB::UseSlaveDB = 1; 910 911 # get module preferences 912 my @Preferences = $Object->Preferences(); 913 return @Preferences if $Param{PreferencesOnly}; 914 915 # Perform the actual data fetching and computation on the slave db, if configured 916 local $Kernel::System::DB::UseSlaveDB = 1; 917 918 if ( $Param{FilterContentOnly} ) { 919 my $FilterContent = $Object->FilterContent( 920 FilterColumn => $Param{FilterColumn}, 921 Config => $Configs->{$Name}, 922 Name => $Name, 923 CustomerID => $Self->{CustomerID} || '', 924 CustomerUserID => $Self->{CustomerUserID} || '', 925 ); 926 return $FilterContent; 927 } 928 929 my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); 930 931 # add backend to settings selection 932 if ($Backends) { 933 my $Checked = ''; 934 if ( $Backends->{$Name} || $Configs->{$Name}->{Mandatory} ) { 935 $Checked = 'checked="checked"'; 936 } 937 938 # Check whether the widget is forcibly displayed. 939 # Mandatory widgets are displayed as read-only. 940 my $Readonly = ''; 941 if ( $Configs->{$Name}->{Mandatory} ) { 942 $Readonly = 'disabled="disabled"'; 943 } 944 945 $LayoutObject->Block( 946 Name => 'ContentSettings', 947 Data => { 948 %Config, 949 Name => $Name, 950 Checked => $Checked, 951 Readonly => $Readonly, 952 }, 953 ); 954 955 return if !$Backends->{$Name}; 956 } 957 958 # check backends cache (html page cache) 959 my $Content; 960 my $CacheKey = $Config{CacheKey}; 961 my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache'); 962 963 if ( !$CacheKey ) { 964 $CacheKey = $Name . '-' 965 . ( $Self->{CustomerID} || '' ) . '-' 966 . ( $Self->{CustomerUserID} || '' ) . '-' 967 . $LayoutObject->{UserLanguage}; 968 } 969 if ( $Config{CacheTTL} ) { 970 $Content = $CacheObject->Get( 971 Type => 'Dashboard', 972 Key => $CacheKey, 973 ); 974 } 975 976 # execute backends 977 my $CacheUsed = 1; 978 if ( !defined $Content || $SortBy ) { 979 $CacheUsed = 0; 980 $Content = $Object->Run( 981 AJAX => $Param{AJAX}, 982 CustomerID => $Self->{CustomerID} || '', 983 CustomerUserID => $Self->{CustomerUserID} || '', 984 ); 985 } 986 987 # check if content should be shown 988 return if !$Content; 989 990 # set cache (html page cache) 991 if ( !$CacheUsed && $Config{CacheTTL} ) { 992 $CacheObject->Set( 993 Type => 'Dashboard', 994 Key => $CacheKey, 995 Value => $Content, 996 TTL => $Config{CacheTTL} * 60, 997 ); 998 } 999 1000 # return result 1001 return ( 1002 Content => \$Content, 1003 Config => \%Config, 1004 Preferences => \@Preferences, 1005 ); 1006} 1007 10081; 1009