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