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::CustomerTicketMessage;
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    # allocate new hash for object
23    my $Self = {%Param};
24    bless( $Self, $Type );
25
26    # get form id
27    $Self->{FormID} = $Kernel::OM->Get('Kernel::System::Web::Request')->GetParam( Param => 'FormID' );
28
29    # create form id
30    if ( !$Self->{FormID} ) {
31        $Self->{FormID} = $Kernel::OM->Get('Kernel::System::Web::UploadCache')->FormIDCreate();
32    }
33
34    return $Self;
35}
36
37sub Run {
38    my ( $Self, %Param ) = @_;
39
40    # get params
41    my %GetParam;
42    my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
43    for my $Key (qw( Subject Body PriorityID TypeID ServiceID SLAID Expand Dest FromChatID)) {
44        $GetParam{$Key} = $ParamObject->GetParam( Param => $Key );
45    }
46
47    # ACL compatibility translation
48    my %ACLCompatGetParam;
49    $ACLCompatGetParam{OwnerID} = $GetParam{NewUserID};
50
51    # get Dynamic fields from ParamObject
52    my %DynamicFieldValues;
53
54    my $Config = $Kernel::OM->Get('Kernel::Config')->Get("Ticket::Frontend::$Self->{Action}");
55
56    # get the dynamic fields for this screen
57    my $DynamicField = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
58        Valid       => 1,
59        ObjectType  => [ 'Ticket', 'Article' ],
60        FieldFilter => $Config->{DynamicField} || {},
61    );
62
63    my $LayoutObject  = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
64    my $BackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
65
66    # reduce the dynamic fields to only the ones that are designed for customer interface
67    my @CustomerDynamicFields;
68    DYNAMICFIELD:
69    for my $DynamicFieldConfig ( @{$DynamicField} ) {
70        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
71
72        my $IsCustomerInterfaceCapable = $BackendObject->HasBehavior(
73            DynamicFieldConfig => $DynamicFieldConfig,
74            Behavior           => 'IsCustomerInterfaceCapable',
75        );
76        next DYNAMICFIELD if !$IsCustomerInterfaceCapable;
77
78        push @CustomerDynamicFields, $DynamicFieldConfig;
79    }
80    $DynamicField = \@CustomerDynamicFields;
81
82    # cycle trough the activated Dynamic Fields for this screen
83    DYNAMICFIELD:
84    for my $DynamicFieldConfig ( @{$DynamicField} ) {
85        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
86
87        # extract the dynamic field value from the web request
88        $DynamicFieldValues{ $DynamicFieldConfig->{Name} } =
89            $BackendObject->EditFieldValueGet(
90            DynamicFieldConfig => $DynamicFieldConfig,
91            ParamObject        => $ParamObject,
92            LayoutObject       => $LayoutObject,
93            );
94    }
95
96    # convert dynamic field values into a structure for ACLs
97    my %DynamicFieldACLParameters;
98    DYNAMICFIELD:
99    for my $DynamicField ( sort keys %DynamicFieldValues ) {
100        next DYNAMICFIELD if !$DynamicField;
101        next DYNAMICFIELD if !$DynamicFieldValues{$DynamicField};
102
103        $DynamicFieldACLParameters{ 'DynamicField_' . $DynamicField } = $DynamicFieldValues{$DynamicField};
104    }
105    $GetParam{DynamicField} = \%DynamicFieldACLParameters;
106
107    my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket');
108    my $QueueObject  = $Kernel::OM->Get('Kernel::System::Queue');
109    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
110
111    if ( $GetParam{FromChatID} ) {
112        if ( !$ConfigObject->Get('ChatEngine::Active') ) {
113            return $LayoutObject->FatalError(
114                Message => Translatable('Chat is not active.'),
115            );
116        }
117
118        # Check chat participant
119        my %ChatParticipant = $Kernel::OM->Get('Kernel::System::Chat')->ChatParticipantCheck(
120            ChatID      => $GetParam{FromChatID},
121            ChatterType => 'Customer',
122            ChatterID   => $Self->{UserID},
123        );
124
125        if ( !%ChatParticipant ) {
126            return $LayoutObject->FatalError(
127                Message => Translatable('No permission.'),
128            );
129        }
130    }
131
132    if ( !$Self->{Subaction} ) {
133
134        #Get default Queue ID if none is set
135        my $QueueDefaultID;
136        if ( !$GetParam{Dest} && !$Param{ToSelected} ) {
137            my $QueueDefault = $Config->{'QueueDefault'} || '';
138            if ($QueueDefault) {
139                $QueueDefaultID = $QueueObject->QueueLookup( Queue => $QueueDefault );
140                if ($QueueDefaultID) {
141                    $Param{ToSelected} = $QueueDefaultID . '||' . $QueueDefault;
142                }
143                $ACLCompatGetParam{QueueID} = $QueueDefaultID;
144            }
145
146            # warn if there is no (valid) default queue and the customer can't select one
147            elsif ( !$Config->{'Queue'} ) {
148                $LayoutObject->CustomerFatalError(
149                    Message => $LayoutObject->{LanguageObject}
150                        ->Translate( 'Check SysConfig setting for %s::QueueDefault.', $Self->{Action} ),
151                    Comment => Translatable('Please contact the administrator.'),
152                );
153                return;
154            }
155        }
156        elsif ( $GetParam{Dest} ) {
157            my ( $QueueIDParam, $QueueParam ) = split( /\|\|/, $GetParam{Dest} );
158            my $QueueIDLookup = $QueueObject->QueueLookup( Queue => $QueueParam );
159            if ( $QueueIDLookup && $QueueIDLookup eq $QueueIDParam ) {
160                my $CustomerPanelOwnSelection = $Kernel::OM->Get('Kernel::Config')->Get('CustomerPanelOwnSelection');
161                if ( %{ $CustomerPanelOwnSelection // {} } ) {
162                    $Param{ToSelected} = $QueueIDParam . '||' . $CustomerPanelOwnSelection->{$QueueParam};
163                }
164                else {
165                    $Param{ToSelected} = $GetParam{Dest};
166                }
167                $ACLCompatGetParam{QueueID} = $QueueIDLookup;
168            }
169        }
170
171        # create html strings for all dynamic fields
172        my %DynamicFieldHTML;
173
174        # cycle trough the activated Dynamic Fields for this screen
175        DYNAMICFIELD:
176        for my $DynamicFieldConfig ( @{$DynamicField} ) {
177            next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
178
179            my $PossibleValuesFilter;
180
181            my $IsACLReducible = $BackendObject->HasBehavior(
182                DynamicFieldConfig => $DynamicFieldConfig,
183                Behavior           => 'IsACLReducible',
184            );
185
186            if ($IsACLReducible) {
187
188                # get PossibleValues
189                my $PossibleValues = $BackendObject->PossibleValuesGet(
190                    DynamicFieldConfig => $DynamicFieldConfig,
191                );
192
193                # check if field has PossibleValues property in its configuration
194                if ( IsHashRefWithData($PossibleValues) ) {
195
196                    # convert possible values key => value to key => key for ACLs using a Hash slice
197                    my %AclData = %{$PossibleValues};
198                    @AclData{ keys %AclData } = keys %AclData;
199
200                    # set possible values filter from ACLs
201                    my $ACL = $TicketObject->TicketAcl(
202                        %GetParam,
203                        %ACLCompatGetParam,
204                        Action         => $Self->{Action},
205                        TicketID       => $Self->{TicketID},
206                        ReturnType     => 'Ticket',
207                        ReturnSubType  => 'DynamicField_' . $DynamicFieldConfig->{Name},
208                        Data           => \%AclData,
209                        CustomerUserID => $Self->{UserID},
210                    );
211                    if ($ACL) {
212                        my %Filter = $TicketObject->TicketAclData();
213
214                        # convert Filer key => key back to key => value using map
215                        %{$PossibleValuesFilter} = map { $_ => $PossibleValues->{$_} }
216                            keys %Filter;
217                    }
218                }
219            }
220
221            # get field html
222            $DynamicFieldHTML{ $DynamicFieldConfig->{Name} } =
223                $BackendObject->EditFieldRender(
224                DynamicFieldConfig   => $DynamicFieldConfig,
225                PossibleValuesFilter => $PossibleValuesFilter,
226                Mandatory =>
227                    $Config->{DynamicField}->{ $DynamicFieldConfig->{Name} } == 2,
228                LayoutObject    => $LayoutObject,
229                ParamObject     => $ParamObject,
230                AJAXUpdate      => 1,
231                UpdatableFields => $Self->_GetFieldsToUpdate(),
232                );
233        }
234
235        # print form ...
236        my $Output = $LayoutObject->CustomerHeader();
237        $Output .= $LayoutObject->CustomerNavigationBar();
238        $Output .= $Self->_MaskNew(
239            %GetParam,
240            %ACLCompatGetParam,
241            ToSelected       => $Param{ToSelected},
242            DynamicFieldHTML => \%DynamicFieldHTML,
243            FromChatID       => $GetParam{FromChatID} || '',
244        );
245        $Output .= $LayoutObject->CustomerFooter();
246        return $Output;
247    }
248    elsif ( $Self->{Subaction} eq 'StoreNew' ) {
249
250        my $ArticleObject        = $Kernel::OM->Get('Kernel::System::Ticket::Article');
251        my $ArticleBackendObject = $ArticleObject->BackendForChannel( ChannelName => 'Internal' );
252
253        my $NextScreen = $Config->{NextScreenAfterNewTicket};
254        my %Error;
255
256        # get destination queue
257        my $Dest = $ParamObject->GetParam( Param => 'Dest' ) || '';
258        my ( $NewQueueID, $To ) = split( /\|\|/, $Dest );
259        if ( !$To ) {
260            $NewQueueID = $ParamObject->GetParam( Param => 'NewQueueID' ) || '';
261            $To         = 'System';
262        }
263
264        # fallback, if no destination is given
265        if ( !$NewQueueID ) {
266            my $Queue = $ParamObject->GetParam( Param => 'Queue' )
267                || $Config->{'QueueDefault'}
268                || '';
269            if ($Queue) {
270                my $QueueID = $QueueObject->QueueLookup( Queue => $Queue );
271                $NewQueueID = $QueueID;
272                $To         = $Queue;
273            }
274        }
275
276        $GetParam{NewQueueID} = $NewQueueID;
277
278        # use default if ticket type is not available in screen but activated on system
279        if ( $ConfigObject->Get('Ticket::Type') && !$Config->{'TicketType'} ) {
280            my %TypeList = reverse $TicketObject->TicketTypeList(
281                %Param,
282                Action         => $Self->{Action},
283                CustomerUserID => $Self->{UserID},
284            );
285            $GetParam{TypeID} = $TypeList{ $Config->{'TicketTypeDefault'} };
286            if ( !$GetParam{TypeID} ) {
287                $LayoutObject->CustomerFatalError(
288                    Message =>
289                        $LayoutObject->{LanguageObject}
290                        ->Translate( 'Check SysConfig setting for %s::TicketTypeDefault.', $Self->{Action} ),
291                    Comment => Translatable('Please contact the administrator.'),
292                );
293                return;
294            }
295        }
296
297        my $UploadCacheObject = $Kernel::OM->Get('Kernel::System::Web::UploadCache');
298
299        # get all attachments meta data
300        my @Attachments = $UploadCacheObject->FormIDGetAllFilesMeta(
301            FormID => $Self->{FormID},
302        );
303
304        # create html strings for all dynamic fields
305        my %DynamicFieldHTML;
306
307        # cycle trough the activated Dynamic Fields for this screen
308        DYNAMICFIELD:
309        for my $DynamicFieldConfig ( @{$DynamicField} ) {
310            next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
311
312            my $PossibleValuesFilter;
313
314            my $IsACLReducible = $BackendObject->HasBehavior(
315                DynamicFieldConfig => $DynamicFieldConfig,
316                Behavior           => 'IsACLReducible',
317            );
318
319            if ($IsACLReducible) {
320
321                # get PossibleValues
322                my $PossibleValues = $BackendObject->PossibleValuesGet(
323                    DynamicFieldConfig => $DynamicFieldConfig,
324                );
325
326                # check if field has PossibleValues property in its configuration
327                if ( IsHashRefWithData($PossibleValues) ) {
328
329                    # convert possible values key => value to key => key for ACLs using a Hash slice
330                    my %AclData = %{$PossibleValues};
331                    @AclData{ keys %AclData } = keys %AclData;
332
333                    # set possible values filter from ACLs
334                    my $ACL = $TicketObject->TicketAcl(
335                        %GetParam,
336                        Action         => $Self->{Action},
337                        TicketID       => $Self->{TicketID},
338                        ReturnType     => 'Ticket',
339                        ReturnSubType  => 'DynamicField_' . $DynamicFieldConfig->{Name},
340                        Data           => \%AclData,
341                        CustomerUserID => $Self->{UserID},
342                    );
343                    if ($ACL) {
344                        my %Filter = $TicketObject->TicketAclData();
345
346                        # convert Filer key => key back to key => value using map
347                        %{$PossibleValuesFilter} = map { $_ => $PossibleValues->{$_} }
348                            keys %Filter;
349                    }
350                }
351            }
352
353            my $ValidationResult;
354
355            # do not validate on attachment upload or GetParam Expand
356            if ( !$GetParam{Expand} ) {
357
358                $ValidationResult = $BackendObject->EditFieldValueValidate(
359                    DynamicFieldConfig   => $DynamicFieldConfig,
360                    PossibleValuesFilter => $PossibleValuesFilter,
361                    ParamObject          => $ParamObject,
362                    Mandatory =>
363                        $Config->{DynamicField}->{ $DynamicFieldConfig->{Name} } == 2,
364                );
365
366                if ( !IsHashRefWithData($ValidationResult) ) {
367                    my $Output = $LayoutObject->CustomerHeader(
368                        Title => Translatable('Error'),
369                    );
370                    $Output .= $LayoutObject->CustomerError(
371                        Message =>
372                            $LayoutObject->{LanguageObject}
373                            ->Translate( 'Could not perform validation on field %s!', $DynamicFieldConfig->{Label} ),
374                        Comment => Translatable('Please contact the administrator.'),
375                    );
376                    $Output .= $LayoutObject->CustomerFooter();
377                    return $Output;
378                }
379
380                # propagate validation error to the Error variable to be detected by the frontend
381                if ( $ValidationResult->{ServerError} ) {
382                    $Error{ $DynamicFieldConfig->{Name} } = ' ServerError';
383                }
384            }
385
386            # get field html
387            $DynamicFieldHTML{ $DynamicFieldConfig->{Name} } =
388                $BackendObject->EditFieldRender(
389                DynamicFieldConfig   => $DynamicFieldConfig,
390                PossibleValuesFilter => $PossibleValuesFilter,
391                Mandatory =>
392                    $Config->{DynamicField}->{ $DynamicFieldConfig->{Name} } == 2,
393                ServerError  => $ValidationResult->{ServerError}  || '',
394                ErrorMessage => $ValidationResult->{ErrorMessage} || '',
395                LayoutObject => $LayoutObject,
396                ParamObject  => $ParamObject,
397                AJAXUpdate   => 1,
398                UpdatableFields => $Self->_GetFieldsToUpdate(),
399                );
400        }
401
402        # rewrap body if no rich text is used
403        if ( $GetParam{Body} && !$LayoutObject->{BrowserRichText} ) {
404            $GetParam{Body} = $LayoutObject->WrapPlainText(
405                MaxCharacters => $ConfigObject->Get('Ticket::Frontend::TextAreaNote'),
406                PlainText     => $GetParam{Body},
407            );
408        }
409
410        # if there is FromChatID, get related messages and prepend them to body
411        if ( $GetParam{FromChatID} ) {
412            my @ChatMessages = $Kernel::OM->Get('Kernel::System::Chat')->ChatMessageList(
413                ChatID => $GetParam{FromChatID},
414            );
415
416            for my $Message (@ChatMessages) {
417                $Message->{MessageText} = $LayoutObject->Ascii2Html(
418                    Text        => $Message->{MessageText},
419                    LinkFeature => 1,
420                );
421            }
422        }
423
424        # check queue
425        if ( !$NewQueueID && !$GetParam{Expand} ) {
426            $Error{QueueInvalid} = 'ServerError';
427        }
428
429        # prevent tamper with (Queue/Dest), see bug#9408
430        if ($NewQueueID) {
431
432            # get the original list of queues to display
433            my $Tos = $Self->_GetTos(
434                %GetParam,
435                %ACLCompatGetParam,
436                QueueID => $NewQueueID,
437            );
438
439            # check if current selected QueueID exists in the list of queues,\
440            # otherwise rise an error
441            if ( !$Tos->{$NewQueueID} ) {
442
443                # Check if queue is accessible by customer user (see bug#14886).
444                if ( $ConfigObject->Get('Ticket::Frontend::CustomerTicketMessage')->{Queue} == 0 ) {
445                    $Error{QueueDisabled} = 'ServerError';
446                }
447                else {
448                    $Error{QueueInvalid} = 'ServerError';
449                }
450            }
451
452            # set the correct queue name in $To if it was altered
453            if ( $To ne $Tos->{$NewQueueID} ) {
454                $To = $Tos->{$NewQueueID};
455            }
456        }
457
458        # check subject
459        if ( !$GetParam{Subject} ) {
460            $Error{SubjectInvalid} = 'ServerError';
461        }
462
463        # check body
464        if ( !$GetParam{Body} ) {
465            $Error{BodyInvalid} = 'ServerError';
466        }
467        if ( $GetParam{Expand} ) {
468            %Error = ();
469            $Error{Expand} = 1;
470        }
471
472        # check mandatory service
473        if (
474            $ConfigObject->Get('Ticket::Service')
475            && $Config->{Service}
476            && $Config->{ServiceMandatory}
477            && !$GetParam{ServiceID}
478            )
479        {
480            $Error{'ServiceIDInvalid'} = 'ServerError';
481        }
482
483        # check mandatory sla
484        if (
485            $ConfigObject->Get('Ticket::Service')
486            && $Config->{SLA}
487            && $Config->{SLAMandatory}
488            && !$GetParam{SLAID}
489            )
490        {
491            $Error{'SLAIDInvalid'} = 'ServerError';
492        }
493
494        # check type
495        if (
496            $ConfigObject->Get('Ticket::Type')
497            && !$GetParam{TypeID}
498            && !$GetParam{Expand}
499            )
500        {
501            $Error{TypeIDInvalid} = 'ServerError';
502        }
503
504        if (%Error) {
505
506            # html output
507            my $Output = $LayoutObject->CustomerHeader();
508            if ( $Error{QueueDisabled} ) {
509                $Output .= $LayoutObject->Notify(
510                    Priority => 'Error',
511                    Info => Translatable("You don't have sufficient permissions for ticket creation in default queue."),
512                );
513            }
514            $Output .= $LayoutObject->CustomerNavigationBar();
515            $Output .= $Self->_MaskNew(
516                Attachments => \@Attachments,
517                %GetParam,
518                ToSelected       => $Dest,
519                QueueID          => $NewQueueID,
520                DynamicFieldHTML => \%DynamicFieldHTML,
521                Errors           => \%Error,
522            );
523            $Output .= $LayoutObject->CustomerFooter();
524            return $Output;
525        }
526
527        # challenge token check for write action
528        $LayoutObject->ChallengeTokenCheck( Type => 'Customer' );
529
530        # if customer is not allowed to set priority, set it to default
531        if ( !$Config->{Priority} ) {
532            $GetParam{PriorityID} = '';
533            $GetParam{Priority}   = $Config->{PriorityDefault};
534        }
535
536        # create new ticket, do db insert
537        my $TicketID = $TicketObject->TicketCreate(
538            QueueID      => $NewQueueID,
539            TypeID       => $GetParam{TypeID},
540            ServiceID    => $GetParam{ServiceID},
541            SLAID        => $GetParam{SLAID},
542            Title        => $GetParam{Subject},
543            PriorityID   => $GetParam{PriorityID},
544            Priority     => $GetParam{Priority},
545            Lock         => 'unlock',
546            State        => $Config->{StateDefault},
547            CustomerID   => $Self->{UserCustomerID},
548            CustomerUser => $Self->{UserLogin},
549            OwnerID      => $ConfigObject->Get('CustomerPanelUserID'),
550            UserID       => $ConfigObject->Get('CustomerPanelUserID'),
551        );
552
553        # set ticket dynamic fields
554        # cycle trough the activated Dynamic Fields for this screen
555        DYNAMICFIELD:
556        for my $DynamicFieldConfig ( @{$DynamicField} ) {
557            next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
558            next DYNAMICFIELD if $DynamicFieldConfig->{ObjectType} ne 'Ticket';
559
560            # set the value
561            my $Success = $BackendObject->ValueSet(
562                DynamicFieldConfig => $DynamicFieldConfig,
563                ObjectID           => $TicketID,
564                Value              => $DynamicFieldValues{ $DynamicFieldConfig->{Name} },
565                UserID             => $ConfigObject->Get('CustomerPanelUserID'),
566            );
567        }
568
569        my $MimeType = 'text/plain';
570        if ( $LayoutObject->{BrowserRichText} ) {
571            $MimeType = 'text/html';
572
573            # verify html document
574            $GetParam{Body} = $LayoutObject->RichTextDocumentComplete(
575                String => $GetParam{Body},
576            );
577        }
578
579        my $PlainBody = $GetParam{Body};
580
581        if ( $LayoutObject->{BrowserRichText} ) {
582            $PlainBody = $LayoutObject->RichText2Ascii( String => $GetParam{Body} );
583        }
584
585        # create article
586        my $FullName = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerName(
587            UserLogin => $Self->{UserLogin},
588        );
589        my $From      = "\"$FullName\" <$Self->{UserEmail}>";
590        my $ArticleID = $ArticleBackendObject->ArticleCreate(
591            TicketID             => $TicketID,
592            IsVisibleForCustomer => 1,
593            SenderType           => $Config->{SenderType},
594            From                 => $From,
595            To                   => $To,
596            Subject              => $GetParam{Subject},
597            Body                 => $GetParam{Body},
598            MimeType             => $MimeType,
599            Charset              => $LayoutObject->{UserCharset},
600            UserID               => $ConfigObject->Get('CustomerPanelUserID'),
601            HistoryType          => $Config->{HistoryType},
602            HistoryComment       => $Config->{HistoryComment} || '%%',
603            AutoResponseType     => ( $ConfigObject->Get('AutoResponseForWebTickets') )
604            ? 'auto reply'
605            : '',
606            OrigHeader => {
607                From    => $From,
608                To      => $Self->{UserLogin},
609                Subject => $GetParam{Subject},
610                Body    => $PlainBody,
611            },
612            Queue => $QueueObject->QueueLookup( QueueID => $NewQueueID ),
613        );
614
615        if ( !$ArticleID ) {
616            my $Output = $LayoutObject->CustomerHeader(
617                Title => Translatable('Error'),
618            );
619            $Output .= $LayoutObject->CustomerError();
620            $Output .= $LayoutObject->CustomerFooter();
621            return $Output;
622        }
623
624        # set article dynamic fields
625        # cycle trough the activated Dynamic Fields for this screen
626        DYNAMICFIELD:
627        for my $DynamicFieldConfig ( @{$DynamicField} ) {
628            next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
629            next DYNAMICFIELD if $DynamicFieldConfig->{ObjectType} ne 'Article';
630
631            # set the value
632            my $Success = $BackendObject->ValueSet(
633                DynamicFieldConfig => $DynamicFieldConfig,
634                ObjectID           => $ArticleID,
635                Value              => $DynamicFieldValues{ $DynamicFieldConfig->{Name} },
636                UserID             => $ConfigObject->Get('CustomerPanelUserID'),
637            );
638        }
639
640        # Permissions check were done earlier
641        if ( $GetParam{FromChatID} ) {
642            my $ChatObject = $Kernel::OM->Get('Kernel::System::Chat');
643            my %Chat       = $ChatObject->ChatGet(
644                ChatID => $GetParam{FromChatID},
645            );
646            my @ChatMessageList = $ChatObject->ChatMessageList(
647                ChatID => $GetParam{FromChatID},
648            );
649            my $ChatArticleID;
650
651            if (@ChatMessageList) {
652                for my $Message (@ChatMessageList) {
653                    $Message->{MessageText} = $LayoutObject->Ascii2Html(
654                        Text        => $Message->{MessageText},
655                        LinkFeature => 1,
656                    );
657                }
658
659                my $ArticleChatBackend = $ArticleObject->BackendForChannel( ChannelName => 'Chat' );
660
661                $ChatArticleID = $ArticleChatBackend->ArticleCreate(
662                    TicketID             => $TicketID,
663                    SenderType           => $Config->{SenderType},
664                    ChatMessageList      => \@ChatMessageList,
665                    IsVisibleForCustomer => 1,
666                    UserID               => $ConfigObject->Get('CustomerPanelUserID'),
667                    HistoryType          => $Config->{HistoryType},
668                    HistoryComment       => $Config->{HistoryComment} || '%%',
669                );
670            }
671            if ($ChatArticleID) {
672                $ChatObject->ChatDelete(
673                    ChatID => $GetParam{FromChatID},
674                );
675            }
676        }
677
678        # get pre loaded attachment
679        my @AttachmentData = $UploadCacheObject->FormIDGetAllFilesData(
680            FormID => $Self->{FormID},
681        );
682
683        # get submitted attachment
684        my %UploadStuff = $ParamObject->GetUploadAll(
685            Param => 'file_upload',
686        );
687        if (%UploadStuff) {
688            push @AttachmentData, \%UploadStuff;
689        }
690
691        # write attachments
692        ATTACHMENT:
693        for my $Attachment (@AttachmentData) {
694
695            # skip, deleted not used inline images
696            my $ContentID = $Attachment->{ContentID};
697            if (
698                $ContentID
699                && ( $Attachment->{ContentType} =~ /image/i )
700                && ( $Attachment->{Disposition} eq 'inline' )
701                )
702            {
703                my $ContentIDHTMLQuote = $LayoutObject->Ascii2Html(
704                    Text => $ContentID,
705                );
706
707                # workaround for link encode of rich text editor, see bug#5053
708                my $ContentIDLinkEncode = $LayoutObject->LinkEncode($ContentID);
709                $GetParam{Body} =~ s/(ContentID=)$ContentIDLinkEncode/$1$ContentID/g;
710
711                # ignore attachment if not linked in body
712                next ATTACHMENT if $GetParam{Body} !~ /(\Q$ContentIDHTMLQuote\E|\Q$ContentID\E)/i;
713            }
714
715            # write existing file to backend
716            $ArticleBackendObject->ArticleWriteAttachment(
717                %{$Attachment},
718                ArticleID => $ArticleID,
719                UserID    => $ConfigObject->Get('CustomerPanelUserID'),
720            );
721        }
722
723        # remove pre submitted attachments
724        $UploadCacheObject->FormIDRemove( FormID => $Self->{FormID} );
725
726        # redirect
727        return $LayoutObject->Redirect(
728            OP => "Action=$NextScreen;TicketID=$TicketID",
729        );
730    }
731
732    elsif ( $Self->{Subaction} eq 'AJAXUpdate' ) {
733
734        my $Dest         = $ParamObject->GetParam( Param => 'Dest' ) || '';
735        my $CustomerUser = $Self->{UserID};
736        my $QueueID      = '';
737        if ( $Dest =~ /^(\d{1,100})\|\|.+?$/ ) {
738            $QueueID = $1;
739        }
740
741        # get list type
742        my $TreeView = 0;
743        if ( $ConfigObject->Get('Ticket::Frontend::ListType') eq 'tree' ) {
744            $TreeView = 1;
745        }
746
747        my $Tos = $Self->_GetTos(
748            %GetParam,
749            %ACLCompatGetParam,
750            QueueID => $QueueID,
751        );
752
753        my $NewTos;
754
755        if ($Tos) {
756            TOs:
757            for my $KeyTo ( sort keys %{$Tos} ) {
758                next TOs if ( $Tos->{$KeyTo} eq '-' );
759                $NewTos->{"$KeyTo||$Tos->{$KeyTo}"} = $Tos->{$KeyTo};
760            }
761        }
762        my $Priorities = $Self->_GetPriorities(
763            %GetParam,
764            %ACLCompatGetParam,
765            CustomerUserID => $CustomerUser || '',
766            QueueID        => $QueueID      || 1,
767        );
768        my $Services = $Self->_GetServices(
769            %GetParam,
770            %ACLCompatGetParam,
771            CustomerUserID => $CustomerUser || '',
772            QueueID        => $QueueID      || 1,
773        );
774        my $SLAs = $Self->_GetSLAs(
775            %GetParam,
776            %ACLCompatGetParam,
777            CustomerUserID => $CustomerUser || '',
778            QueueID        => $QueueID      || 1,
779            Services       => $Services,
780        );
781        my $Types = $Self->_GetTypes(
782            %GetParam,
783            %ACLCompatGetParam,
784            CustomerUserID => $CustomerUser || '',
785            QueueID        => $QueueID      || 1,
786        );
787
788        # update Dynamic Fields Possible Values via AJAX
789        my @DynamicFieldAJAX;
790
791        # cycle trough the activated Dynamic Fields for this screen
792        DYNAMICFIELD:
793        for my $DynamicFieldConfig ( @{$DynamicField} ) {
794            next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
795
796            my $IsACLReducible = $BackendObject->HasBehavior(
797                DynamicFieldConfig => $DynamicFieldConfig,
798                Behavior           => 'IsACLReducible',
799            );
800            next DYNAMICFIELD if !$IsACLReducible;
801
802            my $PossibleValues = $BackendObject->PossibleValuesGet(
803                DynamicFieldConfig => $DynamicFieldConfig,
804            );
805
806            # convert possible values key => value to key => key for ACLs using a Hash slice
807            my %AclData = %{$PossibleValues};
808            @AclData{ keys %AclData } = keys %AclData;
809
810            # set possible values filter from ACLs
811            my $ACL = $TicketObject->TicketAcl(
812                %GetParam,
813                %ACLCompatGetParam,
814                Action         => $Self->{Action},
815                QueueID        => $QueueID || 0,
816                ReturnType     => 'Ticket',
817                ReturnSubType  => 'DynamicField_' . $DynamicFieldConfig->{Name},
818                Data           => \%AclData,
819                CustomerUserID => $Self->{UserID},
820            );
821            if ($ACL) {
822                my %Filter = $TicketObject->TicketAclData();
823
824                # convert Filer key => key back to key => value using map
825                %{$PossibleValues} = map { $_ => $PossibleValues->{$_} } keys %Filter;
826            }
827
828            my $DataValues = $BackendObject->BuildSelectionDataGet(
829                DynamicFieldConfig => $DynamicFieldConfig,
830                PossibleValues     => $PossibleValues,
831                Value              => $DynamicFieldValues{ $DynamicFieldConfig->{Name} },
832            ) || $PossibleValues;
833
834            # add dynamic field to the list of fields to update
835            push(
836                @DynamicFieldAJAX,
837                {
838                    Name        => 'DynamicField_' . $DynamicFieldConfig->{Name},
839                    Data        => $DataValues,
840                    SelectedID  => $DynamicFieldValues{ $DynamicFieldConfig->{Name} },
841                    Translation => $DynamicFieldConfig->{Config}->{TranslatableValues} || 0,
842                    Max         => 100,
843                }
844            );
845        }
846
847        my $JSON = $LayoutObject->BuildSelectionJSON(
848            [
849                {
850                    Name         => 'Dest',
851                    Data         => $NewTos,
852                    SelectedID   => $Dest,
853                    Translation  => 0,
854                    PossibleNone => 1,
855                    TreeView     => $TreeView,
856                    Max          => 100,
857                },
858                {
859                    Name        => 'PriorityID',
860                    Data        => $Priorities,
861                    SelectedID  => $GetParam{PriorityID},
862                    Translation => 1,
863                    Max         => 100,
864                },
865                {
866                    Name         => 'ServiceID',
867                    Data         => $Services,
868                    SelectedID   => $GetParam{ServiceID},
869                    PossibleNone => 1,
870                    Translation  => 0,
871                    TreeView     => $TreeView,
872                    Max          => 100,
873                },
874                {
875                    Name         => 'SLAID',
876                    Data         => $SLAs,
877                    SelectedID   => $GetParam{SLAID},
878                    PossibleNone => 1,
879                    Translation  => 0,
880                    Max          => 100,
881                },
882                {
883                    Name         => 'TypeID',
884                    Data         => $Types,
885                    SelectedID   => $GetParam{TypeID},
886                    PossibleNone => 1,
887                    Translation  => 0,
888                    Max          => 100,
889                },
890                @DynamicFieldAJAX,
891            ],
892        );
893        return $LayoutObject->Attachment(
894            ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
895            Content     => $JSON,
896            Type        => 'inline',
897            NoCache     => 1,
898        );
899    }
900    else {
901        return $LayoutObject->ErrorScreen(
902            Message => Translatable('No Subaction!'),
903            Comment => Translatable('Please contact the administrator.'),
904        );
905    }
906
907}
908
909sub _GetPriorities {
910    my ( $Self, %Param ) = @_;
911
912    # get priority
913    my %Priorities;
914    if ( $Param{QueueID} || $Param{TicketID} ) {
915        %Priorities = $Kernel::OM->Get('Kernel::System::Ticket')->TicketPriorityList(
916            %Param,
917            Action         => $Self->{Action},
918            CustomerUserID => $Self->{UserID},
919        );
920    }
921    return \%Priorities;
922}
923
924sub _GetTypes {
925    my ( $Self, %Param ) = @_;
926
927    # get type
928    my %Type;
929    if ( $Param{QueueID} || $Param{TicketID} ) {
930        %Type = $Kernel::OM->Get('Kernel::System::Ticket')->TicketTypeList(
931            %Param,
932            Action         => $Self->{Action},
933            CustomerUserID => $Self->{UserID},
934        );
935    }
936    return \%Type;
937}
938
939sub _GetServices {
940    my ( $Self, %Param ) = @_;
941
942    # get service
943    my %Service;
944
945    # check needed
946    return \%Service if !$Param{QueueID} && !$Param{TicketID};
947
948    # get options for default services for unknown customers
949    my $DefaultServiceUnknownCustomer
950        = $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Service::Default::UnknownCustomer');
951
952    # get service list
953    if ( $Param{CustomerUserID} || $DefaultServiceUnknownCustomer ) {
954        %Service = $Kernel::OM->Get('Kernel::System::Ticket')->TicketServiceList(
955            %Param,
956            Action         => $Self->{Action},
957            CustomerUserID => $Self->{UserID},
958        );
959    }
960    return \%Service;
961}
962
963sub _GetSLAs {
964    my ( $Self, %Param ) = @_;
965
966    # get sla
967    my %SLA;
968    if ( $Param{ServiceID} && $Param{Services} && %{ $Param{Services} } ) {
969        if ( $Param{Services}->{ $Param{ServiceID} } ) {
970            %SLA = $Kernel::OM->Get('Kernel::System::Ticket')->TicketSLAList(
971                %Param,
972                Action         => $Self->{Action},
973                CustomerUserID => $Self->{UserID},
974            );
975        }
976    }
977    return \%SLA;
978}
979
980sub _GetTos {
981    my ( $Self, %Param ) = @_;
982
983    # check own selection
984    my %NewTos = ( '', '-' );
985    my $Module = $Kernel::OM->Get('Kernel::Config')->Get('CustomerPanel::NewTicketQueueSelectionModule')
986        || 'Kernel::Output::HTML::CustomerNewTicket::QueueSelectionGeneric';
987    if ( $Kernel::OM->Get('Kernel::System::Main')->Require($Module) ) {
988        my $Object = $Module->new(
989            %{$Self},
990            SystemAddress => $Kernel::OM->Get('Kernel::System::SystemAddress'),
991            Debug         => $Self->{Debug},
992        );
993
994        # log loaded module
995        if ( $Self->{Debug} && $Self->{Debug} > 1 ) {
996            $Kernel::OM->Get('Kernel::System::Log')->Log(
997                Priority => 'debug',
998                Message  => "Module: $Module loaded!",
999            );
1000        }
1001        %NewTos = (
1002            $Object->Run(
1003                Env       => $Self,
1004                ACLParams => \%Param
1005            ),
1006            ( '', => '-' )
1007        );
1008    }
1009    else {
1010        return $Kernel::OM->Get('Kernel::Output::HTML::Layout')->FatalDie(
1011            Message => "Could not load $Module!",
1012        );
1013    }
1014
1015    return \%NewTos;
1016}
1017
1018sub _MaskNew {
1019    my ( $Self, %Param ) = @_;
1020
1021    $Param{FormID} = $Self->{FormID};
1022    $Param{Errors}->{QueueInvalid} = $Param{Errors}->{QueueInvalid} || '';
1023
1024    my $DynamicFieldNames = $Self->_GetFieldsToUpdate(
1025        OnlyDynamicFields => 1,
1026    );
1027
1028    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
1029
1030    # get list type
1031    my $TreeView = 0;
1032    if ( $ConfigObject->Get('Ticket::Frontend::ListType') eq 'tree' ) {
1033        $TreeView = 1;
1034    }
1035
1036    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
1037    my $Config       = $Kernel::OM->Get('Kernel::Config')->Get("Ticket::Frontend::$Self->{Action}");
1038
1039    if ( $Config->{Queue} ) {
1040
1041        # check own selection
1042        my %NewTos = ( '', '-' );
1043        my $Module = $ConfigObject->Get('CustomerPanel::NewTicketQueueSelectionModule')
1044            || 'Kernel::Output::HTML::CustomerNewTicket::QueueSelectionGeneric';
1045        if ( $Kernel::OM->Get('Kernel::System::Main')->Require($Module) ) {
1046            my $Object = $Module->new(
1047                %{$Self},
1048                SystemAddress => $Kernel::OM->Get('Kernel::System::SystemAddress'),
1049                Debug         => $Self->{Debug},
1050            );
1051
1052            # log loaded module
1053            if ( $Self->{Debug} && $Self->{Debug} > 1 ) {
1054                $Kernel::OM->Get('Kernel::System::Log')->Log(
1055                    Priority => 'debug',
1056                    Message  => "Module: $Module loaded!",
1057                );
1058            }
1059            %NewTos = (
1060                $Object->Run(
1061                    Env       => $Self,
1062                    ACLParams => \%Param
1063                ),
1064                ( '', => '-' )
1065            );
1066        }
1067        else {
1068            return $LayoutObject->FatalError();
1069        }
1070
1071        # build to string
1072        if (%NewTos) {
1073            for ( sort keys %NewTos ) {
1074                $NewTos{"$_||$NewTos{$_}"} = $NewTos{$_};
1075                delete $NewTos{$_};
1076            }
1077        }
1078        $Param{ToStrg} = $LayoutObject->AgentQueueListOption(
1079            Data       => \%NewTos,
1080            Multiple   => 0,
1081            Size       => 0,
1082            Name       => 'Dest',
1083            Class      => "Validate_Required Modernize " . $Param{Errors}->{QueueInvalid},
1084            SelectedID => $Param{ToSelected} || $Param{QueueID},
1085            TreeView   => $TreeView,
1086        );
1087        $LayoutObject->Block(
1088            Name => 'Queue',
1089            Data => {
1090                %Param,
1091                QueueInvalid => $Param{Errors}->{QueueInvalid},
1092            },
1093        );
1094
1095    }
1096
1097    my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket');
1098
1099    # get priority
1100    if ( $Config->{Priority} ) {
1101        my %Priorities = $TicketObject->TicketPriorityList(
1102            %Param,
1103            CustomerUserID => $Self->{UserID},
1104            Action         => $Self->{Action},
1105        );
1106
1107        # build priority string
1108        my %PrioritySelected;
1109        if ( $Param{PriorityID} ) {
1110            $PrioritySelected{SelectedID} = $Param{PriorityID};
1111        }
1112        else {
1113            $PrioritySelected{SelectedValue} = $Config->{PriorityDefault} || '3 normal';
1114        }
1115        $Param{PriorityStrg} = $LayoutObject->BuildSelection(
1116            Data  => \%Priorities,
1117            Name  => 'PriorityID',
1118            Class => 'Modernize',
1119            %PrioritySelected,
1120        );
1121        $LayoutObject->Block(
1122            Name => 'Priority',
1123            Data => \%Param,
1124        );
1125    }
1126
1127    # types
1128    if ( $ConfigObject->Get('Ticket::Type') && $Config->{'TicketType'} ) {
1129        my %Type = $TicketObject->TicketTypeList(
1130            %Param,
1131            Action         => $Self->{Action},
1132            CustomerUserID => $Self->{UserID},
1133        );
1134
1135        if ( $Config->{'TicketTypeDefault'} && !$Param{TypeID} ) {
1136            my %ReverseType = reverse %Type;
1137            $Param{TypeID} = $ReverseType{ $Config->{'TicketTypeDefault'} };
1138        }
1139
1140        $Param{TypeStrg} = $LayoutObject->BuildSelection(
1141            Data         => \%Type,
1142            Name         => 'TypeID',
1143            SelectedID   => $Param{TypeID},
1144            PossibleNone => 1,
1145            Sort         => 'AlphanumericValue',
1146            Translation  => 0,
1147            Class        => "Validate_Required Modernize " . ( $Param{Errors}->{TypeIDInvalid} || '' ),
1148        );
1149        $LayoutObject->Block(
1150            Name => 'TicketType',
1151            Data => {
1152                %Param,
1153                TypeIDInvalid => $Param{Errors}->{TypeIDInvalid},
1154            }
1155        );
1156    }
1157
1158    # services
1159    if ( $ConfigObject->Get('Ticket::Service') && $Config->{Service} ) {
1160        my %Services;
1161        if ( $Param{QueueID} || $Param{TicketID} ) {
1162            %Services = $TicketObject->TicketServiceList(
1163                %Param,
1164                Action         => $Self->{Action},
1165                CustomerUserID => $Self->{UserID},
1166            );
1167        }
1168
1169        $Param{ServiceStrg} = $LayoutObject->BuildSelection(
1170            Data       => \%Services,
1171            Name       => 'ServiceID',
1172            SelectedID => $Param{ServiceID},
1173            Class      => 'Modernize '
1174                . ( $Config->{ServiceMandatory} ? 'Validate_Required ' : '' )
1175                . ( $Param{Errors}->{ServiceIDInvalid} || '' ),
1176            PossibleNone => 1,
1177            TreeView     => $TreeView,
1178            Sort         => 'TreeView',
1179            Translation  => 0,
1180            Max          => 200,
1181        );
1182        $LayoutObject->Block(
1183            Name => 'TicketService',
1184            Data => {
1185                ServiceMandatory => $Config->{ServiceMandatory} || 0,
1186                %Param,
1187            },
1188        );
1189
1190        # reset previous ServiceID to reset SLA-List if no service is selected
1191        if ( !$Services{ $Param{ServiceID} || '' } ) {
1192            $Param{ServiceID} = '';
1193        }
1194        my %SLA;
1195        if ( $Config->{SLA} ) {
1196            if ( $Param{ServiceID} ) {
1197                %SLA = $TicketObject->TicketSLAList(
1198                    %Param,
1199                    Action         => $Self->{Action},
1200                    CustomerUserID => $Self->{UserID},
1201                );
1202            }
1203
1204            $Param{SLAStrg} = $LayoutObject->BuildSelection(
1205                Data       => \%SLA,
1206                Name       => 'SLAID',
1207                SelectedID => $Param{SLAID},
1208                Class      => 'Modernize '
1209                    . ( $Config->{SLAMandatory} ? 'Validate_Required ' : '' )
1210                    . ( $Param{Errors}->{SLAInvalid} || '' ),
1211                PossibleNone => 1,
1212                Sort         => 'AlphanumericValue',
1213                Translation  => 0,
1214                Max          => 200,
1215            );
1216            $LayoutObject->Block(
1217                Name => 'TicketSLA',
1218                Data => {
1219                    SLAMandatory => $Config->{SLAMandatory} || 0,
1220                    %Param,
1221                }
1222            );
1223        }
1224    }
1225
1226    # prepare errors
1227    if ( $Param{Errors} ) {
1228        for ( sort keys %{ $Param{Errors} } ) {
1229            $Param{$_} = $Param{Errors}->{$_};
1230        }
1231    }
1232
1233    # get the dynamic fields for this screen
1234    my $DynamicField = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
1235        Valid       => 1,
1236        ObjectType  => [ 'Ticket', 'Article' ],
1237        FieldFilter => $Config->{DynamicField} || {},
1238    );
1239
1240    # reduce the dynamic fields to only the ones that are designed for customer interface
1241    my @CustomerDynamicFields;
1242    DYNAMICFIELD:
1243    for my $DynamicFieldConfig ( @{$DynamicField} ) {
1244        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
1245
1246        my $IsCustomerInterfaceCapable = $Kernel::OM->Get('Kernel::System::DynamicField::Backend')->HasBehavior(
1247            DynamicFieldConfig => $DynamicFieldConfig,
1248            Behavior           => 'IsCustomerInterfaceCapable',
1249        );
1250        next DYNAMICFIELD if !$IsCustomerInterfaceCapable;
1251
1252        push @CustomerDynamicFields, $DynamicFieldConfig;
1253    }
1254    $DynamicField = \@CustomerDynamicFields;
1255
1256    # Dynamic fields
1257    # cycle trough the activated Dynamic Fields for this screen
1258    DYNAMICFIELD:
1259    for my $DynamicFieldConfig ( @{$DynamicField} ) {
1260        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
1261
1262        # skip fields that HTML could not be retrieved
1263        next DYNAMICFIELD if !IsHashRefWithData(
1264            $Param{DynamicFieldHTML}->{ $DynamicFieldConfig->{Name} }
1265        );
1266
1267        # get the html strings form $Param
1268        my $DynamicFieldHTML = $Param{DynamicFieldHTML}->{ $DynamicFieldConfig->{Name} };
1269
1270        $LayoutObject->Block(
1271            Name => 'DynamicField',
1272            Data => {
1273                Name  => $DynamicFieldConfig->{Name},
1274                Label => $DynamicFieldHTML->{Label},
1275                Field => $DynamicFieldHTML->{Field},
1276            },
1277        );
1278
1279        # example of dynamic fields order customization
1280        $LayoutObject->Block(
1281            Name => 'DynamicField_' . $DynamicFieldConfig->{Name},
1282            Data => {
1283                Name  => $DynamicFieldConfig->{Name},
1284                Label => $DynamicFieldHTML->{Label},
1285                Field => $DynamicFieldHTML->{Field},
1286            },
1287        );
1288    }
1289
1290    # show attachments
1291    ATTACHMENT:
1292    for my $Attachment ( @{ $Param{Attachments} } ) {
1293        if (
1294            $Attachment->{ContentID}
1295            && $LayoutObject->{BrowserRichText}
1296            && ( $Attachment->{ContentType} =~ /image/i )
1297            && ( $Attachment->{Disposition} eq 'inline' )
1298            )
1299        {
1300            next ATTACHMENT;
1301        }
1302
1303        push @{ $Param{AttachmentList} }, $Attachment;
1304    }
1305
1306    # add rich text editor
1307    if ( $LayoutObject->{BrowserRichText} ) {
1308
1309        # use height/width defined for this screen
1310        $Param{RichTextHeight} = $Config->{RichTextHeight} || 0;
1311        $Param{RichTextWidth}  = $Config->{RichTextWidth}  || 0;
1312
1313        # set up customer rich text editor
1314        $LayoutObject->CustomerSetRichTextParameters(
1315            Data => \%Param,
1316        );
1317    }
1318
1319    # Permissions have been checked before in Run()
1320    if ( $Param{FromChatID} ) {
1321        my @ChatMessages = $Kernel::OM->Get('Kernel::System::Chat')->ChatMessageList(
1322            ChatID => $Param{FromChatID},
1323        );
1324
1325        for my $Message (@ChatMessages) {
1326            $Message->{MessageText} = $LayoutObject->Ascii2Html(
1327                Text        => $Message->{MessageText},
1328                LinkFeature => 1,
1329            );
1330        }
1331
1332        $LayoutObject->Block(
1333            Name => 'ChatArticlePreview',
1334            Data => {
1335                ChatMessages => \@ChatMessages,
1336            },
1337        );
1338    }
1339
1340    # send data to JS
1341    $LayoutObject->AddJSData(
1342        Key   => 'DynamicFieldNames',
1343        Value => $DynamicFieldNames,
1344    );
1345
1346    # get output back
1347    return $LayoutObject->Output(
1348        TemplateFile => 'CustomerTicketMessage',
1349        Data         => \%Param,
1350    );
1351}
1352
1353sub _GetFieldsToUpdate {
1354    my ( $Self, %Param ) = @_;
1355
1356    my @UpdatableFields;
1357
1358    # set the fields that can be updatable via AJAXUpdate
1359    if ( !$Param{OnlyDynamicFields} ) {
1360        @UpdatableFields = qw( Dest ServiceID SLAID PriorityID );
1361    }
1362
1363    my $Config = $Kernel::OM->Get('Kernel::Config')->Get("Ticket::Frontend::$Self->{Action}");
1364
1365    # get the dynamic fields for this screen
1366    my $DynamicField = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
1367        Valid       => 1,
1368        ObjectType  => [ 'Ticket', 'Article' ],
1369        FieldFilter => $Config->{DynamicField} || {},
1370    );
1371
1372    # cycle trough the activated Dynamic Fields for this screen
1373    DYNAMICFIELD:
1374    for my $DynamicFieldConfig ( @{$DynamicField} ) {
1375        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
1376
1377        my $IsACLReducible = $Kernel::OM->Get('Kernel::System::DynamicField::Backend')->HasBehavior(
1378            DynamicFieldConfig => $DynamicFieldConfig,
1379            Behavior           => 'IsACLReducible',
1380        );
1381        next DYNAMICFIELD if !$IsACLReducible;
1382
1383        push @UpdatableFields, 'DynamicField_' . $DynamicFieldConfig->{Name};
1384    }
1385
1386    return \@UpdatableFields;
1387}
1388
13891;
1390