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