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