Files
scripts/Perl OTRS/Kernel/Modules/AdminCustomerUser.pm
2024-10-14 00:08:40 +02:00

1670 lines
57 KiB
Perl

# --
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (GPL). If you
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
# --
package Kernel::Modules::AdminCustomerUser;
use strict;
use warnings;
use Kernel::System::CheckItem;
use Kernel::System::VariableCheck qw(:all);
use Kernel::Language qw(Translatable);
our $ObjectManagerDisabled = 1;
sub new {
my ( $Type, %Param ) = @_;
# allocate new hash for object
my $Self = {%Param};
bless( $Self, $Type );
my $DynamicFieldConfigs = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
ObjectType => 'CustomerUser',
);
$Self->{DynamicFieldLookup} = { map { $_->{Name} => $_ } @{$DynamicFieldConfigs} };
return $Self;
}
sub Run {
my ( $Self, %Param ) = @_;
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
my $Nav = $ParamObject->GetParam( Param => 'Nav' ) || '';
my $Source = $ParamObject->GetParam( Param => 'Source' ) || 'CustomerUser';
my $Search = $ParamObject->GetParam( Param => 'Search' );
$Search
||= $ConfigObject->Get('AdminCustomerUser::RunInitialWildcardSearch') ? '*' : '';
# create local object
my $CheckItemObject = $Kernel::OM->Get('Kernel::System::CheckItem');
my $NavBar = '';
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
if ( $Nav eq 'None' ) {
$NavBar = $LayoutObject->Header( Type => 'Small' );
}
else {
$NavBar = $LayoutObject->Header();
$NavBar .= $LayoutObject->NavigationBar(
Type => $Nav eq 'Agent' ? 'Customers' : 'Admin',
);
}
# Get list of valid IDs.
my @ValidIDList = $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet();
# check the permission for the SwitchToCustomer feature
if ( $ConfigObject->Get('SwitchToCustomer') ) {
my $GroupObject = $Kernel::OM->Get('Kernel::System::Group');
# get the group id which is allowed to use the switch to customer feature
my $SwitchToCustomerGroupID = $GroupObject->GroupLookup(
Group => $ConfigObject->Get('SwitchToCustomer::PermissionGroup'),
);
# get user groups, where the user has the rw privilege
my %Groups = $GroupObject->PermissionUserGet(
UserID => $Self->{UserID},
Type => 'rw',
);
# if the user is a member in this group he can access the feature
if ( $Groups{$SwitchToCustomerGroupID} ) {
$Self->{SwitchToCustomerPermission} = 1;
}
}
my $CustomerUserObject = $Kernel::OM->Get('Kernel::System::CustomerUser');
my $MainObject = $Kernel::OM->Get('Kernel::System::Main');
# ------------------------------------------------------------ #
# switch to customer
# ------------------------------------------------------------ #
if (
$Self->{Subaction} eq 'Switch'
&& $ConfigObject->Get('SwitchToCustomer')
&& $Self->{SwitchToCustomerPermission}
)
{
# challenge token check for write action
$LayoutObject->ChallengeTokenCheck();
# get user data
my $UserID = $ParamObject->GetParam( Param => 'ID' ) || '';
my %UserData = $CustomerUserObject->CustomerUserDataGet(
User => $UserID,
Valid => 1,
);
# create new session id
my $NewSessionID = $Kernel::OM->Get('Kernel::System::AuthSession')->CreateSessionID(
%UserData,
UserLastRequest => $Kernel::OM->Create('Kernel::System::DateTime')->ToEpoch(),
UserType => 'Customer',
SessionSource => 'CustomerInterface',
);
# get customer interface session name
my $SessionName = $ConfigObject->Get('CustomerPanelSessionName') || 'CSID';
# create a new LayoutObject with SessionIDCookie
my $Expires = '+' . $ConfigObject->Get('SessionMaxTime') . 's';
if ( !$ConfigObject->Get('SessionUseCookieAfterBrowserClose') ) {
$Expires = '';
}
my $SecureAttribute;
if ( $ConfigObject->Get('HttpType') eq 'https' ) {
# Restrict Cookie to HTTPS if it is used.
$SecureAttribute = 1;
}
my $LayoutObject = Kernel::Output::HTML::Layout->new(
%{$Self},
SetCookies => {
SessionIDCookie => $ParamObject->SetCookie(
Key => $SessionName,
Value => $NewSessionID,
Expires => $Expires,
Path => $ConfigObject->Get('ScriptAlias'),
Secure => scalar $SecureAttribute,
HTTPOnly => 1,
),
},
SessionID => $NewSessionID,
SessionName => $ConfigObject->Get('SessionName'),
);
# log event
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'notice',
Message =>
"Switched from Agent to Customer ($Self->{UserLogin} -=> $UserData{UserLogin})",
);
# build URL to customer interface
my $URL = $ConfigObject->Get('HttpType')
. '://'
. $ConfigObject->Get('FQDN')
. '/'
. $ConfigObject->Get('ScriptAlias')
. 'customer.pl';
# if no sessions are used we attach the session as URL parameter
if ( !$ConfigObject->Get('SessionUseCookie') ) {
$URL .= "?$SessionName=$NewSessionID";
}
# redirect to customer interface with new session id
return $LayoutObject->Redirect( ExtURL => $URL );
}
# search user list
if ( $Self->{Subaction} eq 'Search' ) {
$Self->_Overview(
Nav => $Nav,
Search => $Search,
);
my $Output = $NavBar;
$Output .= $LayoutObject->Output(
TemplateFile => 'AdminCustomerUser',
Data => \%Param,
);
if ( $Nav eq 'None' ) {
$Output .= $LayoutObject->Footer( Type => 'Small' );
}
else {
$Output .= $LayoutObject->Footer();
}
return $Output;
}
# ------------------------------------------------------------ #
# download file preferences
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'Download' ) {
my $Group = $ParamObject->GetParam( Param => 'Group' ) || '';
my $User = $ParamObject->GetParam( Param => 'ID' ) || '';
my $File = $ParamObject->GetParam( Param => 'File' ) || '';
# get user data
my %UserData = $CustomerUserObject->CustomerUserDataGet( User => $User );
my %Preferences = %{ $ConfigObject->Get('CustomerPreferencesGroups') };
my $Module = $Preferences{$Group}->{Module};
if ( !$MainObject->Require($Module) ) {
return $LayoutObject->FatalError();
}
my $Object = $Module->new(
%{$Self},
ConfigItem => $Preferences{$Group},
UserObject => $CustomerUserObject,
Debug => $Self->{Debug},
);
my %File = $Object->Download( UserData => \%UserData );
return $LayoutObject->Attachment(%File);
}
# ------------------------------------------------------------ #
# change
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'Change' ) {
my $User = $ParamObject->GetParam( Param => 'ID' ) || '';
my $Notification = $ParamObject->GetParam( Param => 'Notification' ) || '';
# get user data
my %UserData = $CustomerUserObject->CustomerUserDataGet( User => $User );
my $Output = $NavBar;
$Output .= $LayoutObject->Notify( Info => Translatable('Customer updated!') )
if ( $Notification && $Notification eq 'Update' );
$Output .= $Self->_Edit(
Nav => $Nav,
Action => 'Change',
Source => $Source,
Search => $Search,
ID => $User,
%UserData,
);
if ( $Nav eq 'None' ) {
$Output .= $LayoutObject->Footer( Type => 'Small' );
}
else {
$Output .= $LayoutObject->Footer();
}
return $Output;
}
# ------------------------------------------------------------ #
# change action
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'ChangeAction' ) {
# challenge token check for write action
$LayoutObject->ChallengeTokenCheck();
# update only the preferences and dynamic fields, if the source is readonly or a ldap backend
my $UpdateOnlyPreferences;
if ( $ConfigObject->Get($Source)->{ReadOnly} || $ConfigObject->Get($Source)->{Module} =~ /LDAP/i ) {
$UpdateOnlyPreferences = 1;
}
my $Note = '';
my ( %GetParam, %Errors );
# Get dynamic field backend object.
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
ENTRY:
for my $Entry ( @{ $ConfigObject->Get($Source)->{Map} } ) {
# check dynamic fields
if ( $Entry->[5] eq 'dynamic_field' ) {
my $DynamicFieldConfig = $Self->{DynamicFieldLookup}->{ $Entry->[2] };
if ( !IsHashRefWithData($DynamicFieldConfig) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "DynamicField $Entry->[2] not found!",
);
next ENTRY;
}
my $ValidationResult = $DynamicFieldBackendObject->EditFieldValueValidate(
DynamicFieldConfig => $DynamicFieldConfig,
ParamObject => $ParamObject,
Mandatory => $Entry->[4],
);
if ( $ValidationResult->{ServerError} ) {
$Errors{ $Entry->[0] } = $ValidationResult;
}
else {
# generate storable value of dynamic field edit field
$GetParam{ $Entry->[0] } = $DynamicFieldBackendObject->EditFieldValueGet(
DynamicFieldConfig => $DynamicFieldConfig,
ParamObject => $ParamObject,
LayoutObject => $LayoutObject,
);
}
}
# check remaining non-dynamic-field mandatory fields
else {
$GetParam{ $Entry->[0] } = $ParamObject->GetParam( Param => $Entry->[0] ) || '';
next ENTRY if $UpdateOnlyPreferences;
if ( !$GetParam{ $Entry->[0] } && $Entry->[4] ) {
$Errors{ $Entry->[0] . 'Invalid' } = 'ServerError';
}
}
}
$GetParam{ID} = $ParamObject->GetParam( Param => 'ID' ) || '';
# check email address
if (
!$UpdateOnlyPreferences
&& $GetParam{UserEmail}
&& !$CheckItemObject->CheckEmail( Address => $GetParam{UserEmail} )
&& grep { $_ eq $GetParam{ValidID} } @ValidIDList
)
{
$Errors{UserEmailInvalid} = 'ServerError';
$Errors{ErrorType} = $CheckItemObject->CheckErrorType() . 'ServerErrorMsg';
}
# Get the current user data for some checks.
my %CurrentUserData = $CustomerUserObject->CustomerUserDataGet(
User => $GetParam{ID},
);
# Check CustomerID, if CustomerCompanySupport is enabled and the UserCustomerID was changed.
if (
$ConfigObject->Get($Source)->{CustomerCompanySupport}
&& $GetParam{UserCustomerID}
&& $CurrentUserData{UserCustomerID} ne $GetParam{UserCustomerID}
)
{
my %Company = $Kernel::OM->Get('Kernel::System::CustomerCompany')->CustomerCompanyGet(
CustomerID => $GetParam{UserCustomerID},
);
if ( !%Company ) {
$Errors{UserCustomerIDInvalid} = 'ServerError';
}
}
# if no errors occurred
if ( !%Errors ) {
my $UpdateSuccess;
if ( !$UpdateOnlyPreferences ) {
$UpdateSuccess = $CustomerUserObject->CustomerUserUpdate(
%GetParam,
UserID => $Self->{UserID},
);
}
if ( $UpdateSuccess || $UpdateOnlyPreferences ) {
# set dynamic field values
my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField');
ENTRY:
for my $Entry ( @{ $ConfigObject->Get($Source)->{Map} } ) {
next ENTRY if $Entry->[5] ne 'dynamic_field';
my $DynamicFieldConfig = $Self->{DynamicFieldLookup}->{ $Entry->[2] };
if ( !IsHashRefWithData($DynamicFieldConfig) ) {
$Note .= $LayoutObject->Notify(
Info => $LayoutObject->{LanguageObject}->Translate(
'Dynamic field %s not found!',
$Entry->[2],
),
);
next ENTRY;
}
my $ValueSet = $DynamicFieldBackendObject->ValueSet(
DynamicFieldConfig => $DynamicFieldConfig,
ObjectName => $GetParam{UserLogin},
Value => $GetParam{ $Entry->[0] },
UserID => $Self->{UserID},
);
if ( !$ValueSet ) {
$Note .= $LayoutObject->Notify(
Info => $LayoutObject->{LanguageObject}->Translate(
'Unable to set value for dynamic field %s!',
$Entry->[2],
),
);
next ENTRY;
}
}
# update preferences
my %Preferences = %{ $ConfigObject->Get('CustomerPreferencesGroups') };
GROUP:
for my $Group ( sort keys %Preferences ) {
next GROUP if $Group eq 'Password';
# get user data
my %UserData = $CustomerUserObject->CustomerUserDataGet(
User => $GetParam{UserLogin}
);
my $Module = $Preferences{$Group}->{Module};
if ( !$MainObject->Require($Module) ) {
return $LayoutObject->FatalError();
}
my $Object = $Module->new(
%{$Self},
ConfigItem => $Preferences{$Group},
UserObject => $CustomerUserObject,
Debug => $Self->{Debug},
);
my @Params = $Object->Param( UserData => \%UserData );
if (@Params) {
my %GetParam;
for my $ParamItem (@Params) {
my @Array = $ParamObject->GetArray( Param => $ParamItem->{Name} );
$GetParam{ $ParamItem->{Name} } = \@Array;
}
if (
!$Object->Run(
GetParam => \%GetParam,
UserData => \%UserData
)
)
{
$Note .= $LayoutObject->Notify( Info => $Object->Error() );
}
}
}
# clear customer user cache
$CustomerUserObject->CustomerUserCacheClear(
UserLogin => $GetParam{UserLogin},
);
# get user data and show screen again
if ( !$Note ) {
# if the user would like to continue editing the priority, just redirect to the edit screen
if (
defined $ParamObject->GetParam( Param => 'ContinueAfterSave' )
&& ( $ParamObject->GetParam( Param => 'ContinueAfterSave' ) eq '1' )
)
{
my $ID = $ParamObject->GetParam( Param => 'ID' ) || '';
return $LayoutObject->Redirect(
OP =>
"Action=$Self->{Action};Subaction=Change;ID=$ID;Search=$Search;Nav=$Nav;Notification=Update"
);
}
else {
# otherwise return to overview
return $LayoutObject->Redirect( OP => "Action=$Self->{Action};Notification=Update" );
}
}
}
else {
$Note .= $LayoutObject->Notify( Priority => 'Error' );
}
}
# something has gone wrong
my $Output = $NavBar;
$Output .= $Note;
$Output .= $Self->_Edit(
Nav => $Nav,
Action => 'Change',
Source => $Source,
Search => $Search,
Errors => \%Errors,
%GetParam,
);
if ( $Nav eq 'None' ) {
$Output .= $LayoutObject->Footer( Type => 'Small' );
}
else {
$Output .= $LayoutObject->Footer();
}
return $Output;
}
# ------------------------------------------------------------ #
# add
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'Add' ) {
my %GetParam;
$GetParam{UserLogin} = $ParamObject->GetParam( Param => 'UserLogin' ) || '';
$GetParam{CustomerID} = $ParamObject->GetParam( Param => 'CustomerID' ) || '';
my $Output = $NavBar;
$Output .= $Self->_Edit(
Nav => $Nav,
Action => 'Add',
Source => $Source,
Search => $Search,
%GetParam,
);
if ( $Nav eq 'None' ) {
$Output .= $LayoutObject->Footer( Type => 'Small' );
}
else {
$Output .= $LayoutObject->Footer();
}
return $Output;
}
# ------------------------------------------------------------ #
# add action
# ------------------------------------------------------------ #
elsif ( $Self->{Subaction} eq 'AddAction' ) {
# challenge token check for write action
$LayoutObject->ChallengeTokenCheck();
my $Note = '';
my ( %GetParam, %Errors );
my $AutoLoginCreation = $ConfigObject->Get($Source)->{AutoLoginCreation};
# Get dynamic field backend object.
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
ENTRY:
for my $Entry ( @{ $ConfigObject->Get($Source)->{Map} } ) {
# don't validate UserLogin if AutoLoginCreation is configured
next ENTRY if ( $AutoLoginCreation && $Entry->[0] eq 'UserLogin' );
# check dynamic fields
if ( $Entry->[5] eq 'dynamic_field' ) {
my $DynamicFieldConfig = $Self->{DynamicFieldLookup}->{ $Entry->[2] };
if ( !IsHashRefWithData($DynamicFieldConfig) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "DynamicField $Entry->[2] not found!",
);
next ENTRY;
}
my $ValidationResult = $DynamicFieldBackendObject->EditFieldValueValidate(
DynamicFieldConfig => $DynamicFieldConfig,
ParamObject => $ParamObject,
Mandatory => $Entry->[4],
);
if ( $ValidationResult->{ServerError} ) {
$Errors{ $Entry->[0] } = $ValidationResult;
}
else {
# generate storable value of dynamic field edit field
$GetParam{ $Entry->[0] } = $DynamicFieldBackendObject->EditFieldValueGet(
DynamicFieldConfig => $DynamicFieldConfig,
ParamObject => $ParamObject,
LayoutObject => $LayoutObject,
);
}
}
# check remaining non-dynamic-field mandatory fields
else {
$GetParam{ $Entry->[0] } = $ParamObject->GetParam( Param => $Entry->[0] ) || '';
if ( !$GetParam{ $Entry->[0] } && $Entry->[4] ) {
$Errors{ $Entry->[0] . 'Invalid' } = 'ServerError';
}
}
}
# check email address
if (
$GetParam{UserEmail}
&& !$CheckItemObject->CheckEmail( Address => $GetParam{UserEmail} )
&& grep { $_ eq $GetParam{ValidID} } @ValidIDList
)
{
$Errors{UserEmailInvalid} = 'ServerError';
$Errors{ErrorType} = $CheckItemObject->CheckErrorType() . 'ServerErrorMsg';
}
# Check CustomerID, if CustomerCompanySupport is enabled.
if ( $ConfigObject->Get($Source)->{CustomerCompanySupport} && $GetParam{UserCustomerID} ) {
my %Company = $Kernel::OM->Get('Kernel::System::CustomerCompany')->CustomerCompanyGet(
CustomerID => $GetParam{UserCustomerID},
);
if ( !%Company ) {
$Errors{UserCustomerIDInvalid} = 'ServerError';
}
}
# if no errors occurred
if ( !%Errors ) {
# add user
my $User = $CustomerUserObject->CustomerUserAdd(
%GetParam,
UserID => $Self->{UserID},
Source => $Source
);
if ($User) {
# set dynamic field values
my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField');
ENTRY:
for my $Entry ( @{ $ConfigObject->Get($Source)->{Map} } ) {
next ENTRY if $Entry->[5] ne 'dynamic_field';
my $DynamicFieldConfig = $Self->{DynamicFieldLookup}->{ $Entry->[2] };
if ( !IsHashRefWithData($DynamicFieldConfig) ) {
$Note .= $LayoutObject->Notify(
Info => $LayoutObject->{LanguageObject}->Translate(
'Dynamic field %s not found!',
$Entry->[2],
),
);
next ENTRY;
}
my $ValueSet = $DynamicFieldBackendObject->ValueSet(
DynamicFieldConfig => $DynamicFieldConfig,
ObjectName => $User,
Value => $GetParam{ $Entry->[0] },
UserID => $Self->{UserID},
);
if ( !$ValueSet ) {
$Note .= $LayoutObject->Notify(
Info => $LayoutObject->{LanguageObject}->Translate(
'Unable to set value for dynamic field %s!',
$Entry->[2],
),
);
next ENTRY;
}
}
# update preferences
my %Preferences = %{ $ConfigObject->Get('CustomerPreferencesGroups') };
GROUP:
for my $Group ( sort keys %Preferences ) {
next GROUP if $Group eq 'Password';
# get user data
my %UserData = $CustomerUserObject->CustomerUserDataGet(
User => $User,
);
my $Module = $Preferences{$Group}->{Module};
if ( !$MainObject->Require($Module) ) {
return $LayoutObject->FatalError();
}
my $Object = $Module->new(
%{$Self},
ConfigItem => $Preferences{$Group},
UserObject => $CustomerUserObject,
Debug => $Self->{Debug},
);
my @Params = $Object->Param( %{ $Preferences{$Group} }, UserData => \%UserData );
if (@Params) {
my %GetParam;
for my $ParamItem (@Params) {
my @Array = $ParamObject->GetArray( Param => $ParamItem->{Name} );
$GetParam{ $ParamItem->{Name} } = \@Array;
}
if (
!$Object->Run(
GetParam => \%GetParam,
UserData => \%UserData
)
)
{
$Note .= $LayoutObject->Notify( Info => $Object->Error() );
}
}
}
# get user data and show screen again
if ( !$Note ) {
# in borrowed view, take the new created customer over into the new ticket
if ( $Nav eq 'None' ) {
my $Output = $NavBar;
$LayoutObject->AddJSData(
Key => 'Customer',
Value => $User,
);
$LayoutObject->AddJSData(
Key => 'Nav',
Value => $Nav,
);
$Output .= $LayoutObject->Output(
TemplateFile => 'AdminCustomerUser',
Data => \%Param,
);
$Output .= $LayoutObject->Footer( Type => 'Small' );
return $Output;
}
$Self->_Overview(
Nav => $Nav,
Search => $Search,
);
my $Output = $NavBar . $Note;
my $URL = '';
my $UserHTMLQuote = $LayoutObject->LinkEncode($User);
my $UserQuote = $LayoutObject->Ascii2Html( Text => $User );
if ( $ConfigObject->Get('Frontend::Module')->{AgentTicketPhone} ) {
$URL
.= "<a href=\"$LayoutObject->{Baselink}Action=AgentTicketPhone;Subaction=StoreNew;ExpandCustomerName=2;CustomerUser=$UserHTMLQuote;$LayoutObject->{ChallengeTokenParam}\">"
. $LayoutObject->{LanguageObject}->Translate('New phone ticket')
. "</a>";
}
if ( $ConfigObject->Get('Frontend::Module')->{AgentTicketEmail} ) {
if ($URL) {
$URL .= " - ";
}
$URL
.= "<a href=\"$LayoutObject->{Baselink}Action=AgentTicketEmail;Subaction=StoreNew;ExpandCustomerName=2;CustomerUser=$UserHTMLQuote;$LayoutObject->{ChallengeTokenParam}\">"
. $LayoutObject->{LanguageObject}->Translate('New email ticket')
. "</a>";
}
if ($URL) {
$Output
.= $LayoutObject->Notify(
Data => $LayoutObject->{LanguageObject}->Translate(
'Customer %s added',
$UserQuote,
)
. " ( $URL )!",
);
}
else {
$Output
.= $LayoutObject->Notify(
Data => $LayoutObject->{LanguageObject}->Translate(
'Customer %s added',
$UserQuote,
)
. "!",
);
}
$Output .= $LayoutObject->Output(
TemplateFile => 'AdminCustomerUser',
Data => \%Param,
);
if ( $Nav eq 'None' ) {
$Output .= $LayoutObject->Footer( Type => 'Small' );
}
else {
$Output .= $LayoutObject->Footer();
}
return $Output;
}
}
else {
$Note .= $LayoutObject->Notify( Priority => 'Error' );
}
}
# something has gone wrong
my $Output = $NavBar . $Note;
$Output .= $Self->_Edit(
Nav => $Nav,
Action => 'Add',
Source => $Source,
Search => $Search,
Errors => \%Errors,
%GetParam,
);
if ( $Nav eq 'None' ) {
$Output .= $LayoutObject->Footer( Type => 'Small' );
}
else {
$Output .= $LayoutObject->Footer();
}
return $Output;
}
# ------------------------------------------------------------ #
# overview
# ------------------------------------------------------------ #
else {
$Self->_Overview(
Nav => $Nav,
Search => $Search,
);
my $Notification = $ParamObject->GetParam( Param => 'Notification' ) || '';
my $Output = $NavBar;
$Output .= $LayoutObject->Notify( Info => Translatable('Customer user updated!') )
if ( $Notification && $Notification eq 'Update' );
$Output .= $LayoutObject->Output(
TemplateFile => 'AdminCustomerUser',
Data => \%Param,
);
if ( $Nav eq 'None' ) {
$Output .= $LayoutObject->Footer( Type => 'Small' );
}
else {
$Output .= $LayoutObject->Footer();
}
return $Output;
}
}
sub _Overview {
my ( $Self, %Param ) = @_;
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
$LayoutObject->Block(
Name => 'Overview',
Data => \%Param,
);
$LayoutObject->Block( Name => 'ActionList' );
$LayoutObject->Block(
Name => 'ActionSearch',
Data => \%Param,
);
my $CustomerUserObject = $Kernel::OM->Get('Kernel::System::CustomerUser');
# get writable data sources
my %CustomerSource = $CustomerUserObject->CustomerSourceList(
ReadOnly => 0,
);
# only show Add option if we have at least one writable backend
if ( scalar keys %CustomerSource ) {
$Param{SourceOption} = $LayoutObject->BuildSelection(
Data => { %CustomerSource, },
Name => 'Source',
SelectedID => $Param{Source} || '',
Class => 'Modernize',
);
$LayoutObject->Block(
Name => 'ActionAdd',
Data => \%Param,
);
}
if ( $Param{Search} ) {
# get config object
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
# when there is no data to show, a message is displayed on the table with this colspan
my $ColSpan = 6;
# same Limit as $Self->{CustomerUserMap}->{CustomerUserSearchListLimit}
# smallest Limit from all sources
my $Limit = 400;
SOURCE:
for my $Count ( '', 1 .. 10 ) {
next SOURCE if !$ConfigObject->Get("CustomerUser$Count");
my $CustomerUserMap = $ConfigObject->Get("CustomerUser$Count");
next SOURCE if !$CustomerUserMap->{CustomerUserSearchListLimit};
if ( $CustomerUserMap->{CustomerUserSearchListLimit} < $Limit ) {
$Limit = $CustomerUserMap->{CustomerUserSearchListLimit};
}
}
my %ListAllItems = $CustomerUserObject->CustomerSearch(
Search => $Param{Search},
Limit => $Limit + 1,
Valid => 0,
);
if ( keys %ListAllItems <= $Limit ) {
my $ListAllItems = keys %ListAllItems;
$LayoutObject->Block(
Name => 'OverviewHeader',
Data => {
ListAll => $ListAllItems,
Limit => $Limit,
},
);
}
my %List = $CustomerUserObject->CustomerSearch(
Search => $Param{Search},
Valid => 0,
);
if ( keys %ListAllItems > $Limit ) {
my $ListAllItems = keys %ListAllItems;
my $SearchListSize = keys %List;
$LayoutObject->Block(
Name => 'OverviewHeader',
Data => {
SearchListSize => $SearchListSize,
ListAll => $ListAllItems,
Limit => $Limit,
},
);
}
$LayoutObject->Block(
Name => 'OverviewResult',
Data => \%Param,
);
if ( $ConfigObject->Get('SwitchToCustomer') && $Self->{SwitchToCustomerPermission} && $Param{Nav} ne 'None' )
{
$ColSpan = 7;
$LayoutObject->Block(
Name => 'OverviewResultSwitchToCustomer',
);
}
# if there are results to show
if (%List) {
# get valid list
my %ValidList = $Kernel::OM->Get('Kernel::System::Valid')->ValidList();
for my $ListKey ( sort { lc($a) cmp lc($b) } keys %List ) {
my %UserData = $CustomerUserObject->CustomerUserDataGet( User => $ListKey );
$UserData{UserFullname} = $CustomerUserObject->CustomerName(
UserLogin => $UserData{UserLogin},
);
$LayoutObject->Block(
Name => 'OverviewResultRow',
Data => {
Valid => $ValidList{ $UserData{ValidID} || '' } || '-',
Search => $Param{Search},
CustomerKey => $ListKey,
%UserData,
},
);
if ( $Param{Nav} eq 'None' ) {
$LayoutObject->Block(
Name => 'OverviewResultRowLinkNone',
Data => {
Search => $Param{Search},
CustomerKey => $ListKey,
%UserData,
},
);
}
else {
$LayoutObject->Block(
Name => 'OverviewResultRowLink',
Data => {
Search => $Param{Search},
Nav => $Param{Nav},
CustomerKey => $ListKey,
%UserData,
},
);
}
if (
$ConfigObject->Get('SwitchToCustomer')
&& $Self->{SwitchToCustomerPermission}
&& $Param{Nav} ne 'None'
)
{
$LayoutObject->Block(
Name => 'OverviewResultRowSwitchToCustomer',
Data => {
Search => $Param{Search},
%UserData,
},
);
}
}
}
# otherwise it displays a no data found message
else {
$LayoutObject->Block(
Name => 'NoDataFoundMsg',
Data => {
ColSpan => $ColSpan,
},
);
}
}
# if there is nothing to search it shows a message
else
{
$LayoutObject->Block(
Name => 'NoSearchTerms',
Data => {},
);
}
$LayoutObject->AddJSData(
Key => 'Nav',
Value => $Param{Nav},
);
return;
}
sub _Edit {
my ( $Self, %Param ) = @_;
# Get layout object.
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $Output = '';
$LayoutObject->Block(
Name => 'Overview',
Data => \%Param,
);
$LayoutObject->Block( Name => 'ActionList' );
$LayoutObject->Block(
Name => 'ActionOverview',
Data => \%Param,
);
$LayoutObject->Block(
Name => 'OverviewUpdate',
Data => \%Param,
);
if ( $Param{Action} eq 'Change' ) {
# shows edit header
$LayoutObject->Block( Name => 'HeaderEdit' );
# shows effective permissions matrix
$Self->_EffectivePermissions(%Param);
}
# shows add header
else {
$LayoutObject->Block( Name => 'HeaderAdd' );
}
my $UpdateOnlyPreferences;
# Get config object
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
# update user
if ( $ConfigObject->Get( $Param{Source} )->{ReadOnly} || $ConfigObject->Get( $Param{Source} )->{Module} =~ /LDAP/i )
{
$UpdateOnlyPreferences = 1;
}
# Get dynamic field backend object.
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
ENTRY:
for my $Entry ( @{ $ConfigObject->Get( $Param{Source} )->{Map} } ) {
next ENTRY if !$Entry->[0];
# Handle dynamic fields
if ( $Entry->[5] eq 'dynamic_field' ) {
my $DynamicFieldConfig = $Self->{DynamicFieldLookup}->{ $Entry->[2] };
next ENTRY if !IsHashRefWithData($DynamicFieldConfig);
# Get HTML for dynamic field
my $DynamicFieldHTML = $DynamicFieldBackendObject->EditFieldRender(
DynamicFieldConfig => $DynamicFieldConfig,
Value => $Param{ $Entry->[0] } ? $Param{ $Entry->[0] } : undef,
Mandatory => $Entry->[4],
LayoutObject => $LayoutObject,
ParamObject => $ParamObject,
# Server error, if any
%{ $Param{Errors}->{ $Entry->[0] } },
);
# skip fields for which HTML could not be retrieved
next ENTRY if !IsHashRefWithData($DynamicFieldHTML);
$LayoutObject->Block(
Name => 'Item',
Data => {},
);
$LayoutObject->Block(
Name => 'DynamicField',
Data => {
Name => $DynamicFieldConfig->{Name},
Label => $DynamicFieldHTML->{Label},
Field => $DynamicFieldHTML->{Field},
},
);
next ENTRY;
}
my $Block = 'Input';
# check input type
if ( $Entry->[0] =~ /^UserPasswor/i ) {
$Block = 'Password';
}
# check if login auto creation
if ( $ConfigObject->Get( $Param{Source} )->{AutoLoginCreation} && $Entry->[0] eq 'UserLogin' ) {
$Block = 'InputHidden';
}
if ( $Entry->[7] || $UpdateOnlyPreferences ) {
$Param{ReadOnly} = 1;
}
else {
$Param{ReadOnly} = 0;
}
# show required flag
if ( $Entry->[4] ) {
$Param{RequiredClass} = 'Validate_Required';
$Param{RequiredLabelClass} = 'Mandatory';
$Param{RequiredLabelCharacter} = '*';
}
else {
$Param{RequiredClass} = '';
$Param{RequiredLabelClass} = '';
$Param{RequiredLabelCharacter} = '';
}
# set empty string
$Param{Errors}->{ $Entry->[0] . 'Invalid' } ||= '';
# add class to validate emails
if ( $Entry->[0] eq 'UserEmail' ) {
$Param{RequiredClass} .= ' Validate_Email';
}
# build selections or input fields
if ( $ConfigObject->Get( $Param{Source} )->{Selections}->{ $Entry->[0] } ) {
$Block = 'Option';
# Change the validation class
if ( $Param{RequiredClass} ) {
$Param{RequiredClass} = 'Validate_Required';
}
# get the data of the current selection
my $SelectionsData = $ConfigObject->Get( $Param{Source} )->{Selections}->{ $Entry->[0] };
# make sure the encoding stamp is set
for my $Key ( sort keys %{$SelectionsData} ) {
$SelectionsData->{$Key}
= $Kernel::OM->Get('Kernel::System::Encode')->EncodeInput( $SelectionsData->{$Key} );
}
# build option string
$Param{Option} = $LayoutObject->BuildSelection(
Data => $SelectionsData,
Name => $Entry->[0],
Translation => 1,
SelectedID => $Param{ $Entry->[0] },
Class => "$Param{RequiredClass} Modernize " . $Param{Errors}->{ $Entry->[0] . 'Invalid' },
Disabled => $UpdateOnlyPreferences ? 1 : 0,
);
}
elsif ( $Entry->[0] =~ /^ValidID/i ) {
# Change the validation class
if ( $Param{RequiredClass} ) {
$Param{RequiredClass} = 'Validate_Required';
}
# build ValidID string
$Block = 'Option';
$Param{Option} = $LayoutObject->BuildSelection(
Data => { $Kernel::OM->Get('Kernel::System::Valid')->ValidList(), },
Name => $Entry->[0],
SelectedID => defined( $Param{ $Entry->[0] } ) ? $Param{ $Entry->[0] } : 1,
Class => "$Param{RequiredClass} Modernize " . $Param{Errors}->{ $Entry->[0] . 'Invalid' },
Disabled => $UpdateOnlyPreferences ? 1 : 0,
);
}
elsif (
$Entry->[0] =~ /^UserCustomerID$/i
&& $ConfigObject->Get( $Param{Source} )->{CustomerCompanySupport}
)
{
my $CustomerCompanyObject = $Kernel::OM->Get('Kernel::System::CustomerCompany');
my %CompanyList = (
$CustomerCompanyObject->CustomerCompanyList( Limit => 0 ),
'' => '-',
);
if ( $Param{ $Entry->[0] } ) {
my %Company = $CustomerCompanyObject->CustomerCompanyGet(
CustomerID => $Param{ $Entry->[0] },
);
if ( !%Company ) {
$CompanyList{ $Param{ $Entry->[0] } } = $Param{ $Entry->[0] } . ' (-)';
}
}
$Block = 'Option';
# Change the validation class
if ( $Param{RequiredClass} ) {
$Param{RequiredClass} = 'Validate_Required';
}
my $UseAutoComplete = $Kernel::OM->Get('Kernel::Config')->Get('AdminCustomerUser::UseAutoComplete');
if ($UseAutoComplete) {
my $Value = $Param{ $Entry->[0] } || $Param{CustomerID};
$Param{Option} = '<input type="text" id="UserCustomerID" name="UserCustomerID" value="' . $Value . '"
class="W50pc CustomerAutoCompleteSimple '
. $Param{RequiredClass} . ' '
. $Param{Errors}->{ $Entry->[0] . 'Invalid' }
. '" data-customer-search-type="CustomerID" />';
}
else {
$Param{Option} = $LayoutObject->BuildSelection(
Data => \%CompanyList,
Name => $Entry->[0],
Max => 80,
SelectedID => $Param{ $Entry->[0] } || $Param{CustomerID},
Class => "$Param{RequiredClass} Modernize " . $Param{Errors}->{ $Entry->[0] . 'Invalid' },
Disabled => $UpdateOnlyPreferences ? 1 : 0,
);
}
}
elsif ( $Param{Action} eq 'Add' && $Entry->[0] =~ /^UserCustomerID$/i ) {
# Use CustomerID param if called from CIC.
$Param{Value} = $Param{ $Entry->[0] } || $Param{CustomerID} || '';
}
else {
$Param{Value} = $Param{ $Entry->[0] } || '';
}
# add form option
if ( $Param{Type} && $Param{Type} eq 'hidden' ) {
$Param{Preferences} .= $Param{Value};
}
else {
$LayoutObject->Block(
Name => 'PreferencesGeneric',
Data => {
Item => $Entry->[1],
%Param
},
);
$LayoutObject->Block(
Name => "PreferencesGeneric$Block",
Data => {
Item => $Entry->[1],
Name => $Entry->[0],
InvalidField => $Param{Errors}->{ $Entry->[0] . 'Invalid' } || '',
%Param,
},
);
# add the correct client side error msg
if ( $Block eq 'Input' && $Entry->[0] eq 'UserEmail' ) {
$LayoutObject->Block(
Name => 'PreferencesUserEmailErrorMsg',
Data => { Name => $Entry->[0] },
);
}
else {
$LayoutObject->Block(
Name => "PreferencesGenericErrorMsg",
Data => { Name => $Entry->[0] },
);
}
# add the correct server error msg
if ( $Block eq 'Input' && $Param{UserEmail} && $Entry->[0] eq 'UserEmail' ) {
# display server error msg according with the occurred email error type
$LayoutObject->Block(
Name => 'PreferencesUserEmail' . ( $Param{Errors}->{ErrorType} || '' ),
Data => { Name => $Entry->[0] },
);
}
else {
$LayoutObject->Block(
Name => "PreferencesGenericServerErrorMsg",
Data => { Name => $Entry->[0] },
);
}
}
}
my $PreferencesUsed = $ConfigObject->Get( $Param{Source} )->{AdminSetPreferences};
if ( ( defined $PreferencesUsed && $PreferencesUsed != 0 ) || !defined $PreferencesUsed ) {
my %Data;
my %Preferences = %{ $ConfigObject->Get('CustomerPreferencesGroups') };
GROUP:
for my $Group ( sort keys %Preferences ) {
next GROUP if !$Group;
my $PreferencesGroup = $Preferences{$Group};
next GROUP if !$PreferencesGroup;
next GROUP if ref $PreferencesGroup ne 'HASH';
if ( $Data{ $PreferencesGroup->{Prio} } ) {
COUNT:
for ( 1 .. 151 ) {
$PreferencesGroup->{Prio}++;
if ( !$Data{ $PreferencesGroup->{Prio} } ) {
$Data{ $PreferencesGroup->{Prio} } = $Group;
last COUNT;
}
}
}
$Data{ $PreferencesGroup->{Prio} } = $Group;
}
# sort
for my $Key ( sort keys %Data ) {
$Data{ sprintf "%07d", $Key } = $Data{$Key};
delete $Data{$Key};
}
# show each preferences setting
PRIO:
for my $Prio ( sort keys %Data ) {
my $Group = $Data{$Prio};
if ( !$ConfigObject->{CustomerPreferencesGroups}->{$Group} ) {
next PRIO;
}
my %Preference = %{ $ConfigObject->{CustomerPreferencesGroups}->{$Group} };
if ( $Group eq 'Password' ) {
next PRIO;
}
my $Module = $Preference{Module}
|| 'Kernel::Output::HTML::CustomerPreferencesGeneric';
# load module
if ( $Kernel::OM->Get('Kernel::System::Main')->Require($Module) ) {
my $Object = $Module->new(
%{$Self},
ConfigItem => \%Preference,
UserObject => $Kernel::OM->Get('Kernel::System::CustomerUser'),
Debug => $Self->{Debug},
);
my @Params = $Object->Param( UserData => \%Param );
if (@Params) {
for my $ParamItem (@Params) {
$LayoutObject->Block(
Name => 'Item',
Data => {%Param},
);
if (
ref $ParamItem->{Data} eq 'HASH'
|| ref $Preference{Data} eq 'HASH'
)
{
my %BuildSelectionParams = (
%Preference,
%{$ParamItem},
);
$BuildSelectionParams{Class} = join( ' ', $BuildSelectionParams{Class} // '', 'Modernize' );
$ParamItem->{Option} = $LayoutObject->BuildSelection(
%BuildSelectionParams,
);
}
$LayoutObject->Block(
Name => $ParamItem->{Block} || $Preference{Block} || 'Option',
Data => {
Group => $Group,
%Param,
%Data,
%Preference,
%{$ParamItem},
},
);
}
}
}
else {
return $LayoutObject->FatalError();
}
}
}
$LayoutObject->AddJSData(
Key => 'Nav',
Value => $Param{Nav},
);
return $LayoutObject->Output(
TemplateFile => 'AdminCustomerUser',
Data => \%Param,
);
}
sub _EffectivePermissions {
my ( $Self, %Param ) = @_;
# only if customer group feature is active
if ( !$Kernel::OM->Get('Kernel::Config')->Get('CustomerGroupSupport') ) {
return 1;
}
# get needed objects
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $CustomerGroupObject = $Kernel::OM->Get('Kernel::System::CustomerGroup');
# show tables
$LayoutObject->Block(
Name => 'EffectivePermissions',
);
my %Groups;
my %Permissions;
# go through permission types
my @Types = @{ $ConfigObject->Get('System::Customer::Permission') };
for my $Type (@Types) {
# show header
$LayoutObject->Block(
Name => "HeaderGroupPermissionType",
Data => {
Type => $Type,
},
);
# get groups of the user
my %UserGroups = $CustomerGroupObject->GroupMemberList(
UserID => $Param{ID},
Type => $Type,
Result => 'HASH',
RawPermissions => 0, # get effective permissions
);
# store data in lookup hashes
for my $GroupID ( sort keys %UserGroups ) {
$Groups{$GroupID} = $UserGroups{$GroupID};
$Permissions{$GroupID}{$Type} = 1;
}
}
# show message if no permissions found
if ( !%Permissions ) {
$LayoutObject->Block(
Name => 'NoGroupPermissionsFoundMsg',
);
}
# go through groups, sort by name
else {
for my $GroupID ( sort { uc( $Groups{$a} ) cmp uc( $Groups{$b} ) } keys %Groups ) {
# show table rows
$LayoutObject->Block(
Name => 'GroupPermissionTableRow',
Data => {
ID => $GroupID,
Name => $Groups{$GroupID},
},
);
# show permission marks
for my $Type (@Types) {
my $PermissionMark = $Permissions{$GroupID}{$Type} ? 'On' : 'Off';
my $HighlightMark = $Type eq 'rw' ? 'Highlight' : '';
$LayoutObject->Block(
Name => 'GroupPermissionMark',
);
$LayoutObject->Block(
Name => 'GroupPermissionMark' . $PermissionMark,
Data => {
Highlight => $HighlightMark,
},
);
}
}
}
# get all accessible customers of the user
my %Customers = $CustomerGroupObject->GroupContextCustomers(
CustomerUserID => $Param{ID},
);
# show message if no customers found
if ( !%Customers ) {
$LayoutObject->Block(
Name => 'NoCustomerAccessFoundMsg',
);
return 1;
}
# get permission contexts
my $ContextConfig = $ConfigObject->Get('CustomerGroupPermissionContext');
my $DirectAccessContextKey = '001-CustomerID-same';
my $IndirectAccessContextKey = '100-CustomerID-other';
# use default context if none are found
if ( !IsHashRefWithData($ContextConfig) ) {
$ContextConfig = {
$DirectAccessContextKey => {
Name => Translatable('Same Customer'),
},
};
}
# show default and extra context headers if available
if ( $ContextConfig->{$DirectAccessContextKey} ) {
$LayoutObject->Block(
Name => 'HeaderCustomerAccessContext',
Data => {
Name => Translatable('Direct'),
},
);
}
if ( $ContextConfig->{$IndirectAccessContextKey} ) {
$LayoutObject->Block(
Name => 'HeaderCustomerAccessContext',
Data => {
Name => Translatable('Indirect'),
},
);
}
# determine customers for direct and indirect access
my @UserCustomerIDs = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerIDs(
User => $Param{ID},
);
my %ExtraCustomerIDs;
if ( $ContextConfig->{$IndirectAccessContextKey} ) {
my $ExtraContextName = $CustomerGroupObject->GroupContextNameGet(
SysConfigName => $IndirectAccessContextKey,
);
# for all CustomerIDs get groups with extra access
my %ExtraPermissionGroups;
CUSTOMERID:
for my $CustomerID (@UserCustomerIDs) {
my %GroupList = $CustomerGroupObject->GroupCustomerList(
CustomerID => $CustomerID,
Type => 'ro',
Context => $ExtraContextName,
Result => 'HASH',
);
next CUSTOMERID if !%GroupList;
# add to groups
%ExtraPermissionGroups = (
%ExtraPermissionGroups,
%GroupList,
);
}
# add all unique accessible Group<->Customer combinations
GROUPID:
for my $GroupID ( sort keys %ExtraPermissionGroups ) {
my @GroupCustomerIDs = $CustomerGroupObject->GroupCustomerList(
GroupID => $GroupID,
Type => 'ro',
Result => 'ID',
);
next GROUPID if !@GroupCustomerIDs;
# add to ExtraCustomerIDs
%ExtraCustomerIDs = (
%ExtraCustomerIDs,
map { $_ => 1 } @GroupCustomerIDs,
);
}
}
# go through customers
CUSTOMERID:
for my $CustomerID ( sort keys %Customers ) {
# show table rows
$LayoutObject->Block(
Name => 'CustomerAccessTableRow',
Data => {
ID => $CustomerID,
Name => $Customers{$CustomerID},
},
);
# 'Same Customer'
if ( $ContextConfig->{$DirectAccessContextKey} ) {
# check if we should show check mark for 'Same Customer'
my $AccessMark = ( grep { $_ eq $CustomerID } @UserCustomerIDs ) ? 'On' : 'Off';
# show blocks
$LayoutObject->Block(
Name => 'CustomerAccessMark',
);
$LayoutObject->Block(
Name => 'CustomerAccessMark' . $AccessMark,
);
}
# 'Other Customers'
next CUSTOMERID if !$ContextConfig->{$IndirectAccessContextKey};
# check if we should show check mark for 'Other Customers'
my $AccessMark = $ExtraCustomerIDs{$CustomerID} ? 'On' : 'Off';
# show blocks
$LayoutObject->Block(
Name => 'CustomerAccessMark',
);
$LayoutObject->Block(
Name => 'CustomerAccessMark' . $AccessMark,
);
}
return 1;
}
1;