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::AdminCommunicationLog;
10
11use strict;
12use warnings;
13
14our $ObjectManagerDisabled = 1;
15
16use Kernel::System::VariableCheck qw(:all);
17use Kernel::Language qw(Translatable);
18
19sub new {
20    my ( $Type, %Param ) = @_;
21
22    my $Self = {%Param};
23    bless( $Self, $Type );
24
25    return $Self;
26}
27
28sub Run {
29    my ( $Self, %Param ) = @_;
30
31    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
32    my $ParamObject  = $Kernel::OM->Get('Kernel::System::Web::Request');
33
34    my %GetParam;
35    for my $Param (
36        qw(
37        CommunicationID ObjectLogID StartTime Filter SortBy
38        OrderBy StartHit Expand AccountID Direct PriorityFilter
39        )
40        )
41    {
42        $GetParam{$Param} = $ParamObject->GetParam( Param => $Param );
43    }
44
45    my $Communication;
46    if ( $GetParam{CommunicationID} ) {
47        my $CommunicationLogDBObj = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB');
48        $Communication = $CommunicationLogDBObj->CommunicationGet(
49            CommunicationID => $GetParam{CommunicationID},
50        );
51
52        if ( !IsHashRefWithData($Communication) ) {
53            return $LayoutObject->FatalError(
54                Message => Translatable('Invalid CommunicationID!'),
55            );
56        }
57    }
58
59    my %TimeRanges = (
60        0       => Translatable('All communications'),
61        3600    => Translatable('Last 1 hour'),
62        10800   => Translatable('Last 3 hours'),
63        21600   => Translatable('Last 6 hours'),
64        43200   => Translatable('Last 12 hours'),
65        86400   => Translatable('Last 24 hours'),
66        604800  => Translatable('Last week'),
67        2593000 => Translatable('Last month'),
68    );
69
70    $GetParam{TimeRanges} = \%TimeRanges;
71
72    $GetParam{StartHit}  //= int( $Param{StartHit} || 1 );
73    $GetParam{SortBy}    //= 'StartTime';
74    $GetParam{OrderBy}   //= 'Down';
75    $GetParam{Filter}    //= 'All';
76    $GetParam{StartTime} //= 86400;
77
78    if ( $GetParam{StartTime} && $GetParam{StartTime} !~ m{^\d+$} ) {
79        return $LayoutObject->FatalError(
80            Message => $LayoutObject->{LanguageObject}->Translate( 'Invalid StartTime: %s!', $GetParam{StartTime} ),
81        );
82    }
83    elsif ( $GetParam{StartTime} == 0 ) {
84        $GetParam{DateTime} = $GetParam{StartTime};
85    }
86    else {
87        my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
88        my $ValidDate      = $DateTimeObject->Subtract(
89            Seconds => $GetParam{StartTime},
90        );
91
92        if ( !$ValidDate ) {
93            return $LayoutObject->FatalError(
94                Message => $LayoutObject->{LanguageObject}->Translate( 'Invalid StartTime: %s!', $GetParam{StartTime} ),
95            );
96        }
97        $GetParam{DateTime} = $DateTimeObject->ToString();
98    }
99
100    my %SubactionHandlerMap = (
101        Overview            => '_ShowOverview',
102        Zoom                => '_ZoomView',
103        Accounts            => '_AccountsView',
104        GetObjectLog        => '_GetObjectLog',
105        GetCommunicationLog => '_GetCommunicationLog',
106    );
107
108    my $Subaction = $Self->{Subaction};
109    if ( !( exists $SubactionHandlerMap{$Subaction} ) ) {
110        $Subaction = 'Overview';
111    }
112
113    my $SubactionHandler = $SubactionHandlerMap{$Subaction};
114
115    return $Self->$SubactionHandler(
116        %GetParam,
117        Action        => $Subaction,
118        Communication => $Communication,
119    );
120}
121
122sub _ShowOverview {
123    my ( $Self, %Param ) = @_;
124
125    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
126
127    my $Output = $LayoutObject->Header();
128    $Output .= $LayoutObject->NavigationBar();
129
130    my $TimeRangeStrg = $LayoutObject->BuildSelection(
131        Data         => $Param{TimeRanges},
132        Name         => 'TimeRange',
133        ID           => 'TimeRange',
134        SelectedID   => $Param{StartTime} // 86400,
135        PossibleNone => 0,
136        Translation  => 1,
137        Sort         => 'NumericKey',
138        Class        => 'Modernize W75pc',
139    );
140
141    $LayoutObject->Block(
142        Name => 'TimeRange',
143        Data => {
144            TimeRange => $TimeRangeStrg,
145        },
146    );
147
148    # Get personal page shown count.
149    my $PageShownPreferencesKey = 'AdminCommunicationLogPageShown';
150    my $PageShown               = $Self->{$PageShownPreferencesKey} || 25;
151    my $Group                   = 'CommunicationLogPageShown';
152
153    # Prepare filters.
154    my %Filters = (
155        All => {
156            Name   => Translatable('All'),
157            Prio   => 1000,
158            Filter => 'All',
159            Search => {
160                OrderBy => $Param{OrderBy},
161                SortBy  => $Param{SortBy},
162            },
163        },
164        Successful => {
165            Name   => Translatable('Successful'),
166            Prio   => 1001,
167            Filter => 'Successful',
168            Search => {
169                OrderBy => $Param{OrderBy},
170                SortBy  => $Param{SortBy},
171                Status  => 'Successful',
172            },
173        },
174        Processing => {
175            Name   => Translatable('Processing'),
176            Prio   => 1002,
177            Filter => 'Processing',
178            Search => {
179                OrderBy => $Param{OrderBy},
180                SortBy  => $Param{SortBy},
181                Status  => 'Processing',
182            },
183        },
184        Failed => {
185            Name   => Translatable('Failed'),
186            Prio   => 1004,
187            Filter => 'Failed',
188            Search => {
189                OrderBy => $Param{OrderBy},
190                SortBy  => $Param{SortBy},
191                Status  => 'Failed',
192            },
193        },
194    );
195
196    if ( !$Filters{ $Param{Filter} } ) {
197        return $LayoutObject->FatalError(
198            Message => $LayoutObject->{LanguageObject}->Translate( 'Invalid Filter: %s!', $Param{Filter} ),
199        );
200    }
201
202    my $CommunicationLogDBObj = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB');
203
204    my @CommunicationData;
205    for my $Filter ( values %Filters ) {
206        my @Communications = @{
207            $CommunicationLogDBObj->CommunicationList(
208                StartDate => $Param{DateTime},
209                %{ $Filter->{Search} },
210                )
211                || []
212        };
213
214        $Filter->{Count} = scalar @Communications;
215
216        if ( $Filter->{Filter} eq $Param{Filter} ) {
217            @CommunicationData = @Communications;
218        }
219    }
220
221    $LayoutObject->Block(
222        Name => 'CommunicationNavBarFilter',
223        Data => {
224            %Param,
225        },
226    );
227
228    # Generate human readable average processing time.
229    my $AverageSeconds = $CommunicationLogDBObj->CommunicationList(
230        StartDate => $Param{DateTime},
231        Result    => 'AVERAGE',
232    );
233
234    my $AverageString = $AverageSeconds >= 1
235        ? $Self->_HumanReadableAverage( Seconds => $AverageSeconds )
236        : $LayoutObject->{LanguageObject}->Translate('Less than a second');
237
238    my %Accounts = $Self->_AccountStatus(
239        StartDate => $Param{DateTime},
240        %Param,
241    );
242
243    my %AccountsOverview = (
244        Failed     => 0,
245        Warning    => 0,
246        Successful => 0,
247    );
248
249    my $Status = '';
250
251    # Assume all accounts are working.
252    if (%Accounts) {
253        $Status = 'Successful';
254    }
255
256    ACCOUNTS:
257    for my $AccountKey ( sort keys %Accounts ) {
258
259        my ( $Failed, $Successful );
260        if ( $Accounts{$AccountKey}->{Failed} ) {
261            $Failed = 1;
262        }
263        if ( $Accounts{$AccountKey}->{Successful} ) {
264            $Successful = 1;
265        }
266
267        # Set global account status.
268        if ($Failed) {
269            $Status = 'Failed';
270            if ($Successful) {
271                $Status = 'Warning';
272            }
273        }
274
275        $AccountsOverview{$Status}++;
276    }
277
278    my $StatusFilter = 'Successful';
279    if ( $Filters{Failed}->{Count} ) {
280        $StatusFilter = 'Failed';
281    }
282
283    $LayoutObject->Block(
284        Name => 'StatusOverview',
285        Data => {
286            Successful       => $Filters{Successful}->{Count},
287            Processing       => $Filters{Processing}->{Count},
288            Failed           => $Filters{Failed}->{Count},
289            StatusFilter     => $StatusFilter,
290            StartTime        => $Param{StartTime} || 0,
291            TimeRange        => $LayoutObject->{LanguageObject}->Translate( $Param{TimeRanges}->{ $Param{StartTime} } ),
292            AverageString    => $AverageString,
293            AccountsStatus   => $Status,
294            AccountsOverview => \%AccountsOverview,
295        },
296    );
297
298    my $Total = scalar @CommunicationData;
299
300    # Get data selection.
301    my %Data;
302    my $Config = $Kernel::OM->Get('Kernel::Config')->Get('PreferencesGroups');
303    if ( $Config && $Config->{$Group} && $Config->{$Group}->{Data} ) {
304        %Data = %{ $Config->{$Group}->{Data} };
305    }
306
307    # Calculate max. shown per page.
308    if ( $Param{StartHit} > $Total ) {
309        my $Pages = int( ( $Total / $PageShown ) + 0.99999 );
310        $Param{StartHit} = ( ( $Pages - 1 ) * $PageShown ) + 1;
311    }
312
313    my $URLExtension = 'Expand=1;';
314
315    for my $URLPart (qw(Filter SortBy OrderBy StartTime)) {
316        $URLExtension .= "$URLPart=$Param{$URLPart};";
317    }
318
319    # Build nav bar.
320    my $Limit   = $Param{Limit} || 20_000;
321    my %PageNav = $LayoutObject->PageNavBar(
322        Limit     => $Limit,
323        StartHit  => $Param{StartHit},
324        PageShown => $PageShown,
325        AllHits   => $Total || 0,
326        Action    => 'Action=' . $LayoutObject->{Action},
327        Link      => $URLExtension,
328        IDPrefix  => $LayoutObject->{Action},
329    );
330
331    # Build shown dynamic fields per page.
332    $Param{RequestedURL} = "Action=$Self->{Action};$URLExtension";
333
334    for my $URLPart (qw(Filter SortBy OrderBy StartTime)) {
335        $Param{RequestedURL} .= ";$URLPart=$Param{$URLPart}";
336    }
337
338    $Param{Group}           = $Group;
339    $Param{PreferencesKey}  = $PageShownPreferencesKey;
340    $Param{PageShownString} = $LayoutObject->BuildSelection(
341        Name        => $PageShownPreferencesKey,
342        SelectedID  => $PageShown,
343        Translation => 0,
344        Data        => \%Data,
345        Sort        => 'NumericValue',
346        Class       => 'Modernize',
347    );
348
349    if (%PageNav) {
350        $LayoutObject->Block(
351            Name => 'OverviewNavBarPageNavBar',
352            Data => \%PageNav,
353        );
354
355        $LayoutObject->Block(
356            Name => 'ContextSettings',
357            Data => { %PageNav, %Param, },
358        );
359    }
360
361    for my $FilterItem ( sort { $a->{Prio} <=> $b->{Prio} } values %Filters ) {
362        $LayoutObject->Block(
363            Name => 'CommunicationNavBarFilterItem',
364            Data => {
365                %Param,
366                %{$FilterItem},
367                Selected => ( $FilterItem->{Filter} eq $Param{Filter} ) ? 1 : 0,
368            },
369        );
370    }
371
372    my @TableHeaders = (
373        {
374            HeaderName => Translatable('Status'),
375            SortByName => 'Status',
376            Class      => 'Status Center',
377        },
378        {
379            HeaderName => Translatable('Transport'),
380            SortByName => 'Transport',
381            Class      => 'Transport',
382        },
383        {
384            HeaderName => Translatable('Direction'),
385            SortByName => 'Direction',
386            Class      => 'Direction Center',
387        },
388        {
389            HeaderName => Translatable('Account'),
390            SortByName => 'Account',
391            Class      => 'Account',
392        },
393        {
394            HeaderName => Translatable('Start Time'),
395            SortByName => 'StartTime',
396            Class      => 'StartTime',
397        },
398        {
399            HeaderName => Translatable('End Time'),
400            SortByName => 'EndTime',
401            Class      => 'EndTime',
402        },
403        {
404            HeaderName => Translatable('Duration'),
405            SortByName => 'Duration',
406            Class      => 'Duration',
407        },
408    );
409
410    my $HeaderURL = 'Expand=1;';
411
412    for my $URLPart (qw(Filter StartTime)) {
413        $HeaderURL .= "$URLPart=$Param{$URLPart};";
414    }
415
416    for my $TableHeader (@TableHeaders) {
417
418        my $CSS             = $TableHeader->{Class};
419        my $TranslatedTitle = $LayoutObject->{LanguageObject}->Translate( $TableHeader->{HeaderName} );
420        my $OrderBy;
421
422        if ( $Param{SortBy} eq $TableHeader->{SortByName} ) {
423            if ( $Param{OrderBy} eq 'Up' ) {
424                $OrderBy = 'Down';
425                $CSS .= ' SortAscendingLarge';
426            }
427            else {
428                $OrderBy = 'Up';
429                $CSS .= ' SortDescendingLarge';
430            }
431
432            # Set title description.
433            my $TitleDesc = $OrderBy eq 'Up'
434                ? $LayoutObject->{LanguageObject}->Translate('sorted descending')
435                : $LayoutObject->{LanguageObject}->Translate('sorted ascending');
436            $TranslatedTitle .= ', ' . $TitleDesc;
437        }
438
439        $LayoutObject->Block(
440            Name => 'TableHeader',
441            Data => {
442                HeaderName => $TableHeader->{HeaderName},
443                SortByName => $TableHeader->{SortByName},
444                OrderBy    => $OrderBy,
445                CSS        => $CSS,
446                Title      => $TranslatedTitle,
447                HeaderLink => $HeaderURL,
448            },
449        );
450    }
451
452    # Prepare communication data.
453    if (@CommunicationData) {
454        my $Counter = 0;
455
456        for my $Communication (@CommunicationData) {
457            $Counter++;
458
459            if ( $Counter >= $Param{StartHit} && $Counter < ( $PageShown + $Param{StartHit} ) ) {
460                my $Account = '-';
461                if ( $Communication->{AccountID} ) {
462                    $Account = $CommunicationLogDBObj->CommunicationAccountLabelGet(
463                        AccountType => $Communication->{AccountType},
464                        AccountID   => $Communication->{AccountID},
465                        Transport   => $Communication->{Transport},
466                    );
467                }
468                elsif ( $Communication->{AccountType} ) {
469                    $Account = $Communication->{AccountType};
470                }
471
472                $LayoutObject->Block(
473                    Name => 'CommunicationRow',
474                    Data => {
475                        %{$Communication},
476                        DisplayAccount => $Account,
477                    },
478                );
479            }
480        }
481    }
482    else {
483        $LayoutObject->Block(
484            Name => 'NoCommunicationsFound',
485        );
486    }
487
488    $Output .= $LayoutObject->Output(
489        TemplateFile => 'AdminCommunicationLog',
490        Data         => {
491            %Param,
492            CommunicationCount => $Filters{All}->{Count},
493        },
494    );
495
496    $Output .= $LayoutObject->Footer();
497    return $Output;
498}
499
500sub _ZoomView {
501    my ( $Self, %Param ) = @_;
502
503    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
504
505    my $Output = $LayoutObject->Header();
506    $Output .= $LayoutObject->NavigationBar();
507
508    # Call all needed template blocks.
509    $LayoutObject->Block(
510        Name => 'Main',
511        Data => \%Param,
512    );
513
514    $LayoutObject->Block(
515        Name => 'Hint',
516        Data => \%Param,
517    );
518
519    my $CommunicationLogDBObj = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB');
520    my $Communication         = $Param{Communication};
521    my $CommunicationObjects  = $CommunicationLogDBObj->ObjectLogList(
522        CommunicationID => $Communication->{CommunicationID},
523    );
524
525    if ( !IsArrayRefWithData($CommunicationObjects) ) {
526        $LayoutObject->Block(
527            Name => 'NoCommunicationObjectsFound',
528        );
529    }
530
531    my $Direction = $Communication->{Direction};
532
533    for my $CommunicationObject ( @{$CommunicationObjects} ) {
534        $CommunicationObject->{Direction} = $Direction;
535
536        # Get account specific information.
537        if ( $Communication->{AccountType} && $Communication->{AccountID} ) {
538
539            $CommunicationObject->{AccountLabel} = $CommunicationLogDBObj->CommunicationAccountLabelGet(
540                AccountType => $Communication->{AccountType},
541                AccountID   => $Communication->{AccountID},
542                Transport   => $Communication->{Transport},
543            );
544            $CommunicationObject->{AccountLink} = $CommunicationLogDBObj->CommunicationAccountLinkGet(
545                AccountType => $Communication->{AccountType},
546                AccountID   => $Communication->{AccountID},
547                Transport   => $Communication->{Transport},
548            );
549            $CommunicationObject->{AccountType} = $Communication->{AccountType};
550        }
551        else {
552            $CommunicationObject->{AccountLabel} = $Communication->{AccountType};
553            $CommunicationObject->{AccountType}  = $Communication->{AccountType};
554        }
555
556        $LayoutObject->Block(
557            Name => 'CommunicationObjectRow',
558            Data => $CommunicationObject,
559        );
560    }
561
562    my $PriorityFilterStrg = $LayoutObject->BuildSelection(
563        Data => [
564            Translatable('Trace'),
565            Translatable('Debug'),
566            Translatable('Info'),
567            Translatable('Notice'),
568            Translatable('Warn'),
569            Translatable('Error'),
570        ],
571        Name         => 'PriorityFilter',
572        ID           => 'PriorityFilter',
573        SelectedID   => $Param{PriorityFilter} // 'Trace',
574        PossibleNone => 0,
575        Translation  => 1,
576        Class        => 'Modernize W75pc',
577    );
578
579    # Send CommunicationID to JS.
580    $LayoutObject->AddJSData(
581        Key   => 'CommunicationID',
582        Value => $Param{CommunicationID},
583    );
584
585    # Send ObjectLogID to JS.
586    $LayoutObject->AddJSData(
587        Key   => 'ObjectLogID',
588        Value => $Param{ObjectLogID},
589    );
590
591    $Output .= $LayoutObject->Output(
592        TemplateFile => 'AdminCommunicationLogZoom',
593        Data         => {
594            %Param,
595            ObjectCount      => scalar @{$CommunicationObjects},
596            PriorityFilter   => $PriorityFilterStrg,
597            CommunicationLog => $Communication,
598        },
599    );
600
601    $Output .= $LayoutObject->Footer();
602    return $Output;
603}
604
605sub _AccountsView {
606    my ( $Self, %Param ) = @_;
607
608    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
609
610    if ( $Param{Direct} && $Param{AccountID} ) {
611        $LayoutObject->AddJSData(
612            Key   => 'AccountID',
613            Value => $Param{AccountID},
614        );
615    }
616
617    my $Output = $LayoutObject->Header();
618    $Output .= $LayoutObject->NavigationBar();
619
620    my $TimeRangeStrg = $LayoutObject->BuildSelection(
621        Data         => $Param{TimeRanges},
622        Name         => 'TimeRangeAccounts',
623        ID           => 'TimeRangeAccounts',
624        SelectedID   => $Param{StartTime},
625        PossibleNone => 0,
626        Translation  => 1,
627        Sort         => 'NumericKey',
628        Class        => 'Modernize W75pc',
629    );
630
631    $LayoutObject->Block(
632        Name => 'TimeRange',
633        Data => {
634            TimeRange => $TimeRangeStrg,
635        },
636    );
637
638    my %Accounts = $Self->_AccountStatus(
639        StartDate => $Param{DateTime},
640        %Param,
641    );
642
643    my $CommunicationLogDBObj = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB');
644
645    if ( !scalar keys %Accounts ) {
646        $LayoutObject->Block(
647            Name => 'NoAccountsFound',
648        );
649    }
650    else {
651        for my $AccountKey ( sort keys %Accounts ) {
652
653            my $Account = $Accounts{$AccountKey};
654
655            my $AccountLabel = $Account->{AccountType} // '-';
656            my ( $AccountLink, $AverageSeconds );
657
658            if ( $Account->{AccountID} ) {
659                $AccountLabel = $CommunicationLogDBObj->CommunicationAccountLabelGet(
660                    AccountType => $Account->{AccountType},
661                    AccountID   => $Account->{AccountID},
662                    Transport   => $Account->{Transport},
663                );
664                $AccountLink = $CommunicationLogDBObj->CommunicationAccountLinkGet(
665                    AccountType => $Account->{AccountType},
666                    AccountID   => $Account->{AccountID},
667                    Transport   => $Account->{Transport},
668                );
669                $AverageSeconds = $CommunicationLogDBObj->CommunicationList(
670                    StartDate => $Param{DateTime},
671                    AccountID => $Account->{AccountID},
672                    Result    => 'AVERAGE',
673                );
674            }
675            else {
676                $AverageSeconds = $CommunicationLogDBObj->CommunicationList(
677                    StartDate   => $Param{DateTime},
678                    AccountType => $Account->{AccountType},
679                    Result      => 'AVERAGE',
680                );
681            }
682
683            # Generate human readable average processing time.
684            my $AverageString = $AverageSeconds >= 1
685                ? $Self->_HumanReadableAverage( Seconds => $AverageSeconds )
686                : $LayoutObject->{LanguageObject}->Translate('Less than a second');
687
688            my $HealthStatus = $Self->_CheckHealth($Account);
689
690            my $AccountErrorLink;
691            if ( $HealthStatus ne 'Successful' ) {
692                my $CommunicationID = $Account->{Failed}[0];
693                if ($CommunicationID) {
694                    $AccountErrorLink = "Subaction=Zoom;CommunicationID=$CommunicationID";
695                }
696            }
697
698            $LayoutObject->Block(
699                Name => 'AccountRow',
700                Data => {
701                    AccountLabel     => $AccountLabel,
702                    AccountLink      => $AccountLink,
703                    AccountStatus    => $HealthStatus,
704                    AccountErrorLink => $AccountErrorLink,
705                    AccountKey       => $AccountKey,
706                    AverageSeconds   => $AverageSeconds,
707                    AverageString    => $AverageString,
708                },
709            );
710
711        }
712    }
713
714    my $CommunicationLogCount = 0;
715
716    if ( $Param{Direct} ) {
717        $CommunicationLogCount = $Self->_GetCommunicationLog(%Param);
718    }
719    else {
720        $LayoutObject->Block(
721            Name => 'NoCommunicationLogsFound',
722        );
723    }
724
725    $Output .= $LayoutObject->Output(
726        TemplateFile => 'AdminCommunicationLogAccounts',
727        Data         => {
728            %Param,
729            CommunicationLogCount => $CommunicationLogCount,
730            TimeRange => $LayoutObject->{LanguageObject}->Translate( $Param{TimeRanges}->{ $Param{StartTime} } ),
731        },
732    );
733
734    $Output .= $LayoutObject->Footer();
735    return $Output;
736}
737
738sub _GetObjectLog {
739    my ( $Self, %Param ) = @_;
740
741    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
742
743    my $CommunicationLogDBObj   = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB');
744    my $CommunicationObjectLogs = $CommunicationLogDBObj->ObjectLogEntryList(
745        ObjectLogID => $Param{ObjectLogID},
746        OrderBy     => 'up',
747    );
748
749    if ( !IsArrayRefWithData($CommunicationObjectLogs) ) {
750        $LayoutObject->Block(
751            Name => 'NoObjectLogsFound',
752        );
753    }
754
755    for my $CommunicationObjectLog ( @{$CommunicationObjectLogs} ) {
756        $LayoutObject->Block(
757            Name => 'ObjectLogEntry',
758            Data => $CommunicationObjectLog,
759        );
760    }
761
762    my $Output = $LayoutObject->Output(
763        TemplateFile => 'AdminCommunicationLogObjectLog',
764        Data         => {
765            %Param,
766            ObjectLogCount => scalar @{$CommunicationObjectLogs},
767        },
768    );
769
770    return $LayoutObject->Attachment(
771        ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
772        Content     => $Output,
773        Type        => 'inline',
774        NoCache     => 1,
775    );
776}
777
778sub _GetCommunicationLog {
779    my ( $Self, %Param ) = @_;
780
781    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
782
783    # $Param{AccountID} can be like 'DoNotSendEmail' or 'IMAPS::1', for example.
784    my ( $AccountType, $AccountID ) = split '::', $Param{AccountID};
785
786    my $CommunicationLogDBObj   = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB');
787    my $CommunicationLogObjects = $CommunicationLogDBObj->ObjectLogList(
788        AccountID => $AccountID || $Param{AccountID},
789        StartDate => $Param{DateTime},
790    );
791
792    # Get personal page shown count.
793    my $PageShownPreferencesKey = 'AdminCommunicationLogPageShown';
794    my $PageShown               = $Self->{$PageShownPreferencesKey} || 25;
795    my $Group                   = 'CommunicationLogPageShown';
796
797    my %CommunicationIDs;
798    my $Counter = 0;
799
800    COMMUNICATIONLOGOBJECT:
801    for my $LogObject ( @{$CommunicationLogObjects} ) {
802
803        next COMMUNICATIONLOGOBJECT if $CommunicationIDs{ $LogObject->{CommunicationID} };
804
805        $Counter++;
806
807        if ( $Counter >= $Param{StartHit} && $Counter < ( $PageShown + $Param{StartHit} ) ) {
808
809            my %CommunicationLog = %{
810                $CommunicationLogDBObj->CommunicationGet(
811                    CommunicationID => $LogObject->{CommunicationID},
812                    )
813                    || {}
814            };
815
816            next COMMUNICATIONLOGOBJECT if $CommunicationLog{AccountType} ne $AccountType;
817
818            next COMMUNICATIONLOGOBJECT if $AccountID && $CommunicationLog{AccountID} ne $AccountID;
819
820            $CommunicationIDs{ $LogObject->{CommunicationID} } = 1;
821
822            $LayoutObject->Block(
823                Name => 'CommunicationLogRow',
824                Data => \%CommunicationLog,
825            );
826        }
827    }
828
829    if ( !%CommunicationIDs ) {
830        $LayoutObject->Block(
831            Name => 'NoCommunicationLogsFound',
832        );
833    }
834
835    return scalar keys %CommunicationIDs if $Param{Direct};
836
837    my $Total = scalar keys %CommunicationIDs;
838
839    # Get data selection.
840    my %Data;
841    my $Config = $Kernel::OM->Get('Kernel::Config')->Get('PreferencesGroups');
842    if ( $Config && $Config->{$Group} && $Config->{$Group}->{Data} ) {
843        %Data = %{ $Config->{$Group}->{Data} };
844    }
845
846    # Calculate max. shown per page.
847    if ( $Param{StartHit} > $Total ) {
848        my $Pages = int( ( $Total / $PageShown ) + 0.99999 );
849        $Param{StartHit} = ( ( $Pages - 1 ) * $PageShown ) + 1;
850    }
851
852    my $URLExtension = 'Direct=1;';
853
854    for my $URLPart (qw(SortBy OrderBy StartTime AccountID)) {
855        $URLExtension .= "$URLPart=$Param{$URLPart};";
856    }
857
858    # Build nav bar.
859    my $Limit   = $Param{Limit} || 20_000;
860    my %PageNav = $LayoutObject->PageNavBar(
861        Limit     => $Limit,
862        StartHit  => $Param{StartHit},
863        PageShown => $PageShown,
864        AllHits   => $Total || 0,
865        Action    => 'Action=' . $LayoutObject->{Action} . ';Subaction=Accounts',
866        Link      => $URLExtension,
867    );
868
869    # Build shown dynamic fields per page.
870    $Param{RequestedURL} = "Action=$Self->{Action};$URLExtension";
871
872    for my $URLPart (qw(SortBy OrderBy StartTime)) {
873        $Param{RequestedURL} .= ";$URLPart=$Param{$URLPart}";
874    }
875
876    $Param{Group}           = $Group;
877    $Param{PreferencesKey}  = $PageShownPreferencesKey;
878    $Param{PageShownString} = $LayoutObject->BuildSelection(
879        Name        => $PageShownPreferencesKey,
880        SelectedID  => $PageShown,
881        Translation => 0,
882        Data        => \%Data,
883    );
884
885    if (%PageNav) {
886        $LayoutObject->Block(
887            Name => 'OverviewNavBarPageNavBar',
888            Data => \%PageNav,
889        );
890    }
891
892    my $Output = $LayoutObject->Output(
893        TemplateFile => 'AdminCommunicationLogCommunications',
894        Data         => {
895            %Param,
896            CommunicationLogCount => scalar keys %CommunicationIDs,
897        },
898    );
899
900    return $LayoutObject->Attachment(
901        ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
902        Content     => $Output,
903        Type        => 'inline',
904        NoCache     => 1,
905    );
906}
907
908sub _HumanReadableAverage {
909    my ( $Self, %Param ) = @_;
910
911    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
912
913    my $DateTimeAverageStart = $Kernel::OM->Create('Kernel::System::DateTime');
914    my $DateTimeAverageStop  = $Kernel::OM->Create('Kernel::System::DateTime');
915
916    $DateTimeAverageStop->Add( Seconds => $Param{Seconds} );
917
918    my $AverageDelta = $DateTimeAverageStart->Delta( DateTimeObject => $DateTimeAverageStop );
919
920    my @HumanReadableUnits;
921
922    if ( $AverageDelta->{Days} ) {
923        push @HumanReadableUnits,
924            "$AverageDelta->{Days} " .
925            (
926            $AverageDelta->{Days} > 1
927            ? $LayoutObject->{LanguageObject}->Translate('days')
928            : $LayoutObject->{LanguageObject}->Translate('day')
929            );
930    }
931
932    if ( $AverageDelta->{Hours} ) {
933        push @HumanReadableUnits,
934            "$AverageDelta->{Hours} " .
935            (
936            $AverageDelta->{Hours} > 1
937            ? $LayoutObject->{LanguageObject}->Translate('hours')
938            : $LayoutObject->{LanguageObject}->Translate('hour')
939            );
940    }
941
942    if ( $AverageDelta->{Minutes} ) {
943        push @HumanReadableUnits,
944            "$AverageDelta->{Minutes} " .
945            (
946            $AverageDelta->{Minutes} > 1
947            ? $LayoutObject->{LanguageObject}->Translate('minutes')
948            : $LayoutObject->{LanguageObject}->Translate('minute')
949            );
950    }
951
952    if ( $AverageDelta->{Seconds} ) {
953        push @HumanReadableUnits,
954            "$AverageDelta->{Seconds} " .
955            (
956            $AverageDelta->{Seconds} > 1
957            ? $LayoutObject->{LanguageObject}->Translate('seconds')
958            : $LayoutObject->{LanguageObject}->Translate('second')
959            );
960    }
961
962    return if !@HumanReadableUnits;
963
964    return join ', ', @HumanReadableUnits;
965}
966
967sub _AccountStatus {
968    my ( $Self, %Param ) = @_;
969
970    my %Filter = (
971        ObjectLogStartDate => $Param{StartDate},
972    );
973
974    if ( $Param{Status} ) {
975        $Filter{ObjectLogStatus} = $Param{Status};
976    }
977
978    my $CommunicationLogDBObj = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB');
979    my $Connections           = $CommunicationLogDBObj->GetConnectionsObjectsAndCommunications(%Filter);
980    if ( !$Connections || !@{$Connections} ) {
981        return;
982    }
983
984    my %Account;
985    for my $Connection (@$Connections) {
986
987        my $AccountKey = $Connection->{AccountType};
988        if ( $Connection->{AccountID} ) {
989            $AccountKey .= "::$Connection->{AccountID}";
990        }
991
992        if ( !$Account{$AccountKey} ) {
993            $Account{$AccountKey} = {
994                AccountID   => $Connection->{AccountID},
995                AccountType => $Connection->{AccountType},
996                Transport   => $Connection->{Transport},
997            };
998        }
999
1000        $Account{$AccountKey}->{ $Connection->{ObjectLogStatus} } ||= [];
1001
1002        push @{ $Account{$AccountKey}->{ $Connection->{ObjectLogStatus} } },
1003            $Connection->{CommunicationID};
1004    }
1005
1006    for my $AccountKey ( sort keys %Account ) {
1007        $Account{$AccountKey}->{Status} =
1008            $Self->_CheckHealth( $Account{$AccountKey} );
1009    }
1010
1011    return %Account;
1012
1013}
1014
1015sub _CheckHealth {
1016    my ( $Self, $Connections ) = @_;
1017
1018    # Success if all is Successful;
1019    # Failed if all is Failed;
1020    # Warning if has both Successful and Failed Connections;
1021
1022    my $Health = 'Success';
1023
1024    if ( scalar $Connections->{Failed} ) {
1025        $Health = 'Failed';
1026        if ( scalar $Connections->{Successful} ) {
1027            $Health = 'Warning';
1028        }
1029    }
1030
1031    return $Health;
1032
1033}
1034
10351;
1036