1# -- 2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/ 3# -- 4# This software comes with ABSOLUTELY NO WARRANTY. For details, see 5# the enclosed file COPYING for license information (GPL). If you 6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. 7# -- 8 9package Kernel::System::CommunicationLog; 10 11use strict; 12use warnings; 13 14use Kernel::System::VariableCheck qw(:all); 15 16our %ObjectManagerFlags = ( 17 NonSingleton => 1, 18 AllowConstructorFailure => 1, 19); 20 21our @ObjectDependencies = ( 22 'Kernel::Config', 23 'Kernel::System::Log', 24 'Kernel::System::CommunicationLog::DB', 25 'Kernel::System::DB', 26 'Kernel::System::DateTime', 27 'Kernel::System::Main', 28); 29 30=head1 PUBLIC INTERFACE 31 32=head2 new() 33 34Creates a CommunicationLog object. Do not use new() directly, instead use the object manager. 35This is a class which represents a complete communication. Therefore the created 36instances must not be shared between processes of different communications. 37 38Please use the object manager as follows for this class: 39 40 # Create an object, representing a new communication: 41 my $CommunicationLogObject = $Kernel::OM->Create( 42 'Kernel::System::CommunicationLog', 43 ObjectParams => { 44 Transport => 'Email', 45 Direction => 'Incoming', 46 } 47 ); 48 49 # Create an object for an already existing communication: 50 my $CommunicationLogObject = $Kernel::OM->Create( 51 'Kernel::System::CommunicationLog', 52 ObjectParams => { 53 CommunicationID => 123, 54 } 55 ); 56 57=cut 58 59sub new { 60 my ( $Type, %Param ) = @_; 61 62 # allocate new hash for object 63 my $Self = {}; 64 bless( $Self, $Type ); 65 66 if ( IsStringWithData( $Param{CommunicationID} ) || IsStringWithData( $Param{ObjectLogID} ) ) { 67 return $Self->_RecoverCommunicationObject(%Param); 68 } 69 70 return $Self->_CommunicationStart(%Param); 71} 72 73=head2 CommunicationStop() 74 75Update the status of a communication entry. 76 77 my $Success = $CommunicationLogObject->CommunicationStop( 78 Status => 'Successful', # (required) Needs to be either 'Successful', 'Warning' or 'Failed' 79 ); 80 81Returns: 82 83 1 in case of success, 0 in case of errors 84 85=cut 86 87sub CommunicationStop { 88 my ( $Self, %Param ) = @_; 89 90 # close open object types before 91 for my $ObjectType ( sort keys %{ $Self->{Object} } ) { 92 return if !$Self->ObjectLogStop( ObjectType => $ObjectType ); 93 } 94 95 my $CommunicationDBObject = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB'); 96 97 my $Result = $CommunicationDBObject->CommunicationUpdate( 98 CommunicationID => $Self->{CommunicationID}, 99 Status => $Param{Status}, 100 ); 101 102 # Remember status 103 $Self->{Status} = $Param{Status}; 104 105 return 1; 106} 107 108=head2 CommunicationIDGet() 109 110Returns the communication id. 111 112 my $CommunicationID = $CommunicationLogObject->CommunicationIDGet(); 113 114Returns: 115 116 The communication id of the current communication represented by this object. 117 118=cut 119 120sub CommunicationIDGet { 121 my ( $Self, %Param ) = @_; 122 123 return $Self->{CommunicationID}; 124} 125 126=head2 TransportGet() 127 128Returns the used transport. 129 130 my $Transport = $CommunicationLogObject->TransportGet(); 131 132Returns: 133 134 The transport of the current communication represented by this object. 135 136=cut 137 138sub TransportGet { 139 my ( $Self, %Param ) = @_; 140 141 return $Self->{Transport}; 142} 143 144=head2 DirectionGet() 145 146Returns the used direction. 147 148 my $Direction = $CommunicationLogObject->DirectionGet(); 149 150Returns: 151 152 The direction of the current communication represented by this object. 153 154=cut 155 156sub DirectionGet { 157 my ( $Self, %Param ) = @_; 158 159 return $Self->{Direction}; 160} 161 162=head2 StatusGet() 163 164Returns the current Status. 165 166 my $Direction = $CommunicationLogObject->StatusGet(); 167 168Returns: 169 170 The status of the current communication represented by this object. 171 172=cut 173 174sub StatusGet { 175 my ( $Self, %Param ) = @_; 176 177 return $Self->{Status}; 178} 179 180=head2 ObjectLogStart() 181 182Starts a log object of a given object type. 183 184 my $ObjectID = $CommunicationLogObject->ObjectLogStart( 185 ObjectType => 'Connection' # (required) Can be 'Connection' or 'Message' 186 ); 187 188Returns: 189 190 1 in case of success, 0 in case of errors 191 192=cut 193 194sub ObjectLogStart { 195 my ( $Self, %Param ) = @_; 196 197 if ( $Self->{Current}->{ $Param{ObjectLogType} } ) { 198 return $Self->_LogError("Object already has an open Log for this type."); 199 } 200 201 my $CommunicationDBObject = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB'); 202 203 my $ObjectLogID = $CommunicationDBObject->ObjectLogCreate( 204 CommunicationID => $Self->{CommunicationID}, 205 %Param 206 ); 207 208 return if !$ObjectLogID; 209 210 $Self->{Current}->{ $Param{ObjectLogType} } = $ObjectLogID; 211 212 return $ObjectLogID; 213} 214 215=head2 ObjectLogStop() 216 217Stops a log object of a given object type. 218 219 my $Success = $CommunicationLogObject->ObjectLogStop( 220 ObjectLogType => 'Connection' # (required) Can be 'Connection' or 'Message' 221 ObjectLogID => 123, # (required) The ObjectID of the started object type 222 ); 223 224Returns: 225 226 1 in case of success, 0 in case of errors 227 228=cut 229 230sub ObjectLogStop { 231 my ( $Self, %Param ) = @_; 232 233 if ( !$Param{ObjectLogType} ) { 234 return $Self->_LogError("Need ObjectLogType."); 235 } 236 237 if ( !$Self->{Current}->{ $Param{ObjectLogType} } ) { 238 return $Self->_LogError("Cannot stop a ObjectLog that is not open."); 239 } 240 241 my $CommunicationDBObject = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB'); 242 243 my $Result = $CommunicationDBObject->ObjectLogUpdate( 244 CommunicationID => $Self->{CommunicationID}, 245 ObjectLogID => $Self->{Current}->{ $Param{ObjectLogType} }, 246 ObjectLogType => $Param{ObjectLogType}, 247 Status => $Param{Status}, 248 ); 249 250 if ( !$Result ) { 251 return $Self->_LogError("Could not stop object log."); 252 } 253 254 delete $Self->{Current}->{ $Param{ObjectLogType} }; 255 256 return 1; 257} 258 259=head2 ObjectLog() 260 261Adds a log entry for a certain log object. 262 263 my $Success = $CommunicationLogObject->ObjectLog( 264 ObjectLogType => '...' # (required) To be defined by the related LogObject 265 ObjectLogID => 123, # (required) The ObjectID of the started object type 266 ); 267 268Returns: 269 270 1 in case of success, 0 in case of errors 271 272=cut 273 274sub ObjectLog { 275 my ( $Self, %Param ) = @_; 276 277 if ( !$Param{ObjectLogType} ) { 278 return $Self->_LogError("Need ObjectLogType."); 279 } 280 281 my $ObjectLogID = $Self->{Current}->{ $Param{ObjectLogType} }; 282 if ( !$ObjectLogID ) { 283 return $Self->_LogError("Object Log needs to have an open Log Type."); 284 } 285 286 $Param{Priority} //= 'Info'; 287 288 # In case of error also add it to the system log. 289 if ( $Param{Priority} eq 'Error' ) { 290 my @Identification = ( 291 'ID:' . $Self->CommunicationIDGet(), 292 'AccountType:' . ( $Self->{AccountType} || '-' ), 293 'AccountID:' . ( $Self->{AccountID} || '-' ), 294 'Direction:' . $Self->{Direction}, 295 'Transport:' . $Self->{Transport}, 296 'ObjectLogType:' . $Param{ObjectLogType}, 297 'ObjectLogID:' . $ObjectLogID, 298 ); 299 300 $Self->_LogError( 301 sprintf( 302 'CommunicationLog(%s)' . '::%s => %s', 303 join( ',', @Identification, ), 304 $Param{Key}, 305 $Param{Value}, 306 ), 307 ); 308 } 309 310 my $CommunicationDBObject = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB'); 311 312 return $CommunicationDBObject->ObjectLogEntryCreate( 313 CommunicationID => $Self->{CommunicationID}, 314 ObjectLogID => $ObjectLogID, 315 Key => $Param{Key}, 316 Value => $Param{Value}, 317 Priority => $Param{Priority}, 318 ); 319} 320 321=head2 ObjectLookupSet() 322 323Inserts or updates a lookup information. 324 325 my $Result = $CommunicationLogObject->ObjectLookupSet( 326 ObjectID => 123, # (required) 327 TargetObjectType => 'Article', # (required) 328 TargetObjectID => 123, # (required) 329 ); 330 331Returns: 332 333 <undef> - if any error occur 334 1 - in case of success 335 336=cut 337 338sub ObjectLookupSet { 339 my ( $Self, %Param ) = @_; 340 341 if ( !$Param{ObjectLogType} ) { 342 return $Self->_LogError("Need ObjectLogType."); 343 } 344 345 if ( !$Self->{Current}->{ $Param{ObjectLogType} } ) { 346 return $Self->_LogError("Cannot set a ObjectLog that is not open."); 347 } 348 349 my $CommunicationDBObject = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB'); 350 351 return $CommunicationDBObject->ObjectLookupSet( 352 ObjectLogID => $Self->{Current}->{ $Param{ObjectLogType} }, 353 TargetObjectType => $Param{TargetObjectType}, 354 TargetObjectID => $Param{TargetObjectID}, 355 ); 356} 357 358=head2 ObjectLookupGet() 359 360Gets the object lookup information. 361 362 my $Result = $CommunicationLogObject->ObjectLookupGet( 363 TargetObjectID => '...', 364 TargetObjectType => '...', 365 ); 366 367Returns: 368 369 <undef> - if any error occur 370 An hashref with object lookup information - in case info exists 371 An empty hasref - in case info doesn't exists 372 373=cut 374 375sub ObjectLookupGet { 376 my ( $Self, %Param ) = @_; 377 378 my $CommunicationDBObject = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB'); 379 380 return $CommunicationDBObject->ObjectLookupGet(%Param); 381} 382 383=head2 IsObjectLogOpen() 384 385Checks if a given ObjectLogType has an open Object or not. 386 387 my $Result = $CommunicationLogObject->IsObjectLogOpen( 388 ObjectLogType => '...', # Required 389 ); 390 391Returns: 392 393 The ObjectLogID or undef. 394 395=cut 396 397sub IsObjectLogOpen { 398 my ( $Self, %Param ) = @_; 399 400 if ( !$Param{ObjectLogType} ) { 401 return $Self->_LogError("Need ObjectLogType."); 402 } 403 404 return $Self->{Current}->{ $Param{ObjectLogType} }; 405} 406 407=head2 PRIVATE INTERFACE 408 409Private methods 410 411=cut 412 413=head2 _CommunicationStart() 414 415Create a new communication entry. 416 417 my $Success = $CommunicationLogObject->CommunicationStart( 418 Status => 'Processing', # (optional) Needs to be either 'Successful', 'Processing', 'Warning' or 'Failed' 419 # In most of the cases, just 'Processing' will make sense at the very beginning 420 # of a communication (Default: 'Processing'). 421 AccountType => # (optional) The used account type 422 AccountID => # (optional) The used account id 423 ); 424 425Returns: 426 427 1 in case of success, 0 in case of errors 428 429=cut 430 431sub _CommunicationStart { 432 my ( $Self, %Param ) = @_; 433 434 if ( $Self->{CommunicationID} ) { 435 $Kernel::OM->Get('Kernel::System::Log')->Log( 436 Priority => 'debug', 437 Message => "Communication with id '$Self->{CommunicationID}' is already started!", 438 ); 439 return $Self; 440 } 441 442 $Self->{Transport} = $Param{Transport}; 443 $Self->{Direction} = $Param{Direction}; 444 $Self->{Status} = $Param{Status} || 'Processing'; 445 446 my $CommunicationDBObject = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB'); 447 448 my $CommunicationID = $CommunicationDBObject->CommunicationCreate( 449 Direction => $Self->{Direction}, 450 Transport => $Self->{Transport}, 451 Status => $Self->{Status}, 452 AccountType => $Param{AccountType}, 453 AccountID => $Param{AccountID}, 454 ); 455 456 # return if there is not article created 457 if ( !$CommunicationID ) { 458 return $Self->_LogError("Can't get CommunicationID from communication start!"); 459 } 460 461 # remember the new communication id 462 $Self->{CommunicationID} = $CommunicationID; 463 464 return $Self; 465} 466 467=head2 _RecoverCommunciationObject() 468 469Recover a Communication object given an CommunicationID or ObjectLogID. 470 471=cut 472 473sub _RecoverCommunicationObject { 474 my ( $Self, %Param ) = @_; 475 476 my $CommunicationDBObject = $Kernel::OM->Get('Kernel::System::CommunicationLog::DB'); 477 my $CommunicationData = {}; 478 my $ErrorMessage = "Could not restore the communication with %s '%s'!"; 479 480 if ( $Param{CommunicationID} ) { 481 $ErrorMessage = sprintf $ErrorMessage, 'CommunicationID', $Param{CommunicationID}; 482 $CommunicationData = $CommunicationDBObject->CommunicationGet( 483 CommunicationID => $Param{CommunicationID}, 484 ); 485 } 486 else { 487 $ErrorMessage = sprintf $ErrorMessage, 'ObjectLogID', $Param{ObjectLogID}; 488 489 $CommunicationData = $CommunicationDBObject->CommunicationGetByObjectLogID( 490 ObjectLogID => $Param{ObjectLogID}, 491 ); 492 } 493 494 if ( !$CommunicationData || !%{$CommunicationData} ) { 495 return $Self->_LogError($ErrorMessage); 496 } 497 498 if ( $CommunicationData->{Status} ne 'Processing' ) { 499 return $Self->_LogError( 500 sprintf( 501 "The communication '%s' is already closed, can't be used.", 502 $CommunicationData->{CommunicationID}, 503 ), 504 ); 505 } 506 507 $Self->{CommunicationID} = $CommunicationData->{CommunicationID}; 508 $Self->{Transport} = $CommunicationData->{Transport}; 509 $Self->{Direction} = $CommunicationData->{Direction}; 510 $Self->{Status} = $CommunicationData->{Status}; 511 512 # Recover open objects. 513 my $Objects = $CommunicationDBObject->ObjectLogList( 514 CommunicationID => $CommunicationData->{CommunicationID}, 515 ObjectLogStatus => 'Processing', 516 ); 517 518 if ( !$Objects ) { 519 return $Self->_LogError( $ErrorMessage, ); 520 } 521 522 for my $Object ( @{$Objects} ) { 523 $Self->{Current}->{ $Object->{ObjectLogType} } = $Object->{ObjectLogID}; 524 } 525 526 return $Self; 527} 528 529=head2 _LogError() 530 531Helper Method for logging. 532 533=cut 534 535sub _LogError { 536 my ( $Self, $Message ) = @_; 537 538 $Kernel::OM->Get('Kernel::System::Log')->Log( 539 Priority => 'error', 540 Message => $Message, 541 ); 542 return; 543} 544 545=head1 TERMS AND CONDITIONS 546 547This software is part of the OTRS project (L<https://otrs.org/>). 548 549This software comes with ABSOLUTELY NO WARRANTY. For details, see 550the enclosed file COPYING for license information (GPL). If you 551did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>. 552 553=cut 554 5551; 556