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::AdminGenericInterfaceDebugger;
10
11use strict;
12use warnings;
13
14use utf8;
15
16use Kernel::System::VariableCheck qw(:all);
17use Kernel::Language qw(Translatable);
18
19our $ObjectManagerDisabled = 1;
20
21sub new {
22    my ( $Type, %Param ) = @_;
23
24    my $Self = {%Param};
25    bless( $Self, $Type );
26
27    return $Self;
28}
29
30sub Run {
31    my ( $Self, %Param ) = @_;
32
33    my $WebserviceID = $Kernel::OM->Get('Kernel::System::Web::Request')->GetParam( Param => 'WebserviceID' );
34
35    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
36
37    if ( !$WebserviceID ) {
38        return $LayoutObject->ErrorScreen(
39            Message => Translatable('Need WebserviceID!'),
40        );
41    }
42
43    my $WebserviceData = $Kernel::OM->Get('Kernel::System::GenericInterface::Webservice')->WebserviceGet(
44        ID => $WebserviceID,
45    );
46
47    if ( !IsHashRefWithData($WebserviceData) ) {
48        return $LayoutObject->ErrorScreen(
49            Message =>
50                $LayoutObject->{LanguageObject}->Translate( 'Could not get data for WebserviceID %s', $WebserviceID ),
51        );
52    }
53
54    # Send value to JS.
55    $LayoutObject->AddJSData(
56        Key   => 'WebserviceID',
57        Value => $WebserviceID,
58    );
59
60    if ( $Self->{Subaction} eq 'GetRequestList' ) {
61        return $Self->_GetRequestList(
62            %Param,
63            WebserviceID   => $WebserviceID,
64            WebserviceData => $WebserviceData,
65        );
66    }
67    elsif ( $Self->{Subaction} eq 'GetCommunicationDetails' ) {
68        return $Self->_GetCommunicationDetails(
69            %Param,
70            WebserviceID   => $WebserviceID,
71            WebserviceData => $WebserviceData,
72        );
73    }
74    elsif ( $Self->{Subaction} eq 'ClearDebugLog' ) {
75        return $Self->_ClearDebugLog(
76            %Param,
77            WebserviceID   => $WebserviceID,
78            WebserviceData => $WebserviceData,
79        );
80    }
81
82    # Default: show start screen.
83    return $Self->_ShowScreen(
84        %Param,
85        WebserviceID   => $WebserviceID,
86        WebserviceData => $WebserviceData,
87    );
88}
89
90sub _ShowScreen {
91    my ( $Self, %Param ) = @_;
92
93    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
94
95    my $Output = $LayoutObject->Header();
96    $Output .= $LayoutObject->NavigationBar();
97
98    my $FilterLimitStrg = $LayoutObject->BuildSelection(
99        Data => [
100            '10',
101            '25',
102            '50',
103            '100',
104            '250',
105            '500',
106            '1000',
107            '10000',
108        ],
109        Name          => 'FilterLimit',
110        SelectedValue => '10',
111        Translate     => 0,
112        Class         => 'Modernize',
113    );
114
115    my $FilterSortStrg = $LayoutObject->BuildSelection(
116        Data => {
117            'ASC'  => Translatable('ascending'),
118            'DESC' => Translatable('descending'),
119        },
120        Name         => 'FilterSort',
121        PossibleNone => 0,
122        SelectedID   => 'DESC',
123        Translate    => 0,
124        Class        => 'Modernize',
125    );
126
127    my $FilterTypeStrg = $LayoutObject->BuildSelection(
128        Data => [
129            'Provider',
130            'Requester',
131        ],
132        Name         => 'FilterType',
133        PossibleNone => 1,
134        Translate    => 0,
135        Class        => 'Modernize',
136    );
137
138    my $FilterFromStrg = $LayoutObject->BuildDateSelection(
139        Prefix   => 'FilterFrom',
140        DiffTime => -60 * 60 * 24 * 356,
141    );
142
143    my $FilterToStrg = $LayoutObject->BuildDateSelection(
144        Prefix => 'FilterTo',
145    );
146
147    $Output .= $LayoutObject->Output(
148        TemplateFile => 'AdminGenericInterfaceDebugger',
149        Data         => {
150            %Param,
151            WebserviceName  => $Param{WebserviceData}->{Name},
152            FilterLimitStrg => $FilterLimitStrg,
153            FilterSortStrg  => $FilterSortStrg,
154            FilterTypeStrg  => $FilterTypeStrg,
155            FilterFromStrg  => $FilterFromStrg,
156            FilterToStrg    => $FilterToStrg,
157        },
158    );
159
160    $Output .= $LayoutObject->Footer();
161    return $Output;
162}
163
164sub _GetRequestList {
165    my ( $Self, %Param ) = @_;
166
167    my %LogSearchParam = (
168        WebserviceID => $Param{WebserviceID},
169    );
170
171    my $ParamObject  = $Kernel::OM->Get('Kernel::System::Web::Request');
172    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
173
174    my $FilterType = $ParamObject->GetParam( Param => 'FilterType' );
175    $LogSearchParam{CommunicationType} = $FilterType if ($FilterType);
176
177    my $FilterRemoteIP = $ParamObject->GetParam( Param => 'FilterRemoteIP' );
178
179    if ( $FilterRemoteIP && IsIPv4Address($FilterRemoteIP) ) {
180        $LogSearchParam{RemoteIP} = $FilterRemoteIP;
181    }
182
183    $LogSearchParam{CreatedAtOrAfter}  = $ParamObject->GetParam( Param => 'FilterFrom' );
184    $LogSearchParam{CreatedAtOrBefore} = $ParamObject->GetParam( Param => 'FilterTo' );
185    $LogSearchParam{Limit}             = $ParamObject->GetParam( Param => 'FilterLimit' ) || 10;
186    $LogSearchParam{Sort}              = $ParamObject->GetParam( Param => 'FilterSort' ) || 'DESC';
187
188    my $LogData = $Kernel::OM->Get('Kernel::System::GenericInterface::DebugLog')->LogSearch(%LogSearchParam);
189
190    # Get current user time zone.
191    my $TimeZone = $Self->{UserTimeZone} || $Kernel::OM->Create('Kernel::System::DateTime')->UserDefaultTimeZoneGet();
192
193    # Set date time format and values for 'Time' column.
194    for my $Log ( @{$LogData} ) {
195        my $DateTimeObject = $Kernel::OM->Create(
196            'Kernel::System::DateTime',
197            ObjectParams => {
198                String => $Log->{Created},
199            },
200        );
201
202        $DateTimeObject->ToTimeZone(
203            TimeZone => $TimeZone,
204        );
205
206        $Log->{Created} = $LayoutObject->{LanguageObject}->FormatTimeString(
207            $Log->{Created},
208            'DateFormat',
209        );
210    }
211
212    # Fail gracefully.
213    $LogData ||= [];
214
215    # Build JSON output.
216    my $JSON = $LayoutObject->JSONEncode(
217        Data => {
218            LogData => $LogData,
219        },
220    );
221
222    # Send JSON response.
223    return $LayoutObject->Attachment(
224        ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
225        Content     => $JSON,
226        Type        => 'inline',
227        NoCache     => 1,
228    );
229}
230
231sub _GetCommunicationDetails {
232    my ( $Self, %Param ) = @_;
233
234    my $CommunicationID = $Kernel::OM->Get('Kernel::System::Web::Request')->GetParam( Param => 'CommunicationID' );
235
236    if ( !$CommunicationID ) {
237        $Kernel::OM->Get('Kernel::System::Log')->Log(
238            Priority => 'error',
239            Message  => 'Got no CommunicationID',
240        );
241
242        return;    # return empty response
243    }
244
245    my $LogData = $Kernel::OM->Get('Kernel::System::GenericInterface::DebugLog')->LogGetWithData(
246        CommunicationID => $CommunicationID,
247    );
248
249    # Get current user time zone.
250    my $TimeZone = $Self->{UserTimeZone} || $Kernel::OM->Create('Kernel::System::DateTime')->UserDefaultTimeZoneGet();
251
252    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
253
254    # Duplicate widgets containing xml data and format the new version for better readability.
255    if ( IsArrayRefWithData( $LogData->{Data} ) ) {
256        $Kernel::OM->Get('Kernel::System::Main')->Require('XML::LibXML');
257        my $XML = XML::LibXML->new();
258
259        INDEX:
260        for my $Index ( 0 .. scalar( @{ $LogData->{Data} } ) + 1 ) {
261
262            my $Data = $LogData->{Data}->[$Index]->{Data};
263
264            # remove entries with empty data hashes before JSON encoding
265            if ( !IsHashRefWithData( $LogData->{Data}->[$Index] ) ) {
266                delete $LogData->{Data}->[$Index];
267                next INDEX;
268            }
269
270            # Set date time format and values for created log time.
271            my $CreatedTime = $LogData->{Data}->[$Index]->{Created};
272            if ( $LogData->{Data}->[$Index]->{Created} ) {
273                my $DateTimeObject = $Kernel::OM->Create(
274                    'Kernel::System::DateTime',
275                    ObjectParams => {
276                        String => $LogData->{Data}->[$Index]->{Created},
277                    },
278                );
279
280                $DateTimeObject->ToTimeZone(
281                    TimeZone => $TimeZone,
282                );
283
284                $LogData->{Data}->[$Index]->{Created} = $LayoutObject->{LanguageObject}->FormatTimeString(
285                    $LogData->{Data}->[$Index]->{Created},
286                    'DateFormat',
287                );
288            }
289
290            next INDEX if !IsStringWithData($Data);
291            next INDEX if substr( $Data, 0, 5 ) ne '<?xml';
292
293            # Safely attempt to format xml.
294            my $LintedXML;
295            eval {
296                $LintedXML = $XML->parse_string($Data)->serialize(1);
297            };
298
299            next INDEX if !$LintedXML;
300
301            # Prevent double encoding of utf8 data.
302            utf8::decode($LintedXML);
303
304            next INDEX if $LintedXML eq $Data;
305
306            # If formatted xml differs from original version, add it to data.
307            splice @{ $LogData->{Data} }, $Index + 1, 0, {
308                Created    => $CreatedTime,
309                Data       => $LintedXML,
310                DebugLevel => $LogData->{Data}->[$Index]->{DebugLevel},
311                Summary    => $LogData->{Data}->[$Index]->{Summary}
312                    . ' (auto-formatted XML, not part of original transmission)',
313            };
314        }
315    }
316
317    # Build JSON output.
318    my $JSON = $LayoutObject->JSONEncode(
319        Data => {
320            LogData => $LogData,
321        },
322    );
323
324    # Send JSON response.
325    return $LayoutObject->Attachment(
326        ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
327        Content     => $JSON,
328        Type        => 'inline',
329        NoCache     => 1,
330    );
331}
332
333sub _ClearDebugLog {
334    my ( $Self, %Param ) = @_;
335
336    my $Success = $Kernel::OM->Get('Kernel::System::GenericInterface::DebugLog')->LogDelete(
337        WebserviceID => $Param{WebserviceID},
338    );
339
340    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
341
342    # Build JSON output.
343    my $JSON = $LayoutObject->JSONEncode(
344        Data => {
345            Success => $Success,
346        },
347    );
348
349    # Send JSON response.
350    return $LayoutObject->Attachment(
351        ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
352        Content     => $JSON,
353        Type        => 'inline',
354        NoCache     => 1,
355    );
356}
357
3581;
359