Files
2024-10-14 00:08:40 +02:00

1707 lines
51 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::System::CustomerUser::LDAP;
use strict;
use warnings;
use Net::LDAP;
use Net::LDAP::Util qw(escape_filter_value);
use Kernel::System::VariableCheck qw(:all);
our @ObjectDependencies = (
'Kernel::Config',
'Kernel::System::Cache',
'Kernel::System::DB',
'Kernel::System::DynamicField',
'Kernel::System::DynamicField::Backend',
'Kernel::System::Encode',
'Kernel::System::Log',
'Kernel::System::DateTime',
);
sub new {
my ( $Type, %Param ) = @_;
# allocate new hash for object
my $Self = {};
bless( $Self, $Type );
# check needed data
for my $Needed (qw( PreferencesObject CustomerUserMap )) {
$Self->{$Needed} = $Param{$Needed} || die "Got no $Needed!";
}
# max shown user a search list
$Self->{UserSearchListLimit} = $Self->{CustomerUserMap}->{CustomerUserSearchListLimit} || 200;
# get ldap preferences
$Self->{Die} = 0;
if ( defined $Self->{CustomerUserMap}->{Params}->{Die} ) {
$Self->{Die} = $Self->{CustomerUserMap}->{Params}->{Die};
}
# get config object
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
# params
if ( $Self->{CustomerUserMap}->{Params}->{Params} ) {
$Self->{Params} = $Self->{CustomerUserMap}->{Params}->{Params};
}
# Net::LDAP new params
elsif ( $ConfigObject->Get( 'AuthModule::LDAP::Params' . $Param{Count} ) ) {
$Self->{Params} = $ConfigObject->Get( 'AuthModule::LDAP::Params' . $Param{Count} );
}
else {
$Self->{Params} = {};
}
# host
if ( $Self->{CustomerUserMap}->{Params}->{Host} ) {
$Self->{Host} = $Self->{CustomerUserMap}->{Params}->{Host};
}
else {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need CustomerUser->Params->Host in Kernel/Config.pm',
);
return;
}
# base dn
if ( defined $Self->{CustomerUserMap}->{Params}->{BaseDN} ) {
$Self->{BaseDN} = $Self->{CustomerUserMap}->{Params}->{BaseDN};
}
else {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need CustomerUser->Params->BaseDN in Kernel/Config.pm',
);
return;
}
# scope
if ( $Self->{CustomerUserMap}->{Params}->{SSCOPE} ) {
$Self->{SScope} = $Self->{CustomerUserMap}->{Params}->{SSCOPE};
}
else {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need CustomerUser->Params->SSCOPE in Kernel/Config.pm',
);
return;
}
# search user
$Self->{SearchUserDN} = $Self->{CustomerUserMap}->{Params}->{UserDN} || '';
$Self->{SearchUserPw} = $Self->{CustomerUserMap}->{Params}->{UserPw} || '';
# group dn
$Self->{GroupDN} = $Self->{CustomerUserMap}->{Params}->{GroupDN} || '';
# customer key
if ( $Self->{CustomerUserMap}->{CustomerKey} ) {
$Self->{CustomerKey} = $Self->{CustomerUserMap}->{CustomerKey};
}
else {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need CustomerUser->CustomerKey in Kernel/Config.pm',
);
return;
}
# customer id
if ( $Self->{CustomerUserMap}->{CustomerID} ) {
$Self->{CustomerID} = $Self->{CustomerUserMap}->{CustomerID};
}
else {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need CustomerUser->CustomerID in Kernel/Config.pm',
);
return;
}
# ldap filter always used
$Self->{AlwaysFilter} = $Self->{CustomerUserMap}->{Params}->{AlwaysFilter} || '';
$Self->{ExcludePrimaryCustomerID} = $Self->{CustomerUserMap}->{CustomerUserExcludePrimaryCustomerID} || 0;
$Self->{SearchPrefix} = $Self->{CustomerUserMap}->{CustomerUserSearchPrefix};
if ( !defined $Self->{SearchPrefix} ) {
$Self->{SearchPrefix} = '';
}
$Self->{SearchSuffix} = $Self->{CustomerUserMap}->{CustomerUserSearchSuffix};
if ( !defined $Self->{SearchSuffix} ) {
$Self->{SearchSuffix} = '*';
}
# charset settings
$Self->{SourceCharset} = $Self->{CustomerUserMap}->{Params}->{SourceCharset} || '';
# set cache type
$Self->{CacheType} = 'CustomerUser' . $Param{Count};
# create cache object, but only if CacheTTL is set in customer config
if ( $Self->{CustomerUserMap}->{CacheTTL} ) {
$Self->{CacheObject} = $Kernel::OM->Get('Kernel::System::Cache');
}
# get valid filter if used
$Self->{ValidFilter} = $Self->{CustomerUserMap}->{CustomerUserValidFilter} || '';
# connect first if Die is enabled, make sure that connection is possible, else die
if ( $Self->{Die} ) {
return if !$Self->_Connect();
}
# fetch names of configured dynamic fields
my @DynamicFieldMapEntries = grep { $_->[5] eq 'dynamic_field' } @{ $Self->{CustomerUserMap}->{Map} };
$Self->{ConfiguredDynamicFieldNames} = { map { $_->[2] => 1 } @DynamicFieldMapEntries };
return $Self;
}
sub _Connect {
my ( $Self, %Param ) = @_;
# return if connection is already open
return 1 if $Self->{LDAP};
# ldap connect and bind (maybe with SearchUserDN and SearchUserPw)
$Self->{LDAP} = Net::LDAP->new( $Self->{Host}, %{ $Self->{Params} } );
if ( !$Self->{LDAP} ) {
if ( $Self->{Die} ) {
die "Can't connect to $Self->{Host}: $@";
}
else {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Can't connect to $Self->{Host}: $@",
);
return;
}
}
my $Result;
if ( $Self->{SearchUserDN} && $Self->{SearchUserPw} ) {
$Result = $Self->{LDAP}->bind(
dn => $Self->{SearchUserDN},
password => $Self->{SearchUserPw},
);
}
else {
$Result = $Self->{LDAP}->bind();
}
if ( $Result->code() ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'First bind failed! ' . $Result->error(),
);
$Self->{LDAP}->disconnect();
return;
}
return 1;
}
sub CustomerName {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{UserLogin} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need UserLogin!'
);
return;
}
# build filter
my $Filter = "($Self->{CustomerKey}=" . escape_filter_value( $Param{UserLogin} ) . ')';
# prepare filter
if ( $Self->{AlwaysFilter} ) {
$Filter = "(&$Filter$Self->{AlwaysFilter})";
}
# check cache
if ( $Self->{CacheObject} ) {
my $Name = $Self->{CacheObject}->Get(
Type => $Self->{CacheType},
Key => 'CustomerName::' . $Param{UserLogin},
);
return $Name if defined $Name;
}
# create ldap connect
return if !$Self->_Connect();
# perform user search
my $Result = $Self->{LDAP}->search(
base => $Self->{BaseDN},
scope => $Self->{SScope},
filter => $Filter,
sizelimit => $Self->{UserSearchListLimit},
attrs => $Self->{CustomerUserMap}->{CustomerUserNameFields},
);
if ( $Result->code() ) {
if ( $Result->code() == 4 ) {
# Result code 4 (LDAP_SIZELIMIT_EXCEEDED) is normal if there
# are more items in LDAP than search limit defined in OTRS or
# in LDAP server. Avoid spamming logs with such errors.
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'debug',
Message => 'LDAP size limit exceeded (' . $Result->error() . ').',
);
}
else {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Search failed! ' . $Result->error(),
);
}
return;
}
my %NameParts;
for my $Entry ( $Result->all_entries() ) {
for my $Field ( @{ $Self->{CustomerUserMap}->{CustomerUserNameFields} } ) {
if ( defined $Entry->get_value($Field) ) {
$NameParts{$Field} = $Self->_ConvertFrom( $Entry->get_value($Field) );
}
}
}
# fetch dynamic field values, if configured
my @DynamicFieldCustomerUserNameFields = grep { exists $Self->{ConfiguredDynamicFieldNames}->{$_} }
@{ $Self->{CustomerUserMap}->{CustomerUserNameFields} };
if (@DynamicFieldCustomerUserNameFields) {
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
DYNAMICFIELDNAME:
for my $DynamicFieldName (@DynamicFieldCustomerUserNameFields) {
my $DynamicFieldConfig = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldGet(
Name => $DynamicFieldName,
);
next DYNAMICFIELDNAME if !IsHashRefWithData($DynamicFieldConfig);
my $Value = $DynamicFieldBackendObject->ValueGet(
DynamicFieldConfig => $DynamicFieldConfig,
ObjectName => $Param{UserLogin},
);
next DYNAMICFIELDNAME if !defined $Value;
if ( !IsArrayRefWithData($Value) ) {
$Value = [$Value];
}
my @RenderedValues;
VALUE:
for my $CurrentValue ( @{$Value} ) {
next VALUE if !defined $CurrentValue || !length $CurrentValue;
my $RenderedValue = $DynamicFieldBackendObject->ReadableValueRender(
DynamicFieldConfig => $DynamicFieldConfig,
Value => $CurrentValue,
);
next VALUE if !IsHashRefWithData($RenderedValue) || !defined $RenderedValue->{Value};
push @RenderedValues, $RenderedValue->{Value};
}
$NameParts{$DynamicFieldName} = join ' ', @RenderedValues;
}
}
# assemble name
my @NameParts;
CUSTOMERUSERNAMEFIELD:
for my $CustomerUserNameField ( @{ $Self->{CustomerUserMap}->{CustomerUserNameFields} } ) {
next CUSTOMERUSERNAMEFIELD
if !exists $NameParts{$CustomerUserNameField}
|| !defined $NameParts{$CustomerUserNameField}
|| !length $NameParts{$CustomerUserNameField};
push @NameParts, $NameParts{$CustomerUserNameField};
}
my $JoinCharacter = $Self->{CustomerUserMap}->{CustomerUserNameFieldsJoin} // ' ';
my $Name = join $JoinCharacter, @NameParts;
# cache request
if ( $Self->{CacheObject} ) {
$Self->{CacheObject}->Set(
Type => $Self->{CacheType},
Key => 'CustomerName::' . $Param{UserLogin},
Value => $Name,
TTL => $Self->{CustomerUserMap}->{CacheTTL},
);
}
return $Name;
}
sub CustomerSearch {
my ( $Self, %Param ) = @_;
if ( $Param{CustomerIDRaw} ) {
$Param{CustomerID} = $Param{CustomerIDRaw};
}
# check needed stuff
if ( !$Param{Search} && !$Param{UserLogin} && !$Param{PostMasterSearch} && !$Param{CustomerID} )
{
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need Search, UserLogin, PostMasterSearch or CustomerID!'
);
return;
}
# build filter
my $Filter = '';
if ( $Param{Search} ) {
my $Count = 0;
my @Parts = split( /\+/, $Param{Search}, 6 );
for my $Part (@Parts) {
$Part = $Self->{SearchPrefix} . $Part . $Self->{SearchSuffix};
$Part =~ s/(\%+)/\%/g;
$Part =~ s/(\*+)\*/*/g;
$Count++;
# remove dynamic field names that are configured in CustomerUserSearchFields
# as they cannot be retrieved here
my @CustomerUserSearchFields = grep { !exists $Self->{ConfiguredDynamicFieldNames}->{$_} }
@{ $Self->{CustomerUserMap}->{CustomerUserSearchFields} };
if (@CustomerUserSearchFields) {
# quote LDAP filter value but keep asterisks unescaped (wildcard)
$Part =~ s/\*/encodedasterisk20160930/g;
$Part = escape_filter_value( $Self->_ConvertTo($Part) );
$Part =~ s/encodedasterisk20160930/*/g;
$Filter .= '(|';
for my $Field (@CustomerUserSearchFields) {
$Filter .= "($Field=" . $Part . ')';
}
$Filter .= ')';
}
else {
# quote LDAP filter value but keep asterisks unescaped (wildcard)
$Part =~ s/\*/encodedasterisk20160930/g;
$Part = escape_filter_value($Part);
$Part =~ s/encodedasterisk20160930/*/g;
$Filter .= "($Self->{CustomerKey}=" . $Part . ')';
}
}
if ( $Count > 1 ) {
$Filter = "(&$Filter)";
}
}
elsif ( $Param{PostMasterSearch} ) {
# remove dynamic field names that are configured in CustomerUserPostMasterSearchFields
# as they cannot be retrieved here
my @CustomerUserPostMasterSearchFields = grep { !exists $Self->{ConfiguredDynamicFieldNames}->{$_} }
@{ $Self->{CustomerUserMap}->{CustomerUserPostMasterSearchFields} };
if (@CustomerUserPostMasterSearchFields) {
# quote LDAP filter value but keep asterisks unescaped (wildcard)
$Param{PostMasterSearch} =~ s/\*/encodedasterisk20160930/g;
$Param{PostMasterSearch} = escape_filter_value( $Param{PostMasterSearch} );
$Param{PostMasterSearch} =~ s/encodedasterisk20160930/*/g;
$Filter = '(|';
for my $Field (@CustomerUserPostMasterSearchFields) {
$Filter .= "($Field=$Param{PostMasterSearch})";
}
$Filter .= ')';
}
}
elsif ( $Param{UserLogin} ) {
$Filter = "($Self->{CustomerKey}=" . escape_filter_value( $Param{UserLogin} ) . ')';
}
elsif ( $Param{CustomerID} ) {
$Filter = "($Self->{CustomerID}=" . escape_filter_value( $Param{CustomerID} ) . ')';
}
# prepare filter
if ( $Self->{AlwaysFilter} ) {
$Filter = "(&$Filter$Self->{AlwaysFilter})";
}
# add valid filter
if ( $Self->{ValidFilter} ) {
$Filter = "(&$Filter$Self->{ValidFilter})";
}
# check cache
my $CacheKey = join '::', map { $_ . '=' . $Param{$_} } sort keys %Param;
if ( $Self->{CacheObject} ) {
my $Users = $Self->{CacheObject}->Get(
Type => $Self->{CacheType} . '_CustomerSearch',
Key => $CacheKey,
);
return %{$Users} if ref $Users eq 'HASH';
}
# create ldap connect
return if !$Self->_Connect();
my $CustomerUserListFields = $Self->{CustomerUserMap}->{CustomerUserListFields};
# remove dynamic field names that are configured in CustomerUserListFields
# as they cannot be handled here
my @CustomerUserListFieldsWithoutDynamicFields
= grep { !exists $Self->{ConfiguredDynamicFieldNames}->{$_} } @{$CustomerUserListFields};
# combine needed attrs
my @Attributes = ( @CustomerUserListFieldsWithoutDynamicFields, $Self->{CustomerKey} );
# perform user search
my $Result = $Self->{LDAP}->search(
base => $Self->{BaseDN},
scope => $Self->{SScope},
filter => $Filter,
sizelimit => $Param{Limit} || $Self->{UserSearchListLimit},
attrs => \@Attributes,
);
# log ldap errors
if ( $Result->code() ) {
if ( $Result->code() == 4 ) {
# Result code 4 (LDAP_SIZELIMIT_EXCEEDED) is normal if there
# are more items in LDAP than search limit defined in OTRS or
# in LDAP server. Avoid spamming logs with such errors.
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'debug',
Message => 'LDAP size limit exceeded (' . $Result->error() . ').',
);
}
else {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Search failed! ' . $Result->error(),
);
}
}
# dynamic field handling
my @CustomerUserListFieldsDynamicFields
= grep { exists $Self->{ConfiguredDynamicFieldNames}->{$_} } @{$CustomerUserListFields};
my %CustomerUserListFieldsDynamicFields = map { $_ => 1 } @CustomerUserListFieldsDynamicFields;
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
my $DynamicFieldConfigs = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet(
ObjectType => 'CustomerUser',
Valid => 1,
);
my %DynamicFieldConfigsByName = map { $_->{Name} => $_ } @{$DynamicFieldConfigs};
my %Users;
for my $Entry ( $Result->all_entries() ) {
my $CustomerString = '';
my $CustomerKey;
if ( defined $Entry->get_value( $Self->{CustomerKey} ) ) {
$CustomerKey = $Self->_ConvertFrom( $Entry->get_value( $Self->{CustomerKey} ) );
}
FIELD:
for my $Field ( @{$CustomerUserListFields} ) {
# dynamic field value
if ( $CustomerUserListFieldsDynamicFields{$Field} ) {
next FIELD if !defined $CustomerKey;
next FIELD if !exists $DynamicFieldConfigsByName{$Field};
my $Value = $DynamicFieldBackendObject->ValueGet(
DynamicFieldConfig => $DynamicFieldConfigsByName{$Field},
ObjectName => $CustomerKey,
);
next FIELD if !defined $Value;
if ( !IsArrayRefWithData($Value) ) {
$Value = [$Value];
}
my @Values;
VALUE:
for my $CurrentValue ( @{$Value} ) {
next VALUE if !defined $CurrentValue || !length $CurrentValue;
my $ReadableValue = $DynamicFieldBackendObject->ReadableValueRender(
DynamicFieldConfig => $DynamicFieldConfigsByName{$Field},
Value => $CurrentValue,
);
next VALUE if !IsHashRefWithData($ReadableValue) || !defined $ReadableValue->{Value};
my $IsACLReducible = $DynamicFieldBackendObject->HasBehavior(
DynamicFieldConfig => $DynamicFieldConfigsByName{$Field},
Behavior => 'IsACLReducible',
);
if ($IsACLReducible) {
my $PossibleValues = $DynamicFieldBackendObject->PossibleValuesGet(
DynamicFieldConfig => $DynamicFieldConfigsByName{$Field},
);
if (
IsHashRefWithData($PossibleValues)
&& defined $PossibleValues->{ $ReadableValue->{Value} }
)
{
$ReadableValue->{Value} = $PossibleValues->{ $ReadableValue->{Value} };
}
}
push @Values, $ReadableValue->{Value};
}
$CustomerString .= ( join ' ', @Values ) . ' ';
next FIELD;
}
my $Value = $Self->_ConvertFrom( $Entry->get_value($Field) );
if ($Value) {
if ( $Field =~ /^targetaddress$/i ) {
$Value =~ s/SMTP:(.*)/$1/;
}
$CustomerString .= $Value . ' ';
}
}
$CustomerString =~ s/^(.*)\s(.+?\@.+?\..+?)(\s|)$/"$1" <$2>/;
if ( defined $CustomerKey ) {
$Users{$CustomerKey} = $CustomerString;
}
}
# check if user need to be in a group!
if ( $Self->{GroupDN} ) {
for my $Filter2 ( sort keys %Users ) {
my $Result2 = $Self->{LDAP}->search(
base => $Self->{GroupDN},
scope => $Self->{SScope},
filter => 'memberUid=' . escape_filter_value($Filter2),
sizelimit => $Param{Limit} || $Self->{UserSearchListLimit},
attrs => ['1.1'],
);
if ( !$Result2->all_entries() ) {
delete $Users{$Filter2};
}
}
}
# cache request
if ( $Self->{CacheObject} ) {
$Self->{CacheObject}->Set(
Type => $Self->{CacheType} . '_CustomerSearch',
Key => $CacheKey,
Value => \%Users,
TTL => $Self->{CustomerUserMap}->{CacheTTL},
);
}
return %Users;
}
sub CustomerSearchDetail {
my ( $Self, %Param ) = @_;
if ( ref $Param{SearchFields} ne 'ARRAY' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "SearchFields must be an array reference!",
);
return;
}
my $Valid = defined $Param{Valid} ? $Param{Valid} : 1;
$Param{Limit} //= '';
# Split the search fields in scalar and array fields, before the diffrent handling.
my @ScalarSearchFields = grep { 'Input' eq $_->{Type} } @{ $Param{SearchFields} };
my @ArraySearchFields = grep { 'Selection' eq $_->{Type} } @{ $Param{SearchFields} };
# Verify that all passed array parameters contain an arrayref.
ARGUMENT:
for my $Argument (@ArraySearchFields) {
if ( !defined $Param{ $Argument->{Name} } ) {
$Param{ $Argument->{Name} } ||= [];
next ARGUMENT;
}
if ( ref $Param{ $Argument->{Name} } ne 'ARRAY' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "$Argument->{Name} must be an array reference!",
);
return;
}
}
# Set the default behaviour for the return type.
my $Result = $Param{Result} || 'ARRAY';
# Special handling if the result type is 'COUNT'.
if ( $Result eq 'COUNT' ) {
# Ignore the parameter 'Limit' when result type is 'COUNT'.
$Param{Limit} = '';
# Delete the OrderBy parameter when the result type is 'COUNT'.
$Param{OrderBy} = [];
}
# Define order table from the search fields.
my %OrderByTable = map { $_->{Name} => $_->{DatabaseField} } @{ $Param{SearchFields} };
for my $Field (@ArraySearchFields) {
my $SelectionsData = $Field->{SelectionsData};
for my $SelectedValue ( @{ $Param{ $Field->{Name} } } ) {
# Check if the selected value for the current field is valid.
if ( !$SelectionsData->{$SelectedValue} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "The selected value $Field->{Name} is not valid!",
);
return;
}
}
}
# Build the ldap filter for the diffrent search params.
my $Filter = '';
for my $Field (@ScalarSearchFields) {
# Search for scalar fields (wildcards are allowed).
if ( $Param{ $Field->{Name} } ) {
$Param{ $Field->{Name} } =~ s/(\%+)/\%/g;
$Param{ $Field->{Name} } =~ s/(\*+)\*/*/g;
$Filter .= "($Field->{DatabaseField}=" . $Self->_ConvertTo( $Param{ $Field->{Name} } ) . ")";
}
}
if ($Filter) {
$Filter = "(&$Filter)";
}
my $ArrayFilter = '';
# Special parameter for CustomerIDs from a customer company search result.
if ( IsArrayRefWithData( $Param{CustomerCompanySearchCustomerIDs} ) ) {
$ArrayFilter .= '(|';
for my $OneParam ( @{ $Param{CustomerCompanySearchCustomerIDs} } ) {
$ArrayFilter .= "($Self->{CustomerID}=" . $Self->_ConvertTo($OneParam) . ")";
}
$ArrayFilter .= ')';
}
FIELD:
for my $Field (@ArraySearchFields) {
# Ignore empty lists.
next FIELD if !@{ $Param{ $Field->{Name} } };
$ArrayFilter .= '(|';
for my $OneParam ( @{ $Param{ $Field->{Name} } } ) {
$ArrayFilter .= "($Field->{DatabaseField}=" . $Self->_ConvertTo($OneParam) . ")";
}
$ArrayFilter .= ')';
}
# Add the array filter fields to the ldap filter.
if ($ArrayFilter) {
$Filter = "(&$Filter$ArrayFilter)";
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField');
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
# Check all configured change dynamic fields, build lookup hash by name.
my %CustomerUserDynamicFieldName2Config;
my $CustomerUserDynamicFields = $DynamicFieldObject->DynamicFieldListGet(
ObjectType => 'CustomerUser',
);
for my $DynamicField ( @{$CustomerUserDynamicFields} ) {
$CustomerUserDynamicFieldName2Config{ $DynamicField->{Name} } = $DynamicField;
}
my $SQLDynamicFieldFrom = '';
my $SQLDynamicFieldWhere = '';
my $DynamicFieldJoinCounter = 1;
DYNAMICFIELD:
for my $DynamicField ( @{$CustomerUserDynamicFields} ) {
my $SearchParam = $Param{ "DynamicField_" . $DynamicField->{Name} };
next DYNAMICFIELD if ( !$SearchParam );
next DYNAMICFIELD if ( ref $SearchParam ne 'HASH' );
my $NeedJoin;
for my $Operator ( sort keys %{$SearchParam} ) {
my @SearchParams = ( ref $SearchParam->{$Operator} eq 'ARRAY' )
? @{ $SearchParam->{$Operator} }
: ( $SearchParam->{$Operator} );
my $SQLDynamicFieldWhereSub = '';
if ($SQLDynamicFieldWhere) {
$SQLDynamicFieldWhereSub = ' AND (';
}
else {
$SQLDynamicFieldWhereSub = ' (';
}
my $Counter = 0;
TEXT:
for my $Text (@SearchParams) {
next TEXT if ( !defined $Text || $Text eq '' );
$Text =~ s/\*/%/gi;
# Check search attribute, we do not need to search for '*'.
next TEXT if $Text =~ /^\%{1,3}$/;
my $ValidateSuccess = $DynamicFieldBackendObject->ValueValidate(
DynamicFieldConfig => $DynamicField,
Value => $Text,
UserID => $Param{UserID} || 1,
);
if ( !$ValidateSuccess ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Search not executed due to invalid value '"
. $Text
. "' on field '"
. $DynamicField->{Name} . "'!",
);
return;
}
if ($Counter) {
$SQLDynamicFieldWhereSub .= ' OR ';
}
$SQLDynamicFieldWhereSub .= $DynamicFieldBackendObject->SearchSQLGet(
DynamicFieldConfig => $DynamicField,
TableAlias => "dfv$DynamicFieldJoinCounter",
Operator => $Operator,
SearchTerm => $Text,
);
$Counter++;
}
$SQLDynamicFieldWhereSub .= ') ';
if ($Counter) {
$SQLDynamicFieldWhere .= $SQLDynamicFieldWhereSub;
$NeedJoin = 1;
}
}
if ($NeedJoin) {
$SQLDynamicFieldFrom .= "
INNER JOIN dynamic_field_value dfv$DynamicFieldJoinCounter
ON (df_obj_id_name.object_id = dfv$DynamicFieldJoinCounter.object_id
AND dfv$DynamicFieldJoinCounter.field_id = "
. $DBObject->Quote( $DynamicField->{ID}, 'Integer' ) . ")
";
$DynamicFieldJoinCounter++;
}
}
# Execute a dynamic field search, if a dynamic field where statement exists.
if ($SQLDynamicFieldWhere) {
my @DynamicFieldUserLogins;
# sql uery for the dynamic fields
my $SQLDynamicField
= "SELECT DISTINCT(df_obj_id_name.object_name) FROM dynamic_field_obj_id_name df_obj_id_name "
. $SQLDynamicFieldFrom
. " WHERE "
. $SQLDynamicFieldWhere;
my $UsedCache;
if ( $Self->{CacheObject} ) {
my $DynamicFieldSearchCacheData = $Self->{CacheObject}->Get(
Type => $Self->{CacheType} . '_CustomerSearchDetailDynamicFields',
Key => $SQLDynamicField,
);
if ( defined $DynamicFieldSearchCacheData ) {
if ( ref $DynamicFieldSearchCacheData eq 'ARRAY' ) {
@DynamicFieldUserLogins = @{$DynamicFieldSearchCacheData};
# set the used cache flag
$UsedCache = 1;
}
else {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Invalid ref ' . ref($DynamicFieldSearchCacheData) . '!'
);
return;
}
}
}
# Get the data only from database, if no cache entry exists.
if ( !$UsedCache ) {
return if !$DBObject->Prepare(
SQL => $SQLDynamicField,
);
while ( my @Row = $DBObject->FetchrowArray() ) {
push @DynamicFieldUserLogins, $Row[0];
}
if ( $Self->{CacheObject} ) {
$Self->{CacheObject}->Set(
Type => $Self->{CacheType} . '_CustomerSearchDetailDynamicFields',
Key => $SQLDynamicField,
Value => \@DynamicFieldUserLogins,
TTL => $Self->{CustomerUserMap}->{CacheTTL},
);
}
}
# Add the user logins from the dynamic fields, if a search result exists from the dynamic field search
# or skip the search and return a emptry array ref, if no user logins exists from the dynamic field search.
if (@DynamicFieldUserLogins) {
my $DynamicFieldUserLoginsFilter = '(|';
for my $OneParam (@DynamicFieldUserLogins) {
$DynamicFieldUserLoginsFilter .= "($Self->{CustomerKey}=" . $Self->_ConvertTo($OneParam) . ")";
}
$DynamicFieldUserLoginsFilter .= ')';
# Add the dynamic field user logins filter to the ldap filter.
$Filter = "(&$Filter$DynamicFieldUserLoginsFilter)";
}
else {
return $Result eq 'COUNT' ? 0 : [];
}
}
# Special parameter to exclude some user logins from the search result.
if ( IsArrayRefWithData( $Param{ExcludeUserLogins} ) ) {
my $ExcludeUserLoginsFilter = '(&';
for my $OneParam ( @{ $Param{ExcludeUserLogins} } ) {
$ExcludeUserLoginsFilter .= "(!($Self->{CustomerKey}=" . $Self->_ConvertTo($OneParam) . "))";
}
$ExcludeUserLoginsFilter .= ')';
# Add the exclude user logins filter to the ldap filter.
$Filter = "(&$Filter$ExcludeUserLoginsFilter)";
}
if ( $Self->{AlwaysFilter} ) {
$Filter = "(&$Filter$Self->{AlwaysFilter})";
}
if ( $Self->{ValidFilter} && $Valid ) {
$Filter = "(&$Filter$Self->{ValidFilter})";
}
# Default filter for the search, if no filter exists.
if ( !$Filter ) {
$Filter = "($Self->{CustomerKey}=*)";
}
# Check if OrderBy contains only unique valid values.
my %OrderBySeen;
for my $OrderBy ( @{ $Param{OrderBy} } ) {
if ( !$OrderBy || $OrderBySeen{$OrderBy} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "OrderBy contains invalid value '$OrderBy' or the value is used more than once!",
);
return;
}
# Remember the value to check if it appears more than once.
$OrderBySeen{$OrderBy} = 1;
}
# Check if OrderByDirection array contains only 'Up' or 'Down'.
DIRECTION:
for my $Direction ( @{ $Param{OrderByDirection} } ) {
# Only 'Up' or 'Down' allowed.
next DIRECTION if $Direction eq 'Up';
next DIRECTION if $Direction eq 'Down';
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "OrderByDirection can only contain 'Up' or 'Down'!",
);
return;
}
# Assemble the ORDER BY clause.
my @OrderByFields;
my $OrderByString = '';
my $Count = 0;
ORDERBY:
for my $OrderBy ( @{ $Param{OrderBy} } ) {
next ORDERBY if !$OrderByTable{$OrderBy};
my $Direction = $Param{OrderByDirection}->[$Count] || 'Down';
$OrderByString .= $OrderByTable{$OrderBy} . $Direction;
push @OrderByFields, {
Name => $OrderBy,
DatabaseField => $OrderByTable{$OrderBy},
Direction => $Direction,
};
}
continue {
$Count++;
}
# If there is a possibility that the ordering is not determined
# we add an descending ordering by id.
if ( !grep { $_ eq 'UserLogin' } ( @{ $Param{OrderBy} } ) ) {
push @OrderByFields, {
Name => 'UserLogin',
DatabaseField => "$Self->{CustomerKey}",
Direction => 'Down',
};
}
my $CacheKey = 'CustomerSearchDetail::' . $Result . $Filter . $Param{Limit} . $OrderByString;
if ( $Self->{CacheObject} ) {
my $CacheData = $Self->{CacheObject}->Get(
Type => $Self->{CacheType},
Key => $CacheKey,
);
if ( defined $CacheData ) {
if ( ref $CacheData eq 'ARRAY' ) {
return $CacheData;
}
elsif ( ref $CacheData eq '' ) {
return $CacheData;
}
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Invalid ref ' . ref($CacheData) . '!'
);
return;
}
}
return if !$Self->_Connect();
# cCmbine needed attributes.
my @Attributes = map { $_->{DatabaseField} } @OrderByFields;
# Perform the ldap user search.
my $ResultSearch = $Self->{LDAP}->search(
base => $Self->{BaseDN},
scope => $Self->{SScope},
filter => $Filter,
sizelimit => $Self->{UserSearchListLimit},
attrs => \@Attributes,
);
if ( $ResultSearch->code() ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => $ResultSearch->error(),
);
}
my @TmpCustomerUsers;
for my $Entry ( $ResultSearch->all_entries() ) {
my %Data;
for my $OrderBy (@OrderByFields) {
my $FieldValue = $Entry->get_value( $OrderBy->{DatabaseField} );
$FieldValue = $Self->_ConvertFrom($FieldValue);
$Data{ $OrderBy->{Name} } = $FieldValue;
}
push @TmpCustomerUsers, \%Data;
}
# Sort the customer users.
@TmpCustomerUsers = sort { $Self->_SearchResultSort(@OrderByFields) } @TmpCustomerUsers;
my @IDs;
# Check if user need to be in a group!
if ( $Self->{GroupDN} ) {
FILTERID:
for my $Data (@TmpCustomerUsers) {
my $ResultGroupDN = $Self->{LDAP}->search(
base => $Self->{GroupDN},
scope => $Self->{SScope},
filter => 'memberUid=' . $Data->{UserLogin},
sizelimit => $Self->{UserSearchListLimit},
attrs => ['1.1'],
);
next FILTERID if !$ResultGroupDN->all_entries();
push @IDs, $Data->{UserLogin};
}
}
else {
@IDs = map { $_->{UserLogin} } @TmpCustomerUsers;
}
if ( $Param{Limit} ) {
splice @IDs, $Param{Limit};
}
if ( $Result eq 'COUNT' ) {
if ( $Self->{CacheObject} ) {
$Self->{CacheObject}->Set(
Type => $Self->{CacheType},
Key => $CacheKey,
Value => scalar @IDs,
TTL => $Self->{CustomerUserMap}->{CacheTTL},
);
}
return scalar @IDs;
}
else {
if ( $Self->{CacheObject} ) {
$Self->{CacheObject}->Set(
Type => $Self->{CacheType},
Key => $CacheKey,
Value => \@IDs,
TTL => $Self->{CustomerUserMap}->{CacheTTL},
);
}
return \@IDs;
}
}
sub CustomerIDList {
my ( $Self, %Param ) = @_;
my $Valid = defined $Param{Valid} ? $Param{Valid} : 1;
my $SearchTerm = $Param{SearchTerm} || '';
my $CacheKey = "CustomerIDList::${Valid}::$SearchTerm";
# check cache
if ( $Self->{CacheObject} ) {
my $Result = $Self->{CacheObject}->Get(
Type => $Self->{CacheType},
Key => $CacheKey,
);
return @{$Result} if ref $Result eq 'ARRAY';
}
# prepare filter
my $Filter = "($Self->{CustomerID}=*)";
if ($SearchTerm) {
my $SearchFilter = $Self->{SearchPrefix} . $SearchTerm . $Self->{SearchSuffix};
$SearchFilter =~ s/(\%+)/\%/g;
$SearchFilter =~ s/(\*+)\*/*/g;
# quote LDAP filter value but keep asterisks unescaped (wildcard)
$SearchFilter =~ s/\*/encodedasterisk20160930/g;
$SearchFilter = escape_filter_value($SearchFilter);
$SearchFilter =~ s/encodedasterisk20160930/*/g;
$Filter = "($Self->{CustomerID}=$SearchFilter)";
}
if ( $Self->{AlwaysFilter} ) {
$Filter = "(&$Filter$Self->{AlwaysFilter})";
}
# add valid filter
if ( $Self->{ValidFilter} && $Valid ) {
$Filter = "(&$Filter$Self->{ValidFilter})";
}
# create ldap connect
return if !$Self->_Connect();
# combine needed attrs
my @Attributes = ( $Self->{CustomerKey}, $Self->{CustomerID} );
# perform user search
my $Result = $Self->{LDAP}->search(
base => $Self->{BaseDN},
scope => $Self->{SScope},
filter => $Filter,
sizelimit => $Self->{UserSearchListLimit},
attrs => \@Attributes,
);
# log ldap errors
if ( $Result->code() ) {
if ( $Result->code() == 4 ) {
# Result code 4 (LDAP_SIZELIMIT_EXCEEDED) is normal if there
# are more items in LDAP than search limit defined in OTRS or
# in LDAP server. Avoid spamming logs with such errors.
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'debug',
Message => 'LDAP size limit exceeded (' . $Result->error() . ').',
);
}
else {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Search failed! ' . $Result->error(),
);
}
}
my %Users;
for my $Entry ( $Result->all_entries() ) {
my $FieldValue = $Entry->get_value( $Self->{CustomerID} );
$FieldValue = defined $FieldValue ? $FieldValue : '';
my $KeyValue = $Entry->get_value( $Self->{CustomerKey} );
$KeyValue = defined $KeyValue ? $KeyValue : '';
$Users{ $Self->_ConvertFrom($KeyValue) } = $Self->_ConvertFrom($FieldValue);
}
# check if user need to be in a group!
if ( $Self->{GroupDN} ) {
for my $Filter2 ( sort keys %Users ) {
my $Result2 = $Self->{LDAP}->search(
base => $Self->{GroupDN},
scope => $Self->{SScope},
filter => 'memberUid=' . escape_filter_value($Filter2),
sizelimit => $Self->{UserSearchListLimit},
attrs => ['1.1'],
);
if ( !$Result2->all_entries() ) {
delete $Users{$Filter2};
}
}
}
# make CustomerIDs unique
my %Tmp;
@Tmp{ values %Users } = undef;
my @Result = keys %Tmp;
# cache request
if ( $Self->{CacheObject} ) {
$Self->{CacheObject}->Set(
Type => $Self->{CacheType},
Key => $CacheKey,
Value => \@Result,
TTL => $Self->{CustomerUserMap}->{CacheTTL},
);
}
return @Result;
}
sub CustomerIDs {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{User} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need User!'
);
return;
}
# check cache
if ( $Self->{CacheObject} ) {
my $CustomerIDs = $Self->{CacheObject}->Get(
Type => $Self->{CacheType},
Key => "CustomerIDs::$Param{User}",
);
return @{$CustomerIDs} if ref $CustomerIDs eq 'ARRAY';
}
# get customer data
my %Data = $Self->CustomerUserDataGet(
User => $Param{User},
);
# there are multi customer ids
my @CustomerIDs;
if ( $Data{UserCustomerIDs} ) {
# used separators
SEPARATOR:
for my $Separator ( ';', ',', '|' ) {
next SEPARATOR if $Data{UserCustomerIDs} !~ /\Q$Separator\E/;
# split it
my @IDs = split /\Q$Separator\E/, $Data{UserCustomerIDs};
for my $ID (@IDs) {
$ID =~ s/^\s+//g;
$ID =~ s/\s+$//g;
push @CustomerIDs, $ID;
}
last SEPARATOR;
}
# fallback if no separator got found
if ( !@CustomerIDs ) {
$Data{UserCustomerIDs} =~ s/^\s+//g;
$Data{UserCustomerIDs} =~ s/\s+$//g;
push @CustomerIDs, $Data{UserCustomerIDs};
}
}
# use also the primary customer id
if ( $Data{UserCustomerID} && !$Self->{ExcludePrimaryCustomerID} ) {
push @CustomerIDs, $Data{UserCustomerID};
}
# cache request
if ( $Self->{CacheObject} ) {
$Self->{CacheObject}->Set(
Type => $Self->{CacheType},
Key => 'CustomerIDs::' . $Param{User},
Value => \@CustomerIDs,
TTL => $Self->{CustomerUserMap}->{CacheTTL},
);
}
return @CustomerIDs;
}
sub CustomerUserDataGet {
my ( $Self, %Param ) = @_;
# check needed stuff
if ( !$Param{User} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need User!'
);
return;
}
# perform user search
my @Attributes;
ENTRY:
for my $Entry ( @{ $Self->{CustomerUserMap}->{Map} } ) {
next ENTRY if $Entry->[5] eq 'dynamic_field';
push( @Attributes, $Entry->[2] );
}
my $Filter = "($Self->{CustomerKey}=" . escape_filter_value( $Param{User} ) . ')';
# prepare filter
if ( $Self->{AlwaysFilter} ) {
$Filter = "(&$Filter$Self->{AlwaysFilter})";
}
# check cache
if ( $Self->{CacheObject} ) {
my $Data = $Self->{CacheObject}->Get(
Type => $Self->{CacheType},
Key => 'CustomerUserDataGet::' . $Param{User},
);
return %{$Data} if ref $Data eq 'HASH';
}
# create ldap connect
return if !$Self->_Connect();
# perform search
my $Result = $Self->{LDAP}->search(
base => $Self->{BaseDN},
scope => $Self->{SScope},
filter => $Filter,
attrs => \@Attributes,
);
# log ldap errors
if ( $Result->code() ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => $Result->error(),
);
return;
}
# get first entry
my $Result2 = $Result->entry(0);
if ( !$Result2 ) {
return;
}
# get customer user info
my %Data;
ENTRY:
for my $Entry ( @{ $Self->{CustomerUserMap}->{Map} } ) {
next ENTRY if $Entry->[5] eq 'dynamic_field';
my $Value = $Self->_ConvertFrom( $Result2->get_value( $Entry->[2] ) ) || '';
if ( $Value && $Entry->[2] =~ /^targetaddress$/i ) {
$Value =~ s/SMTP:(.*)/$1/;
}
$Data{ $Entry->[0] } = $Value;
}
return if !$Data{UserLogin};
# to build the UserMailString
my $UserMailString = '';
my @UserMailStringParts;
my $CustomerUserListFieldsMap = $Self->{CustomerUserMap}->{CustomerUserListFields};
if ( !IsArrayRefWithData($CustomerUserListFieldsMap) ) {
$CustomerUserListFieldsMap = [ 'first_name', 'last_name', 'email', ];
}
for my $Field ( @{$CustomerUserListFieldsMap} ) {
my $Value = $Self->_ConvertFrom( $Result2->get_value($Field) ) || '';
if ($Value) {
if ( $Field =~ /^targetaddress$/i ) {
$Value =~ s/SMTP:(.*)/$1/;
}
push @UserMailStringParts, $Value;
}
}
$UserMailString = join ' ', @UserMailStringParts;
$UserMailString =~ s/^(.*)\s(.+?\@.+?\..+?)(\s|)$/"$1" <$2>/;
# add the UserMailString to the data hash
$Data{UserMailString} = $UserMailString;
# compat!
$Data{UserID} = $Data{UserLogin};
# get preferences
my %Preferences = $Self->GetPreferences( UserID => $Data{UserLogin} );
# add last login timestamp
if ( $Preferences{UserLastLogin} ) {
my $DateTimeObject = $Kernel::OM->Create(
'Kernel::System::DateTime',
ObjectParams => {
Epoch => $Preferences{UserLastLogin},
},
);
$Preferences{UserLastLoginTimestamp} = $DateTimeObject->ToString();
}
# cache request
if ( $Self->{CacheObject} ) {
$Self->{CacheObject}->Set(
Type => $Self->{CacheType},
Key => 'CustomerUserDataGet::' . $Param{User},
Value => { %Data, %Preferences },
TTL => $Self->{CustomerUserMap}->{CacheTTL},
);
}
return ( %Data, %Preferences );
}
sub CustomerUserAdd {
my ( $Self, %Param ) = @_;
# check ro/rw
if ( $Self->{ReadOnly} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Customer backend is read only!'
);
return;
}
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Not supported for this module!'
);
return;
}
sub CustomerUserUpdate {
my ( $Self, %Param ) = @_;
# check ro/rw
if ( $Self->{ReadOnly} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Customer backend is read only!'
);
return;
}
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Not supported for this module!'
);
return;
}
sub SetPassword {
my ( $Self, %Param ) = @_;
my $Pw = $Param{PW} || '';
# check ro/rw
if ( $Self->{ReadOnly} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Customer backend is read only!'
);
return;
}
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Not supported for this module!'
);
return;
}
sub GenerateRandomPassword {
my ( $Self, %Param ) = @_;
# generated passwords are eight characters long by default.
my $Size = $Param{Size} || 8;
# The list of characters that can appear in a randomly generated password.
# Note that users can put any character into a password they choose themselves.
my @PwChars = ( 0 .. 9, 'A' .. 'Z', 'a' .. 'z', '-', '_', '!', '@', '#', '$', '%', '^', '&', '*' );
# number of characters in the list.
my $PwCharsLen = scalar(@PwChars);
# generate the password.
my $Password = '';
for ( my $i = 0; $i < $Size; $i++ ) {
$Password .= $PwChars[ rand $PwCharsLen ];
}
return $Password;
}
sub SetPreferences {
my ( $Self, %Param ) = @_;
# check needed params
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need UserID!'
);
return;
}
# cache reset
if ( $Self->{CacheObject} ) {
$Self->{CacheObject}->Delete(
Type => $Self->{CacheType},
Key => "CustomerUserDataGet::$Param{UserID}",
);
}
return $Self->{PreferencesObject}->SetPreferences(%Param);
}
sub GetPreferences {
my ( $Self, %Param ) = @_;
# check needed params
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need UserID!'
);
return;
}
return $Self->{PreferencesObject}->GetPreferences(%Param);
}
sub SearchPreferences {
my ( $Self, %Param ) = @_;
return $Self->{PreferencesObject}->SearchPreferences(%Param);
}
sub _ConvertFrom {
my ( $Self, $Text ) = @_;
return if !defined $Text;
if ( !$Self->{SourceCharset} ) {
return $Text;
}
return $Kernel::OM->Get('Kernel::System::Encode')->Convert(
Text => $Text,
From => $Self->{SourceCharset},
To => 'utf-8',
);
}
sub _ConvertTo {
my ( $Self, $Text ) = @_;
return if !defined $Text;
# get encode object
my $EncodeObject = $Kernel::OM->Get('Kernel::System::Encode');
if ( !$Self->{SourceCharset} ) {
$EncodeObject->EncodeInput( \$Text );
return $Text;
}
return $EncodeObject->Convert(
Text => $Text,
To => $Self->{SourceCharset},
From => 'utf-8',
);
}
sub _CustomerUserCacheClear {
my ( $Self, %Param ) = @_;
return if !$Self->{CacheObject};
if ( !$Param{UserLogin} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need UserLogin!',
);
return;
}
$Self->{CacheObject}->Delete(
Type => $Self->{CacheType},
Key => "CustomerUserDataGet::$Param{UserLogin}",
);
$Self->{CacheObject}->Delete(
Type => $Self->{CacheType},
Key => "CustomerName::$Param{UserLogin}",
);
$Self->{CacheObject}->CleanUp(
Type => $Self->{CacheType} . '_CustomerSearch',
);
$Self->{CacheObject}->CleanUp(
Type => 'CustomerGroup',
);
return 1;
}
sub _SearchResultSort {
my ( $Self, @OrderByFields ) = @_;
for my $OrderBy (@OrderByFields) {
my $Compare;
if ( $OrderBy->{Direction} && $OrderBy->{Direction} eq 'Up' ) {
$Compare = lc( $a->{ $OrderBy->{Name} } ) cmp lc( $b->{ $OrderBy->{Name} } );
}
else {
$Compare = lc( $b->{ $OrderBy->{Name} } ) cmp lc( $a->{ $OrderBy->{Name} } );
}
return $Compare if $Compare;
}
return 0;
}
sub DESTROY {
my ( $Self, %Param ) = @_;
# take down session
if ( $Self->{LDAP} ) {
$Self->{LDAP}->unbind();
}
return 1;
}
1;