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