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::AdminCustomerUser;
10
11use strict;
12use warnings;
13
14use Kernel::System::CheckItem;
15use Kernel::System::VariableCheck qw(:all);
16use Kernel::Language qw(Translatable);
17
18our $ObjectManagerDisabled = 1;
19
20sub new {
21    my ( $Type, %Param ) = @_;
22
23    # allocate new hash for object
24    my $Self = {%Param};
25    bless( $Self, $Type );
26
27    my $DynamicFieldConfigs = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
28        ObjectType => 'CustomerUser',
29    );
30
31    $Self->{DynamicFieldLookup} = { map { $_->{Name} => $_ } @{$DynamicFieldConfigs} };
32
33    return $Self;
34}
35
36sub Run {
37    my ( $Self, %Param ) = @_;
38
39    my $ParamObject  = $Kernel::OM->Get('Kernel::System::Web::Request');
40    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
41
42    my $Nav    = $ParamObject->GetParam( Param => 'Nav' )    || '';
43    my $Source = $ParamObject->GetParam( Param => 'Source' ) || 'CustomerUser';
44    my $Search = $ParamObject->GetParam( Param => 'Search' );
45    $Search
46        ||= $ConfigObject->Get('AdminCustomerUser::RunInitialWildcardSearch') ? '*' : '';
47
48    # create local object
49    my $CheckItemObject = $Kernel::OM->Get('Kernel::System::CheckItem');
50
51    my $NavBar       = '';
52    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
53    if ( $Nav eq 'None' ) {
54        $NavBar = $LayoutObject->Header( Type => 'Small' );
55    }
56    else {
57        $NavBar = $LayoutObject->Header();
58        $NavBar .= $LayoutObject->NavigationBar(
59            Type => $Nav eq 'Agent' ? 'Customers' : 'Admin',
60        );
61    }
62
63    # Get list of valid IDs.
64    my @ValidIDList = $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet();
65
66    # check the permission for the SwitchToCustomer feature
67    if ( $ConfigObject->Get('SwitchToCustomer') ) {
68
69        my $GroupObject = $Kernel::OM->Get('Kernel::System::Group');
70
71        # get the group id which is allowed to use the switch to customer feature
72        my $SwitchToCustomerGroupID = $GroupObject->GroupLookup(
73            Group => $ConfigObject->Get('SwitchToCustomer::PermissionGroup'),
74        );
75
76        # get user groups, where the user has the rw privilege
77        my %Groups = $GroupObject->PermissionUserGet(
78            UserID => $Self->{UserID},
79            Type   => 'rw',
80        );
81
82        # if the user is a member in this group he can access the feature
83        if ( $Groups{$SwitchToCustomerGroupID} ) {
84            $Self->{SwitchToCustomerPermission} = 1;
85        }
86    }
87
88    my $CustomerUserObject = $Kernel::OM->Get('Kernel::System::CustomerUser');
89    my $MainObject         = $Kernel::OM->Get('Kernel::System::Main');
90
91    # ------------------------------------------------------------ #
92    #  switch to customer
93    # ------------------------------------------------------------ #
94    if (
95        $Self->{Subaction} eq 'Switch'
96        && $ConfigObject->Get('SwitchToCustomer')
97        && $Self->{SwitchToCustomerPermission}
98        )
99    {
100
101        # challenge token check for write action
102        $LayoutObject->ChallengeTokenCheck();
103
104        # get user data
105        my $UserID   = $ParamObject->GetParam( Param => 'ID' ) || '';
106        my %UserData = $CustomerUserObject->CustomerUserDataGet(
107            User  => $UserID,
108            Valid => 1,
109        );
110
111        # create new session id
112        my $NewSessionID = $Kernel::OM->Get('Kernel::System::AuthSession')->CreateSessionID(
113            %UserData,
114            UserLastRequest => $Kernel::OM->Create('Kernel::System::DateTime')->ToEpoch(),
115            UserType        => 'Customer',
116            SessionSource   => 'CustomerInterface',
117        );
118
119        # get customer interface session name
120        my $SessionName = $ConfigObject->Get('CustomerPanelSessionName') || 'CSID';
121
122        # create a new LayoutObject with SessionIDCookie
123        my $Expires = '+' . $ConfigObject->Get('SessionMaxTime') . 's';
124        if ( !$ConfigObject->Get('SessionUseCookieAfterBrowserClose') ) {
125            $Expires = '';
126        }
127
128        my $SecureAttribute;
129        if ( $ConfigObject->Get('HttpType') eq 'https' ) {
130
131            # Restrict Cookie to HTTPS if it is used.
132            $SecureAttribute = 1;
133        }
134
135        my $LayoutObject = Kernel::Output::HTML::Layout->new(
136            %{$Self},
137            SetCookies => {
138                SessionIDCookie => $ParamObject->SetCookie(
139                    Key      => $SessionName,
140                    Value    => $NewSessionID,
141                    Expires  => $Expires,
142                    Path     => $ConfigObject->Get('ScriptAlias'),
143                    Secure   => scalar $SecureAttribute,
144                    HTTPOnly => 1,
145                ),
146            },
147            SessionID   => $NewSessionID,
148            SessionName => $ConfigObject->Get('SessionName'),
149        );
150
151        # log event
152        $Kernel::OM->Get('Kernel::System::Log')->Log(
153            Priority => 'notice',
154            Message =>
155                "Switched from Agent to Customer ($Self->{UserLogin} -=> $UserData{UserLogin})",
156        );
157
158        # build URL to customer interface
159        my $URL = $ConfigObject->Get('HttpType')
160            . '://'
161            . $ConfigObject->Get('FQDN')
162            . '/'
163            . $ConfigObject->Get('ScriptAlias')
164            . 'customer.pl';
165
166        # if no sessions are used we attach the session as URL parameter
167        if ( !$ConfigObject->Get('SessionUseCookie') ) {
168            $URL .= "?$SessionName=$NewSessionID";
169        }
170
171        # redirect to customer interface with new session id
172        return $LayoutObject->Redirect( ExtURL => $URL );
173    }
174
175    # search user list
176    if ( $Self->{Subaction} eq 'Search' ) {
177        $Self->_Overview(
178            Nav    => $Nav,
179            Search => $Search,
180        );
181        my $Output = $NavBar;
182        $Output .= $LayoutObject->Output(
183            TemplateFile => 'AdminCustomerUser',
184            Data         => \%Param,
185        );
186
187        if ( $Nav eq 'None' ) {
188            $Output .= $LayoutObject->Footer( Type => 'Small' );
189        }
190        else {
191            $Output .= $LayoutObject->Footer();
192        }
193
194        return $Output;
195    }
196
197    # ------------------------------------------------------------ #
198    # download file preferences
199    # ------------------------------------------------------------ #
200    elsif ( $Self->{Subaction} eq 'Download' ) {
201        my $Group = $ParamObject->GetParam( Param => 'Group' ) || '';
202        my $User  = $ParamObject->GetParam( Param => 'ID' )    || '';
203        my $File  = $ParamObject->GetParam( Param => 'File' )  || '';
204
205        # get user data
206        my %UserData    = $CustomerUserObject->CustomerUserDataGet( User => $User );
207        my %Preferences = %{ $ConfigObject->Get('CustomerPreferencesGroups') };
208        my $Module      = $Preferences{$Group}->{Module};
209        if ( !$MainObject->Require($Module) ) {
210            return $LayoutObject->FatalError();
211        }
212        my $Object = $Module->new(
213            %{$Self},
214            ConfigItem => $Preferences{$Group},
215            UserObject => $CustomerUserObject,
216            Debug      => $Self->{Debug},
217        );
218        my %File = $Object->Download( UserData => \%UserData );
219
220        return $LayoutObject->Attachment(%File);
221    }
222
223    # ------------------------------------------------------------ #
224    # change
225    # ------------------------------------------------------------ #
226    elsif ( $Self->{Subaction} eq 'Change' ) {
227        my $User         = $ParamObject->GetParam( Param => 'ID' )           || '';
228        my $Notification = $ParamObject->GetParam( Param => 'Notification' ) || '';
229
230        # get user data
231        my %UserData = $CustomerUserObject->CustomerUserDataGet( User => $User );
232
233        my $Output = $NavBar;
234        $Output .= $LayoutObject->Notify( Info => Translatable('Customer updated!') )
235            if ( $Notification && $Notification eq 'Update' );
236        $Output .= $Self->_Edit(
237            Nav    => $Nav,
238            Action => 'Change',
239            Source => $Source,
240            Search => $Search,
241            ID     => $User,
242            %UserData,
243        );
244
245        if ( $Nav eq 'None' ) {
246            $Output .= $LayoutObject->Footer( Type => 'Small' );
247        }
248        else {
249            $Output .= $LayoutObject->Footer();
250        }
251
252        return $Output;
253    }
254
255    # ------------------------------------------------------------ #
256    # change action
257    # ------------------------------------------------------------ #
258    elsif ( $Self->{Subaction} eq 'ChangeAction' ) {
259
260        # challenge token check for write action
261        $LayoutObject->ChallengeTokenCheck();
262
263        # update only the preferences and dynamic fields, if the source is readonly or a ldap backend
264        my $UpdateOnlyPreferences;
265
266        if ( $ConfigObject->Get($Source)->{ReadOnly} || $ConfigObject->Get($Source)->{Module} =~ /LDAP/i ) {
267            $UpdateOnlyPreferences = 1;
268        }
269
270        my $Note = '';
271        my ( %GetParam, %Errors );
272
273        # Get dynamic field backend object.
274        my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
275
276        ENTRY:
277        for my $Entry ( @{ $ConfigObject->Get($Source)->{Map} } ) {
278
279            # check dynamic fields
280            if ( $Entry->[5] eq 'dynamic_field' ) {
281
282                my $DynamicFieldConfig = $Self->{DynamicFieldLookup}->{ $Entry->[2] };
283
284                if ( !IsHashRefWithData($DynamicFieldConfig) ) {
285                    $Kernel::OM->Get('Kernel::System::Log')->Log(
286                        Priority => 'error',
287                        Message  => "DynamicField $Entry->[2] not found!",
288                    );
289                    next ENTRY;
290                }
291
292                my $ValidationResult = $DynamicFieldBackendObject->EditFieldValueValidate(
293                    DynamicFieldConfig => $DynamicFieldConfig,
294                    ParamObject        => $ParamObject,
295                    Mandatory          => $Entry->[4],
296                );
297
298                if ( $ValidationResult->{ServerError} ) {
299                    $Errors{ $Entry->[0] } = $ValidationResult;
300                }
301                else {
302
303                    # generate storable value of dynamic field edit field
304                    $GetParam{ $Entry->[0] } = $DynamicFieldBackendObject->EditFieldValueGet(
305                        DynamicFieldConfig => $DynamicFieldConfig,
306                        ParamObject        => $ParamObject,
307                        LayoutObject       => $LayoutObject,
308                    );
309                }
310            }
311
312            # check remaining non-dynamic-field mandatory fields
313            else {
314                $GetParam{ $Entry->[0] } = $ParamObject->GetParam( Param => $Entry->[0] ) || '';
315
316                next ENTRY if $UpdateOnlyPreferences;
317
318                if ( !$GetParam{ $Entry->[0] } && $Entry->[4] ) {
319                    $Errors{ $Entry->[0] . 'Invalid' } = 'ServerError';
320                }
321            }
322        }
323        $GetParam{ID} = $ParamObject->GetParam( Param => 'ID' ) || '';
324
325        # check email address
326        if (
327            !$UpdateOnlyPreferences
328            && $GetParam{UserEmail}
329            && !$CheckItemObject->CheckEmail( Address => $GetParam{UserEmail} )
330            && grep { $_ eq $GetParam{ValidID} } @ValidIDList
331            )
332        {
333            $Errors{UserEmailInvalid} = 'ServerError';
334            $Errors{ErrorType}        = $CheckItemObject->CheckErrorType() . 'ServerErrorMsg';
335        }
336
337        # Get the current user data for some checks.
338        my %CurrentUserData = $CustomerUserObject->CustomerUserDataGet(
339            User => $GetParam{ID},
340        );
341
342        # Check CustomerID, if CustomerCompanySupport is enabled and the UserCustomerID was changed.
343        if (
344            $ConfigObject->Get($Source)->{CustomerCompanySupport}
345            && $GetParam{UserCustomerID}
346            && $CurrentUserData{UserCustomerID} ne $GetParam{UserCustomerID}
347            )
348        {
349
350            my %Company = $Kernel::OM->Get('Kernel::System::CustomerCompany')->CustomerCompanyGet(
351                CustomerID => $GetParam{UserCustomerID},
352            );
353
354            if ( !%Company ) {
355                $Errors{UserCustomerIDInvalid} = 'ServerError';
356            }
357        }
358
359        # if no errors occurred
360        if ( !%Errors ) {
361
362            my $UpdateSuccess;
363            if ( !$UpdateOnlyPreferences ) {
364                $UpdateSuccess = $CustomerUserObject->CustomerUserUpdate(
365                    %GetParam,
366                    UserID => $Self->{UserID},
367                );
368            }
369
370            if ( $UpdateSuccess || $UpdateOnlyPreferences ) {
371
372                # set dynamic field values
373                my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField');
374
375                ENTRY:
376                for my $Entry ( @{ $ConfigObject->Get($Source)->{Map} } ) {
377                    next ENTRY if $Entry->[5] ne 'dynamic_field';
378
379                    my $DynamicFieldConfig = $Self->{DynamicFieldLookup}->{ $Entry->[2] };
380
381                    if ( !IsHashRefWithData($DynamicFieldConfig) ) {
382                        $Note .= $LayoutObject->Notify(
383                            Info => $LayoutObject->{LanguageObject}->Translate(
384                                'Dynamic field %s not found!',
385                                $Entry->[2],
386                            ),
387                        );
388                        next ENTRY;
389                    }
390
391                    my $ValueSet = $DynamicFieldBackendObject->ValueSet(
392                        DynamicFieldConfig => $DynamicFieldConfig,
393                        ObjectName         => $GetParam{UserLogin},
394                        Value              => $GetParam{ $Entry->[0] },
395                        UserID             => $Self->{UserID},
396                    );
397
398                    if ( !$ValueSet ) {
399                        $Note .= $LayoutObject->Notify(
400                            Info => $LayoutObject->{LanguageObject}->Translate(
401                                'Unable to set value for dynamic field %s!',
402                                $Entry->[2],
403                            ),
404                        );
405                        next ENTRY;
406                    }
407                }
408
409                # update preferences
410                my %Preferences = %{ $ConfigObject->Get('CustomerPreferencesGroups') };
411                GROUP:
412                for my $Group ( sort keys %Preferences ) {
413                    next GROUP if $Group eq 'Password';
414
415                    # get user data
416                    my %UserData = $CustomerUserObject->CustomerUserDataGet(
417                        User => $GetParam{UserLogin}
418                    );
419                    my $Module = $Preferences{$Group}->{Module};
420                    if ( !$MainObject->Require($Module) ) {
421                        return $LayoutObject->FatalError();
422                    }
423                    my $Object = $Module->new(
424                        %{$Self},
425                        ConfigItem => $Preferences{$Group},
426                        UserObject => $CustomerUserObject,
427                        Debug      => $Self->{Debug},
428                    );
429                    my @Params = $Object->Param( UserData => \%UserData );
430                    if (@Params) {
431                        my %GetParam;
432                        for my $ParamItem (@Params) {
433                            my @Array = $ParamObject->GetArray( Param => $ParamItem->{Name} );
434                            $GetParam{ $ParamItem->{Name} } = \@Array;
435                        }
436                        if (
437                            !$Object->Run(
438                                GetParam => \%GetParam,
439                                UserData => \%UserData
440                            )
441                            )
442                        {
443                            $Note .= $LayoutObject->Notify( Info => $Object->Error() );
444                        }
445                    }
446                }
447
448                # clear customer user cache
449                $CustomerUserObject->CustomerUserCacheClear(
450                    UserLogin => $GetParam{UserLogin},
451                );
452
453                # get user data and show screen again
454                if ( !$Note ) {
455
456                    # if the user would like to continue editing the priority, just redirect to the edit screen
457                    if (
458                        defined $ParamObject->GetParam( Param => 'ContinueAfterSave' )
459                        && ( $ParamObject->GetParam( Param => 'ContinueAfterSave' ) eq '1' )
460                        )
461                    {
462                        my $ID = $ParamObject->GetParam( Param => 'ID' ) || '';
463                        return $LayoutObject->Redirect(
464                            OP =>
465                                "Action=$Self->{Action};Subaction=Change;ID=$ID;Search=$Search;Nav=$Nav;Notification=Update"
466                        );
467                    }
468                    else {
469
470                        # otherwise return to overview
471                        return $LayoutObject->Redirect( OP => "Action=$Self->{Action};Notification=Update" );
472                    }
473                }
474            }
475            else {
476                $Note .= $LayoutObject->Notify( Priority => 'Error' );
477            }
478        }
479
480        # something has gone wrong
481        my $Output = $NavBar;
482        $Output .= $Note;
483        $Output .= $Self->_Edit(
484            Nav    => $Nav,
485            Action => 'Change',
486            Source => $Source,
487            Search => $Search,
488            Errors => \%Errors,
489            %GetParam,
490        );
491
492        if ( $Nav eq 'None' ) {
493            $Output .= $LayoutObject->Footer( Type => 'Small' );
494        }
495        else {
496            $Output .= $LayoutObject->Footer();
497        }
498
499        return $Output;
500    }
501
502    # ------------------------------------------------------------ #
503    # add
504    # ------------------------------------------------------------ #
505    elsif ( $Self->{Subaction} eq 'Add' ) {
506        my %GetParam;
507        $GetParam{UserLogin}  = $ParamObject->GetParam( Param => 'UserLogin' )  || '';
508        $GetParam{CustomerID} = $ParamObject->GetParam( Param => 'CustomerID' ) || '';
509        my $Output = $NavBar;
510        $Output .= $Self->_Edit(
511            Nav    => $Nav,
512            Action => 'Add',
513            Source => $Source,
514            Search => $Search,
515            %GetParam,
516        );
517
518        if ( $Nav eq 'None' ) {
519            $Output .= $LayoutObject->Footer( Type => 'Small' );
520        }
521        else {
522            $Output .= $LayoutObject->Footer();
523        }
524
525        return $Output;
526    }
527
528    # ------------------------------------------------------------ #
529    # add action
530    # ------------------------------------------------------------ #
531    elsif ( $Self->{Subaction} eq 'AddAction' ) {
532
533        # challenge token check for write action
534        $LayoutObject->ChallengeTokenCheck();
535
536        my $Note = '';
537        my ( %GetParam, %Errors );
538
539        my $AutoLoginCreation = $ConfigObject->Get($Source)->{AutoLoginCreation};
540
541        # Get dynamic field backend object.
542        my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
543
544        ENTRY:
545        for my $Entry ( @{ $ConfigObject->Get($Source)->{Map} } ) {
546
547            # don't validate UserLogin if AutoLoginCreation is configured
548            next ENTRY if ( $AutoLoginCreation && $Entry->[0] eq 'UserLogin' );
549
550            # check dynamic fields
551            if ( $Entry->[5] eq 'dynamic_field' ) {
552
553                my $DynamicFieldConfig = $Self->{DynamicFieldLookup}->{ $Entry->[2] };
554
555                if ( !IsHashRefWithData($DynamicFieldConfig) ) {
556                    $Kernel::OM->Get('Kernel::System::Log')->Log(
557                        Priority => 'error',
558                        Message  => "DynamicField $Entry->[2] not found!",
559                    );
560                    next ENTRY;
561                }
562
563                my $ValidationResult = $DynamicFieldBackendObject->EditFieldValueValidate(
564                    DynamicFieldConfig => $DynamicFieldConfig,
565                    ParamObject        => $ParamObject,
566                    Mandatory          => $Entry->[4],
567                );
568
569                if ( $ValidationResult->{ServerError} ) {
570                    $Errors{ $Entry->[0] } = $ValidationResult;
571                }
572                else {
573
574                    # generate storable value of dynamic field edit field
575                    $GetParam{ $Entry->[0] } = $DynamicFieldBackendObject->EditFieldValueGet(
576                        DynamicFieldConfig => $DynamicFieldConfig,
577                        ParamObject        => $ParamObject,
578                        LayoutObject       => $LayoutObject,
579                    );
580                }
581            }
582
583            # check remaining non-dynamic-field mandatory fields
584            else {
585                $GetParam{ $Entry->[0] } = $ParamObject->GetParam( Param => $Entry->[0] ) || '';
586                if ( !$GetParam{ $Entry->[0] } && $Entry->[4] ) {
587                    $Errors{ $Entry->[0] . 'Invalid' } = 'ServerError';
588                }
589            }
590        }
591
592        # check email address
593        if (
594            $GetParam{UserEmail}
595            && !$CheckItemObject->CheckEmail( Address => $GetParam{UserEmail} )
596            && grep { $_ eq $GetParam{ValidID} } @ValidIDList
597            )
598        {
599            $Errors{UserEmailInvalid} = 'ServerError';
600            $Errors{ErrorType}        = $CheckItemObject->CheckErrorType() . 'ServerErrorMsg';
601        }
602
603        # Check CustomerID, if CustomerCompanySupport is enabled.
604        if ( $ConfigObject->Get($Source)->{CustomerCompanySupport} && $GetParam{UserCustomerID} ) {
605
606            my %Company = $Kernel::OM->Get('Kernel::System::CustomerCompany')->CustomerCompanyGet(
607                CustomerID => $GetParam{UserCustomerID},
608            );
609
610            if ( !%Company ) {
611                $Errors{UserCustomerIDInvalid} = 'ServerError';
612            }
613        }
614
615        # if no errors occurred
616        if ( !%Errors ) {
617
618            # add user
619            my $User = $CustomerUserObject->CustomerUserAdd(
620                %GetParam,
621                UserID => $Self->{UserID},
622                Source => $Source
623            );
624            if ($User) {
625
626                # set dynamic field values
627                my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField');
628
629                ENTRY:
630                for my $Entry ( @{ $ConfigObject->Get($Source)->{Map} } ) {
631                    next ENTRY if $Entry->[5] ne 'dynamic_field';
632
633                    my $DynamicFieldConfig = $Self->{DynamicFieldLookup}->{ $Entry->[2] };
634
635                    if ( !IsHashRefWithData($DynamicFieldConfig) ) {
636                        $Note .= $LayoutObject->Notify(
637                            Info => $LayoutObject->{LanguageObject}->Translate(
638                                'Dynamic field %s not found!',
639                                $Entry->[2],
640                            ),
641                        );
642                        next ENTRY;
643                    }
644
645                    my $ValueSet = $DynamicFieldBackendObject->ValueSet(
646                        DynamicFieldConfig => $DynamicFieldConfig,
647                        ObjectName         => $User,
648                        Value              => $GetParam{ $Entry->[0] },
649                        UserID             => $Self->{UserID},
650                    );
651
652                    if ( !$ValueSet ) {
653                        $Note .= $LayoutObject->Notify(
654                            Info => $LayoutObject->{LanguageObject}->Translate(
655                                'Unable to set value for dynamic field %s!',
656                                $Entry->[2],
657                            ),
658                        );
659                        next ENTRY;
660                    }
661                }
662
663                # update preferences
664                my %Preferences = %{ $ConfigObject->Get('CustomerPreferencesGroups') };
665                GROUP:
666                for my $Group ( sort keys %Preferences ) {
667                    next GROUP if $Group eq 'Password';
668
669                    # get user data
670                    my %UserData = $CustomerUserObject->CustomerUserDataGet(
671                        User => $User,
672                    );
673                    my $Module = $Preferences{$Group}->{Module};
674                    if ( !$MainObject->Require($Module) ) {
675                        return $LayoutObject->FatalError();
676                    }
677                    my $Object = $Module->new(
678                        %{$Self},
679                        ConfigItem => $Preferences{$Group},
680                        UserObject => $CustomerUserObject,
681                        Debug      => $Self->{Debug},
682                    );
683                    my @Params = $Object->Param( %{ $Preferences{$Group} }, UserData => \%UserData );
684                    if (@Params) {
685                        my %GetParam;
686                        for my $ParamItem (@Params) {
687                            my @Array = $ParamObject->GetArray( Param => $ParamItem->{Name} );
688                            $GetParam{ $ParamItem->{Name} } = \@Array;
689                        }
690                        if (
691                            !$Object->Run(
692                                GetParam => \%GetParam,
693                                UserData => \%UserData
694                            )
695                            )
696                        {
697                            $Note .= $LayoutObject->Notify( Info => $Object->Error() );
698                        }
699                    }
700                }
701
702                # get user data and show screen again
703                if ( !$Note ) {
704
705                    # in borrowed view, take the new created customer over into the new ticket
706                    if ( $Nav eq 'None' ) {
707                        my $Output = $NavBar;
708
709                        $LayoutObject->AddJSData(
710                            Key   => 'Customer',
711                            Value => $User,
712                        );
713                        $LayoutObject->AddJSData(
714                            Key   => 'Nav',
715                            Value => $Nav,
716                        );
717
718                        $Output .= $LayoutObject->Output(
719                            TemplateFile => 'AdminCustomerUser',
720                            Data         => \%Param,
721                        );
722
723                        $Output .= $LayoutObject->Footer( Type => 'Small' );
724
725                        return $Output;
726                    }
727
728                    $Self->_Overview(
729                        Nav    => $Nav,
730                        Search => $Search,
731                    );
732
733                    my $Output        = $NavBar . $Note;
734                    my $URL           = '';
735                    my $UserHTMLQuote = $LayoutObject->LinkEncode($User);
736                    my $UserQuote     = $LayoutObject->Ascii2Html( Text => $User );
737                    if ( $ConfigObject->Get('Frontend::Module')->{AgentTicketPhone} ) {
738                        $URL
739                            .= "<a href=\"$LayoutObject->{Baselink}Action=AgentTicketPhone;Subaction=StoreNew;ExpandCustomerName=2;CustomerUser=$UserHTMLQuote;$LayoutObject->{ChallengeTokenParam}\">"
740                            . $LayoutObject->{LanguageObject}->Translate('New phone ticket')
741                            . "</a>";
742                    }
743                    if ( $ConfigObject->Get('Frontend::Module')->{AgentTicketEmail} ) {
744                        if ($URL) {
745                            $URL .= " - ";
746                        }
747                        $URL
748                            .= "<a href=\"$LayoutObject->{Baselink}Action=AgentTicketEmail;Subaction=StoreNew;ExpandCustomerName=2;CustomerUser=$UserHTMLQuote;$LayoutObject->{ChallengeTokenParam}\">"
749                            . $LayoutObject->{LanguageObject}->Translate('New email ticket')
750                            . "</a>";
751                    }
752                    if ($URL) {
753                        $Output
754                            .= $LayoutObject->Notify(
755                            Data => $LayoutObject->{LanguageObject}->Translate(
756                                'Customer %s added',
757                                $UserQuote,
758                                )
759                                . " ( $URL )!",
760                            );
761                    }
762                    else {
763                        $Output
764                            .= $LayoutObject->Notify(
765                            Data => $LayoutObject->{LanguageObject}->Translate(
766                                'Customer %s added',
767                                $UserQuote,
768                                )
769                                . "!",
770                            );
771                    }
772                    $Output .= $LayoutObject->Output(
773                        TemplateFile => 'AdminCustomerUser',
774                        Data         => \%Param,
775                    );
776
777                    if ( $Nav eq 'None' ) {
778                        $Output .= $LayoutObject->Footer( Type => 'Small' );
779                    }
780                    else {
781                        $Output .= $LayoutObject->Footer();
782                    }
783
784                    return $Output;
785                }
786            }
787            else {
788                $Note .= $LayoutObject->Notify( Priority => 'Error' );
789            }
790        }
791
792        # something has gone wrong
793        my $Output = $NavBar . $Note;
794        $Output .= $Self->_Edit(
795            Nav    => $Nav,
796            Action => 'Add',
797            Source => $Source,
798            Search => $Search,
799            Errors => \%Errors,
800            %GetParam,
801        );
802
803        if ( $Nav eq 'None' ) {
804            $Output .= $LayoutObject->Footer( Type => 'Small' );
805        }
806        else {
807            $Output .= $LayoutObject->Footer();
808        }
809
810        return $Output;
811    }
812
813    # ------------------------------------------------------------ #
814    # overview
815    # ------------------------------------------------------------ #
816    else {
817        $Self->_Overview(
818            Nav    => $Nav,
819            Search => $Search,
820        );
821
822        my $Notification = $ParamObject->GetParam( Param => 'Notification' ) || '';
823        my $Output       = $NavBar;
824        $Output .= $LayoutObject->Notify( Info => Translatable('Customer user updated!') )
825            if ( $Notification && $Notification eq 'Update' );
826
827        $Output .= $LayoutObject->Output(
828            TemplateFile => 'AdminCustomerUser',
829            Data         => \%Param,
830        );
831
832        if ( $Nav eq 'None' ) {
833            $Output .= $LayoutObject->Footer( Type => 'Small' );
834        }
835        else {
836            $Output .= $LayoutObject->Footer();
837        }
838
839        return $Output;
840    }
841}
842
843sub _Overview {
844    my ( $Self, %Param ) = @_;
845
846    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
847
848    $LayoutObject->Block(
849        Name => 'Overview',
850        Data => \%Param,
851    );
852
853    $LayoutObject->Block( Name => 'ActionList' );
854    $LayoutObject->Block(
855        Name => 'ActionSearch',
856        Data => \%Param,
857    );
858
859    my $CustomerUserObject = $Kernel::OM->Get('Kernel::System::CustomerUser');
860
861    # get writable data sources
862    my %CustomerSource = $CustomerUserObject->CustomerSourceList(
863        ReadOnly => 0,
864    );
865
866    # only show Add option if we have at least one writable backend
867    if ( scalar keys %CustomerSource ) {
868        $Param{SourceOption} = $LayoutObject->BuildSelection(
869            Data       => { %CustomerSource, },
870            Name       => 'Source',
871            SelectedID => $Param{Source} || '',
872            Class      => 'Modernize',
873        );
874
875        $LayoutObject->Block(
876            Name => 'ActionAdd',
877            Data => \%Param,
878        );
879    }
880
881    if ( $Param{Search} ) {
882
883        # get config object
884        my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
885
886        # when there is no data to show, a message is displayed on the table with this colspan
887        my $ColSpan = 6;
888
889        # same Limit as $Self->{CustomerUserMap}->{CustomerUserSearchListLimit}
890        # smallest Limit from all sources
891        my $Limit = 400;
892        SOURCE:
893        for my $Count ( '', 1 .. 10 ) {
894            next SOURCE if !$ConfigObject->Get("CustomerUser$Count");
895            my $CustomerUserMap = $ConfigObject->Get("CustomerUser$Count");
896            next SOURCE if !$CustomerUserMap->{CustomerUserSearchListLimit};
897            if ( $CustomerUserMap->{CustomerUserSearchListLimit} < $Limit ) {
898                $Limit = $CustomerUserMap->{CustomerUserSearchListLimit};
899            }
900        }
901
902        my %ListAllItems = $CustomerUserObject->CustomerSearch(
903            Search => $Param{Search},
904            Limit  => $Limit + 1,
905            Valid  => 0,
906        );
907
908        if ( keys %ListAllItems <= $Limit ) {
909            my $ListAllItems = keys %ListAllItems;
910            $LayoutObject->Block(
911                Name => 'OverviewHeader',
912                Data => {
913                    ListAll => $ListAllItems,
914                    Limit   => $Limit,
915                },
916            );
917        }
918
919        my %List = $CustomerUserObject->CustomerSearch(
920            Search => $Param{Search},
921            Valid  => 0,
922        );
923
924        if ( keys %ListAllItems > $Limit ) {
925            my $ListAllItems   = keys %ListAllItems;
926            my $SearchListSize = keys %List;
927
928            $LayoutObject->Block(
929                Name => 'OverviewHeader',
930                Data => {
931                    SearchListSize => $SearchListSize,
932                    ListAll        => $ListAllItems,
933                    Limit          => $Limit,
934                },
935            );
936        }
937
938        $LayoutObject->Block(
939            Name => 'OverviewResult',
940            Data => \%Param,
941        );
942
943        if ( $ConfigObject->Get('SwitchToCustomer') && $Self->{SwitchToCustomerPermission} && $Param{Nav} ne 'None' )
944        {
945            $ColSpan = 7;
946            $LayoutObject->Block(
947                Name => 'OverviewResultSwitchToCustomer',
948            );
949        }
950
951        # if there are results to show
952        if (%List) {
953
954            # get valid list
955            my %ValidList = $Kernel::OM->Get('Kernel::System::Valid')->ValidList();
956            for my $ListKey ( sort { lc($a) cmp lc($b) } keys %List ) {
957
958                my %UserData = $CustomerUserObject->CustomerUserDataGet( User => $ListKey );
959                $UserData{UserFullname} = $CustomerUserObject->CustomerName(
960                    UserLogin => $UserData{UserLogin},
961                );
962
963                $LayoutObject->Block(
964                    Name => 'OverviewResultRow',
965                    Data => {
966                        Valid       => $ValidList{ $UserData{ValidID} || '' } || '-',
967                        Search      => $Param{Search},
968                        CustomerKey => $ListKey,
969                        %UserData,
970                    },
971                );
972                if ( $Param{Nav} eq 'None' ) {
973                    $LayoutObject->Block(
974                        Name => 'OverviewResultRowLinkNone',
975                        Data => {
976                            Search      => $Param{Search},
977                            CustomerKey => $ListKey,
978                            %UserData,
979                        },
980                    );
981                }
982                else {
983                    $LayoutObject->Block(
984                        Name => 'OverviewResultRowLink',
985                        Data => {
986                            Search      => $Param{Search},
987                            Nav         => $Param{Nav},
988                            CustomerKey => $ListKey,
989                            %UserData,
990                        },
991                    );
992                }
993
994                if (
995                    $ConfigObject->Get('SwitchToCustomer')
996                    && $Self->{SwitchToCustomerPermission}
997                    && $Param{Nav} ne 'None'
998                    )
999                {
1000                    $LayoutObject->Block(
1001                        Name => 'OverviewResultRowSwitchToCustomer',
1002                        Data => {
1003                            Search => $Param{Search},
1004                            %UserData,
1005                        },
1006                    );
1007                }
1008            }
1009        }
1010
1011        # otherwise it displays a no data found message
1012        else {
1013            $LayoutObject->Block(
1014                Name => 'NoDataFoundMsg',
1015                Data => {
1016                    ColSpan => $ColSpan,
1017                },
1018            );
1019        }
1020    }
1021
1022    # if there is nothing to search it shows a message
1023    else
1024    {
1025        $LayoutObject->Block(
1026            Name => 'NoSearchTerms',
1027            Data => {},
1028        );
1029    }
1030
1031    $LayoutObject->AddJSData(
1032        Key   => 'Nav',
1033        Value => $Param{Nav},
1034    );
1035
1036    return;
1037}
1038
1039sub _Edit {
1040    my ( $Self, %Param ) = @_;
1041
1042    # Get layout object.
1043    my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
1044
1045    my $Output = '';
1046
1047    $LayoutObject->Block(
1048        Name => 'Overview',
1049        Data => \%Param,
1050    );
1051
1052    $LayoutObject->Block( Name => 'ActionList' );
1053    $LayoutObject->Block(
1054        Name => 'ActionOverview',
1055        Data => \%Param,
1056    );
1057
1058    $LayoutObject->Block(
1059        Name => 'OverviewUpdate',
1060        Data => \%Param,
1061    );
1062
1063    if ( $Param{Action} eq 'Change' ) {
1064
1065        # shows edit header
1066        $LayoutObject->Block( Name => 'HeaderEdit' );
1067
1068        # shows effective permissions matrix
1069        $Self->_EffectivePermissions(%Param);
1070    }
1071
1072    # shows add header
1073    else {
1074        $LayoutObject->Block( Name => 'HeaderAdd' );
1075    }
1076
1077    my $UpdateOnlyPreferences;
1078
1079    # Get config object
1080    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
1081
1082    # update user
1083    if ( $ConfigObject->Get( $Param{Source} )->{ReadOnly} || $ConfigObject->Get( $Param{Source} )->{Module} =~ /LDAP/i )
1084    {
1085        $UpdateOnlyPreferences = 1;
1086    }
1087
1088    # Get dynamic field backend object.
1089    my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
1090    my $ParamObject               = $Kernel::OM->Get('Kernel::System::Web::Request');
1091
1092    ENTRY:
1093    for my $Entry ( @{ $ConfigObject->Get( $Param{Source} )->{Map} } ) {
1094        next ENTRY if !$Entry->[0];
1095
1096        # Handle dynamic fields
1097        if ( $Entry->[5] eq 'dynamic_field' ) {
1098
1099            my $DynamicFieldConfig = $Self->{DynamicFieldLookup}->{ $Entry->[2] };
1100
1101            next ENTRY if !IsHashRefWithData($DynamicFieldConfig);
1102
1103            # Get HTML for dynamic field
1104            my $DynamicFieldHTML = $DynamicFieldBackendObject->EditFieldRender(
1105                DynamicFieldConfig => $DynamicFieldConfig,
1106                Value              => $Param{ $Entry->[0] } ? $Param{ $Entry->[0] } : undef,
1107                Mandatory          => $Entry->[4],
1108                LayoutObject       => $LayoutObject,
1109                ParamObject        => $ParamObject,
1110
1111                # Server error, if any
1112                %{ $Param{Errors}->{ $Entry->[0] } },
1113            );
1114
1115            # skip fields for which HTML could not be retrieved
1116            next ENTRY if !IsHashRefWithData($DynamicFieldHTML);
1117
1118            $LayoutObject->Block(
1119                Name => 'Item',
1120                Data => {},
1121            );
1122
1123            $LayoutObject->Block(
1124                Name => 'DynamicField',
1125                Data => {
1126                    Name  => $DynamicFieldConfig->{Name},
1127                    Label => $DynamicFieldHTML->{Label},
1128                    Field => $DynamicFieldHTML->{Field},
1129                },
1130            );
1131
1132            next ENTRY;
1133        }
1134
1135        my $Block = 'Input';
1136
1137        # check input type
1138        if ( $Entry->[0] =~ /^UserPasswor/i ) {
1139            $Block = 'Password';
1140        }
1141
1142        # check if login auto creation
1143        if ( $ConfigObject->Get( $Param{Source} )->{AutoLoginCreation} && $Entry->[0] eq 'UserLogin' ) {
1144            $Block = 'InputHidden';
1145        }
1146
1147        if ( $Entry->[7] || $UpdateOnlyPreferences ) {
1148            $Param{ReadOnly} = 1;
1149        }
1150        else {
1151            $Param{ReadOnly} = 0;
1152        }
1153
1154        # show required flag
1155        if ( $Entry->[4] ) {
1156            $Param{RequiredClass}          = 'Validate_Required';
1157            $Param{RequiredLabelClass}     = 'Mandatory';
1158            $Param{RequiredLabelCharacter} = '*';
1159        }
1160        else {
1161            $Param{RequiredClass}          = '';
1162            $Param{RequiredLabelClass}     = '';
1163            $Param{RequiredLabelCharacter} = '';
1164        }
1165
1166        # set empty string
1167        $Param{Errors}->{ $Entry->[0] . 'Invalid' } ||= '';
1168
1169        # add class to validate emails
1170        if ( $Entry->[0] eq 'UserEmail' ) {
1171            $Param{RequiredClass} .= ' Validate_Email';
1172        }
1173
1174        # build selections or input fields
1175        if ( $ConfigObject->Get( $Param{Source} )->{Selections}->{ $Entry->[0] } ) {
1176            $Block = 'Option';
1177
1178            # Change the validation class
1179            if ( $Param{RequiredClass} ) {
1180                $Param{RequiredClass} = 'Validate_Required';
1181            }
1182
1183            # get the data of the current selection
1184            my $SelectionsData = $ConfigObject->Get( $Param{Source} )->{Selections}->{ $Entry->[0] };
1185
1186            # make sure the encoding stamp is set
1187            for my $Key ( sort keys %{$SelectionsData} ) {
1188                $SelectionsData->{$Key}
1189                    = $Kernel::OM->Get('Kernel::System::Encode')->EncodeInput( $SelectionsData->{$Key} );
1190            }
1191
1192            # build option string
1193            $Param{Option} = $LayoutObject->BuildSelection(
1194                Data        => $SelectionsData,
1195                Name        => $Entry->[0],
1196                Translation => 1,
1197                SelectedID  => $Param{ $Entry->[0] },
1198                Class       => "$Param{RequiredClass} Modernize " . $Param{Errors}->{ $Entry->[0] . 'Invalid' },
1199                Disabled    => $UpdateOnlyPreferences ? 1 : 0,
1200            );
1201        }
1202        elsif ( $Entry->[0] =~ /^ValidID/i ) {
1203
1204            # Change the validation class
1205            if ( $Param{RequiredClass} ) {
1206                $Param{RequiredClass} = 'Validate_Required';
1207            }
1208
1209            # build ValidID string
1210            $Block = 'Option';
1211            $Param{Option} = $LayoutObject->BuildSelection(
1212                Data       => { $Kernel::OM->Get('Kernel::System::Valid')->ValidList(), },
1213                Name       => $Entry->[0],
1214                SelectedID => defined( $Param{ $Entry->[0] } ) ? $Param{ $Entry->[0] } : 1,
1215                Class      => "$Param{RequiredClass} Modernize " . $Param{Errors}->{ $Entry->[0] . 'Invalid' },
1216                Disabled   => $UpdateOnlyPreferences ? 1 : 0,
1217            );
1218        }
1219        elsif (
1220            $Entry->[0] =~ /^UserCustomerID$/i
1221            && $ConfigObject->Get( $Param{Source} )->{CustomerCompanySupport}
1222            )
1223        {
1224            my $CustomerCompanyObject = $Kernel::OM->Get('Kernel::System::CustomerCompany');
1225            my %CompanyList           = (
1226                $CustomerCompanyObject->CustomerCompanyList( Limit => 0 ),
1227                '' => '-',
1228            );
1229            if ( $Param{ $Entry->[0] } ) {
1230                my %Company = $CustomerCompanyObject->CustomerCompanyGet(
1231                    CustomerID => $Param{ $Entry->[0] },
1232                );
1233                if ( !%Company ) {
1234                    $CompanyList{ $Param{ $Entry->[0] } } = $Param{ $Entry->[0] } . ' (-)';
1235                }
1236            }
1237            $Block = 'Option';
1238
1239            # Change the validation class
1240            if ( $Param{RequiredClass} ) {
1241                $Param{RequiredClass} = 'Validate_Required';
1242            }
1243
1244            my $UseAutoComplete = $Kernel::OM->Get('Kernel::Config')->Get('AdminCustomerUser::UseAutoComplete');
1245
1246            if ($UseAutoComplete) {
1247
1248                my $Value = $Param{ $Entry->[0] } || $Param{CustomerID};
1249                $Param{Option} = '<input type="text" id="UserCustomerID" name="UserCustomerID" value="' . $Value . '"
1250                    class="W50pc CustomerAutoCompleteSimple '
1251                    . $Param{RequiredClass} . ' '
1252                    . $Param{Errors}->{ $Entry->[0] . 'Invalid' }
1253                    . '" data-customer-search-type="CustomerID" />';
1254            }
1255            else {
1256                $Param{Option} = $LayoutObject->BuildSelection(
1257                    Data       => \%CompanyList,
1258                    Name       => $Entry->[0],
1259                    Max        => 80,
1260                    SelectedID => $Param{ $Entry->[0] } || $Param{CustomerID},
1261                    Class      => "$Param{RequiredClass} Modernize " . $Param{Errors}->{ $Entry->[0] . 'Invalid' },
1262                    Disabled   => $UpdateOnlyPreferences ? 1 : 0,
1263                );
1264            }
1265        }
1266        elsif ( $Param{Action} eq 'Add' && $Entry->[0] =~ /^UserCustomerID$/i ) {
1267
1268            # Use CustomerID param if called from CIC.
1269            $Param{Value} = $Param{ $Entry->[0] } || $Param{CustomerID} || '';
1270        }
1271        else {
1272            $Param{Value} = $Param{ $Entry->[0] } || '';
1273        }
1274
1275        # add form option
1276        if ( $Param{Type} && $Param{Type} eq 'hidden' ) {
1277            $Param{Preferences} .= $Param{Value};
1278        }
1279        else {
1280            $LayoutObject->Block(
1281                Name => 'PreferencesGeneric',
1282                Data => {
1283                    Item => $Entry->[1],
1284                    %Param
1285                },
1286            );
1287            $LayoutObject->Block(
1288                Name => "PreferencesGeneric$Block",
1289                Data => {
1290                    Item         => $Entry->[1],
1291                    Name         => $Entry->[0],
1292                    InvalidField => $Param{Errors}->{ $Entry->[0] . 'Invalid' } || '',
1293                    %Param,
1294                },
1295            );
1296
1297            # add the correct client side error msg
1298            if ( $Block eq 'Input' && $Entry->[0] eq 'UserEmail' ) {
1299                $LayoutObject->Block(
1300                    Name => 'PreferencesUserEmailErrorMsg',
1301                    Data => { Name => $Entry->[0] },
1302                );
1303            }
1304            else {
1305                $LayoutObject->Block(
1306                    Name => "PreferencesGenericErrorMsg",
1307                    Data => { Name => $Entry->[0] },
1308                );
1309            }
1310
1311            # add the correct server error msg
1312            if ( $Block eq 'Input' && $Param{UserEmail} && $Entry->[0] eq 'UserEmail' ) {
1313
1314                # display server error msg according with the occurred email error type
1315                $LayoutObject->Block(
1316                    Name => 'PreferencesUserEmail' . ( $Param{Errors}->{ErrorType} || '' ),
1317                    Data => { Name => $Entry->[0] },
1318                );
1319            }
1320            else {
1321                $LayoutObject->Block(
1322                    Name => "PreferencesGenericServerErrorMsg",
1323                    Data => { Name => $Entry->[0] },
1324                );
1325            }
1326        }
1327    }
1328
1329    my $PreferencesUsed = $ConfigObject->Get( $Param{Source} )->{AdminSetPreferences};
1330    if ( ( defined $PreferencesUsed && $PreferencesUsed != 0 ) || !defined $PreferencesUsed ) {
1331
1332        my %Data;
1333        my %Preferences = %{ $ConfigObject->Get('CustomerPreferencesGroups') };
1334
1335        GROUP:
1336        for my $Group ( sort keys %Preferences ) {
1337
1338            next GROUP if !$Group;
1339
1340            my $PreferencesGroup = $Preferences{$Group};
1341
1342            next GROUP if !$PreferencesGroup;
1343            next GROUP if ref $PreferencesGroup ne 'HASH';
1344
1345            if ( $Data{ $PreferencesGroup->{Prio} } ) {
1346
1347                COUNT:
1348                for ( 1 .. 151 ) {
1349
1350                    $PreferencesGroup->{Prio}++;
1351
1352                    if ( !$Data{ $PreferencesGroup->{Prio} } ) {
1353                        $Data{ $PreferencesGroup->{Prio} } = $Group;
1354                        last COUNT;
1355                    }
1356                }
1357            }
1358
1359            $Data{ $PreferencesGroup->{Prio} } = $Group;
1360        }
1361
1362        # sort
1363        for my $Key ( sort keys %Data ) {
1364            $Data{ sprintf "%07d", $Key } = $Data{$Key};
1365            delete $Data{$Key};
1366        }
1367
1368        # show each preferences setting
1369        PRIO:
1370        for my $Prio ( sort keys %Data ) {
1371
1372            my $Group = $Data{$Prio};
1373            if ( !$ConfigObject->{CustomerPreferencesGroups}->{$Group} ) {
1374                next PRIO;
1375            }
1376
1377            my %Preference = %{ $ConfigObject->{CustomerPreferencesGroups}->{$Group} };
1378            if ( $Group eq 'Password' ) {
1379                next PRIO;
1380            }
1381
1382            my $Module = $Preference{Module}
1383                || 'Kernel::Output::HTML::CustomerPreferencesGeneric';
1384
1385            # load module
1386            if ( $Kernel::OM->Get('Kernel::System::Main')->Require($Module) ) {
1387                my $Object = $Module->new(
1388                    %{$Self},
1389                    ConfigItem => \%Preference,
1390                    UserObject => $Kernel::OM->Get('Kernel::System::CustomerUser'),
1391                    Debug      => $Self->{Debug},
1392                );
1393                my @Params = $Object->Param( UserData => \%Param );
1394                if (@Params) {
1395                    for my $ParamItem (@Params) {
1396                        $LayoutObject->Block(
1397                            Name => 'Item',
1398                            Data => {%Param},
1399                        );
1400                        if (
1401                            ref $ParamItem->{Data} eq 'HASH'
1402                            || ref $Preference{Data} eq 'HASH'
1403                            )
1404                        {
1405                            my %BuildSelectionParams = (
1406                                %Preference,
1407                                %{$ParamItem},
1408                            );
1409                            $BuildSelectionParams{Class} = join( ' ', $BuildSelectionParams{Class} // '', 'Modernize' );
1410
1411                            $ParamItem->{Option} = $LayoutObject->BuildSelection(
1412                                %BuildSelectionParams,
1413                            );
1414                        }
1415
1416                        $LayoutObject->Block(
1417                            Name => $ParamItem->{Block} || $Preference{Block} || 'Option',
1418                            Data => {
1419                                Group => $Group,
1420                                %Param,
1421                                %Data,
1422                                %Preference,
1423                                %{$ParamItem},
1424                            },
1425                        );
1426                    }
1427                }
1428            }
1429            else {
1430                return $LayoutObject->FatalError();
1431            }
1432        }
1433    }
1434
1435    $LayoutObject->AddJSData(
1436        Key   => 'Nav',
1437        Value => $Param{Nav},
1438    );
1439
1440    return $LayoutObject->Output(
1441        TemplateFile => 'AdminCustomerUser',
1442        Data         => \%Param,
1443    );
1444}
1445
1446sub _EffectivePermissions {
1447    my ( $Self, %Param ) = @_;
1448
1449    # only if customer group feature is active
1450    if ( !$Kernel::OM->Get('Kernel::Config')->Get('CustomerGroupSupport') ) {
1451        return 1;
1452    }
1453
1454    # get needed objects
1455    my $ConfigObject        = $Kernel::OM->Get('Kernel::Config');
1456    my $LayoutObject        = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
1457    my $CustomerGroupObject = $Kernel::OM->Get('Kernel::System::CustomerGroup');
1458
1459    # show tables
1460    $LayoutObject->Block(
1461        Name => 'EffectivePermissions',
1462    );
1463
1464    my %Groups;
1465    my %Permissions;
1466
1467    # go through permission types
1468    my @Types = @{ $ConfigObject->Get('System::Customer::Permission') };
1469    for my $Type (@Types) {
1470
1471        # show header
1472        $LayoutObject->Block(
1473            Name => "HeaderGroupPermissionType",
1474            Data => {
1475                Type => $Type,
1476            },
1477        );
1478
1479        # get groups of the user
1480        my %UserGroups = $CustomerGroupObject->GroupMemberList(
1481            UserID         => $Param{ID},
1482            Type           => $Type,
1483            Result         => 'HASH',
1484            RawPermissions => 0,            # get effective permissions
1485        );
1486
1487        # store data in lookup hashes
1488        for my $GroupID ( sort keys %UserGroups ) {
1489            $Groups{$GroupID} = $UserGroups{$GroupID};
1490            $Permissions{$GroupID}{$Type} = 1;
1491        }
1492    }
1493
1494    # show message if no permissions found
1495    if ( !%Permissions ) {
1496        $LayoutObject->Block(
1497            Name => 'NoGroupPermissionsFoundMsg',
1498        );
1499    }
1500
1501    # go through groups, sort by name
1502    else {
1503        for my $GroupID ( sort { uc( $Groups{$a} ) cmp uc( $Groups{$b} ) } keys %Groups ) {
1504
1505            # show table rows
1506            $LayoutObject->Block(
1507                Name => 'GroupPermissionTableRow',
1508                Data => {
1509                    ID   => $GroupID,
1510                    Name => $Groups{$GroupID},
1511                },
1512            );
1513
1514            # show permission marks
1515            for my $Type (@Types) {
1516                my $PermissionMark = $Permissions{$GroupID}{$Type} ? 'On'        : 'Off';
1517                my $HighlightMark  = $Type eq 'rw'                 ? 'Highlight' : '';
1518                $LayoutObject->Block(
1519                    Name => 'GroupPermissionMark',
1520                );
1521                $LayoutObject->Block(
1522                    Name => 'GroupPermissionMark' . $PermissionMark,
1523                    Data => {
1524                        Highlight => $HighlightMark,
1525                    },
1526                );
1527            }
1528        }
1529    }
1530
1531    # get all accessible customers of the user
1532    my %Customers = $CustomerGroupObject->GroupContextCustomers(
1533        CustomerUserID => $Param{ID},
1534    );
1535
1536    # show message if no customers found
1537    if ( !%Customers ) {
1538        $LayoutObject->Block(
1539            Name => 'NoCustomerAccessFoundMsg',
1540        );
1541        return 1;
1542    }
1543
1544    # get permission contexts
1545    my $ContextConfig            = $ConfigObject->Get('CustomerGroupPermissionContext');
1546    my $DirectAccessContextKey   = '001-CustomerID-same';
1547    my $IndirectAccessContextKey = '100-CustomerID-other';
1548
1549    # use default context if none are found
1550    if ( !IsHashRefWithData($ContextConfig) ) {
1551        $ContextConfig = {
1552            $DirectAccessContextKey => {
1553                Name => Translatable('Same Customer'),
1554            },
1555        };
1556    }
1557
1558    # show default and extra context headers if available
1559    if ( $ContextConfig->{$DirectAccessContextKey} ) {
1560        $LayoutObject->Block(
1561            Name => 'HeaderCustomerAccessContext',
1562            Data => {
1563                Name => Translatable('Direct'),
1564            },
1565        );
1566    }
1567    if ( $ContextConfig->{$IndirectAccessContextKey} ) {
1568        $LayoutObject->Block(
1569            Name => 'HeaderCustomerAccessContext',
1570            Data => {
1571                Name => Translatable('Indirect'),
1572            },
1573        );
1574    }
1575
1576    # determine customers for direct and indirect access
1577    my @UserCustomerIDs = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerIDs(
1578        User => $Param{ID},
1579    );
1580    my %ExtraCustomerIDs;
1581    if ( $ContextConfig->{$IndirectAccessContextKey} ) {
1582        my $ExtraContextName = $CustomerGroupObject->GroupContextNameGet(
1583            SysConfigName => $IndirectAccessContextKey,
1584        );
1585
1586        # for all CustomerIDs get groups with extra access
1587        my %ExtraPermissionGroups;
1588        CUSTOMERID:
1589        for my $CustomerID (@UserCustomerIDs) {
1590            my %GroupList = $CustomerGroupObject->GroupCustomerList(
1591                CustomerID => $CustomerID,
1592                Type       => 'ro',
1593                Context    => $ExtraContextName,
1594                Result     => 'HASH',
1595            );
1596            next CUSTOMERID if !%GroupList;
1597
1598            # add to groups
1599            %ExtraPermissionGroups = (
1600                %ExtraPermissionGroups,
1601                %GroupList,
1602            );
1603        }
1604
1605        # add all unique accessible Group<->Customer combinations
1606        GROUPID:
1607        for my $GroupID ( sort keys %ExtraPermissionGroups ) {
1608            my @GroupCustomerIDs = $CustomerGroupObject->GroupCustomerList(
1609                GroupID => $GroupID,
1610                Type    => 'ro',
1611                Result  => 'ID',
1612            );
1613            next GROUPID if !@GroupCustomerIDs;
1614
1615            # add to ExtraCustomerIDs
1616            %ExtraCustomerIDs = (
1617                %ExtraCustomerIDs,
1618                map { $_ => 1 } @GroupCustomerIDs,
1619            );
1620        }
1621    }
1622
1623    # go through customers
1624    CUSTOMERID:
1625    for my $CustomerID ( sort keys %Customers ) {
1626
1627        # show table rows
1628        $LayoutObject->Block(
1629            Name => 'CustomerAccessTableRow',
1630            Data => {
1631                ID   => $CustomerID,
1632                Name => $Customers{$CustomerID},
1633            },
1634        );
1635
1636        # 'Same Customer'
1637        if ( $ContextConfig->{$DirectAccessContextKey} ) {
1638
1639            # check if we should show check mark for 'Same Customer'
1640            my $AccessMark = ( grep { $_ eq $CustomerID } @UserCustomerIDs ) ? 'On' : 'Off';
1641
1642            # show blocks
1643            $LayoutObject->Block(
1644                Name => 'CustomerAccessMark',
1645            );
1646            $LayoutObject->Block(
1647                Name => 'CustomerAccessMark' . $AccessMark,
1648            );
1649        }
1650
1651        # 'Other Customers'
1652        next CUSTOMERID if !$ContextConfig->{$IndirectAccessContextKey};
1653
1654        # check if we should show check mark for 'Other Customers'
1655        my $AccessMark = $ExtraCustomerIDs{$CustomerID} ? 'On' : 'Off';
1656
1657        # show blocks
1658        $LayoutObject->Block(
1659            Name => 'CustomerAccessMark',
1660        );
1661        $LayoutObject->Block(
1662            Name => 'CustomerAccessMark' . $AccessMark,
1663        );
1664    }
1665
1666    return 1;
1667}
1668
16691;
1670