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::System::User; 10 11use strict; 12use warnings; 13 14use Crypt::PasswdMD5 qw(unix_md5_crypt apache_md5_crypt); 15use Digest::SHA; 16 17our @ObjectDependencies = ( 18 'Kernel::Config', 19 'Kernel::System::Cache', 20 'Kernel::System::CheckItem', 21 'Kernel::System::DB', 22 'Kernel::System::Encode', 23 'Kernel::System::Log', 24 'Kernel::System::Main', 25 'Kernel::System::SearchProfile', 26 'Kernel::System::DateTime', 27 'Kernel::System::Valid', 28); 29 30=head1 NAME 31 32Kernel::System::User - user lib 33 34=head1 DESCRIPTION 35 36All user functions. E. g. to add and updated user and other functions. 37 38=head1 PUBLIC INTERFACE 39 40=head2 new() 41 42Don't use the constructor directly, use the ObjectManager instead: 43 44 my $UserObject = $Kernel::OM->Get('Kernel::System::User'); 45 46=cut 47 48sub new { 49 my ( $Type, %Param ) = @_; 50 51 # allocate new hash for object 52 my $Self = {}; 53 bless( $Self, $Type ); 54 55 # get config object 56 my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); 57 58 # get user table 59 $Self->{UserTable} = $ConfigObject->Get('DatabaseUserTable') || 'user'; 60 $Self->{UserTableUserID} = $ConfigObject->Get('DatabaseUserTableUserID') || 'id'; 61 $Self->{UserTableUserPW} = $ConfigObject->Get('DatabaseUserTableUserPW') || 'pw'; 62 $Self->{UserTableUser} = $ConfigObject->Get('DatabaseUserTableUser') || 'login'; 63 64 $Self->{CacheType} = 'User'; 65 $Self->{CacheTTL} = 60 * 60 * 24 * 20; 66 67 # set lower if database is case sensitive 68 $Self->{Lower} = ''; 69 if ( $Kernel::OM->Get('Kernel::System::DB')->GetDatabaseFunction('CaseSensitive') ) { 70 $Self->{Lower} = 'LOWER'; 71 } 72 73 return $Self; 74} 75 76=head2 GetUserData() 77 78get user data (UserLogin, UserFirstname, UserLastname, UserEmail, ...) 79 80 my %User = $UserObject->GetUserData( 81 UserID => 123, 82 ); 83 84 or 85 86 my %User = $UserObject->GetUserData( 87 User => 'franz', 88 Valid => 1, # not required -> 0|1 (default 0) 89 # returns only data if user is valid 90 NoOutOfOffice => 1, # not required -> 0|1 (default 0) 91 # returns data without out of office infos 92 ); 93 94=cut 95 96sub GetUserData { 97 my ( $Self, %Param ) = @_; 98 99 # check needed stuff 100 if ( !$Param{User} && !$Param{UserID} ) { 101 $Kernel::OM->Get('Kernel::System::Log')->Log( 102 Priority => 'error', 103 Message => 'Need User or UserID!', 104 ); 105 return; 106 } 107 108 # get config object 109 my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); 110 111 # get configuration for the full name order 112 my $FirstnameLastNameOrder = $ConfigObject->Get('FirstnameLastnameOrder') || 0; 113 114 # check if result is cached 115 if ( $Param{Valid} ) { 116 $Param{Valid} = 1; 117 } 118 else { 119 $Param{Valid} = 0; 120 } 121 if ( $Param{NoOutOfOffice} ) { 122 $Param{NoOutOfOffice} = 1; 123 } 124 else { 125 $Param{NoOutOfOffice} = 0; 126 } 127 128 my $CacheKey; 129 if ( $Param{User} ) { 130 $CacheKey = join '::', 'GetUserData', 'User', 131 $Param{User}, 132 $Param{Valid}, 133 $FirstnameLastNameOrder, 134 $Param{NoOutOfOffice}; 135 } 136 else { 137 $CacheKey = join '::', 'GetUserData', 'UserID', 138 $Param{UserID}, 139 $Param{Valid}, 140 $FirstnameLastNameOrder, 141 $Param{NoOutOfOffice}; 142 } 143 144 # check cache 145 my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get( 146 Type => $Self->{CacheType}, 147 Key => $CacheKey, 148 ); 149 return %{$Cache} if $Cache; 150 151 # get initial data 152 my @Bind; 153 my $SQL = "SELECT $Self->{UserTableUserID}, $Self->{UserTableUser}, " 154 . " title, first_name, last_name, $Self->{UserTableUserPW}, valid_id, " 155 . " create_time, change_time FROM $Self->{UserTable} WHERE "; 156 157 if ( $Param{User} ) { 158 my $User = lc $Param{User}; 159 $SQL .= " $Self->{Lower}($Self->{UserTableUser}) = ?"; 160 push @Bind, \$User; 161 } 162 else { 163 $SQL .= " $Self->{UserTableUserID} = ?"; 164 push @Bind, \$Param{UserID}; 165 } 166 167 # get database object 168 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 169 170 return if !$DBObject->Prepare( 171 SQL => $SQL, 172 Bind => \@Bind, 173 Limit => 1, 174 ); 175 176 my %Data; 177 while ( my @Row = $DBObject->FetchrowArray() ) { 178 $Data{UserID} = $Row[0]; 179 $Data{UserLogin} = $Row[1]; 180 $Data{UserTitle} = $Row[2]; 181 $Data{UserFirstname} = $Row[3]; 182 $Data{UserLastname} = $Row[4]; 183 $Data{UserPw} = $Row[5]; 184 $Data{ValidID} = $Row[6]; 185 $Data{CreateTime} = $Row[7]; 186 $Data{ChangeTime} = $Row[8]; 187 } 188 189 # check data 190 if ( !$Data{UserID} ) { 191 if ( $Param{User} ) { 192 $Kernel::OM->Get('Kernel::System::Log')->Log( 193 Priority => 'notice', 194 Message => "No UserData for user: '$Param{User}'.", 195 ); 196 return; 197 } 198 else { 199 $Kernel::OM->Get('Kernel::System::Log')->Log( 200 Priority => 'notice', 201 Message => "No UserData for user id: '$Param{UserID}'.", 202 ); 203 return; 204 } 205 } 206 207 # Store CacheTTL locally so that we can reduce it for users that are out of office. 208 my $CacheTTL = $Self->{CacheTTL}; 209 210 # check valid, return if there is locked for valid users 211 if ( $Param{Valid} ) { 212 213 my $Hit = 0; 214 215 for ( $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet() ) { 216 if ( $_ eq $Data{ValidID} ) { 217 $Hit = 1; 218 } 219 } 220 221 if ( !$Hit ) { 222 223 # set cache 224 $Kernel::OM->Get('Kernel::System::Cache')->Set( 225 Type => $Self->{CacheType}, 226 TTL => $CacheTTL, 227 Key => $CacheKey, 228 Value => {}, 229 ); 230 return; 231 } 232 } 233 234 # generate the full name and save it in the hash 235 my $UserFullname = $Self->_UserFullname( 236 %Data, 237 NameOrder => $FirstnameLastNameOrder, 238 ); 239 240 # save the generated fullname in the hash. 241 $Data{UserFullname} = $UserFullname; 242 243 # get preferences 244 my %Preferences = $Self->GetPreferences( UserID => $Data{UserID} ); 245 246 my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime'); 247 248 # add last login timestamp 249 if ( $Preferences{UserLastLogin} ) { 250 251 my $UserLastLoginTimeObj = $Kernel::OM->Create( 252 'Kernel::System::DateTime', 253 ObjectParams => { 254 Epoch => $Preferences{UserLastLogin} 255 } 256 ); 257 258 $Preferences{UserLastLoginTimestamp} = $UserLastLoginTimeObj->ToString(); 259 } 260 261 # check compat stuff 262 if ( !$Preferences{UserEmail} ) { 263 $Preferences{UserEmail} = $Data{UserLogin}; 264 } 265 266 # out of office check 267 if ( !$Param{NoOutOfOffice} ) { 268 if ( $Preferences{OutOfOffice} ) { 269 270 my $CurrentTimeObject = $Kernel::OM->Create('Kernel::System::DateTime'); 271 my $CreateDTObject = sub { 272 my %Param = @_; 273 274 return $Kernel::OM->Create( 275 'Kernel::System::DateTime', 276 ObjectParams => { 277 String => sprintf( 278 '%d-%02d-%02d %s', 279 $Param{Year}, 280 $Param{Month}, 281 $Param{Day}, 282 $Param{Time} 283 ), 284 }, 285 ); 286 }; 287 288 my $TimeStartObj = $CreateDTObject->( 289 Year => $Preferences{OutOfOfficeStartYear}, 290 Month => $Preferences{OutOfOfficeStartMonth}, 291 Day => $Preferences{OutOfOfficeStartDay}, 292 Time => '00:00:00', 293 ); 294 295 my $TimeEndObj = $CreateDTObject->( 296 Year => $Preferences{OutOfOfficeEndYear}, 297 Month => $Preferences{OutOfOfficeEndMonth}, 298 Day => $Preferences{OutOfOfficeEndDay}, 299 Time => '23:59:59', 300 ); 301 302 if ( $TimeStartObj < $CurrentTimeObject && $TimeEndObj > $CurrentTimeObject ) { 303 my $OutOfOfficeMessageTemplate = 304 $ConfigObject->Get('OutOfOfficeMessageTemplate') || '*** out of office until %s (%s d left) ***'; 305 my $TillDate = sprintf( 306 '%04d-%02d-%02d', 307 $Preferences{OutOfOfficeEndYear}, 308 $Preferences{OutOfOfficeEndMonth}, 309 $Preferences{OutOfOfficeEndDay} 310 ); 311 my $Till = int( ( $TimeEndObj->ToEpoch() - $CurrentTimeObject->ToEpoch() ) / 60 / 60 / 24 ); 312 $Preferences{OutOfOfficeMessage} = sprintf( $OutOfOfficeMessageTemplate, $TillDate, $Till ); 313 $Data{UserFullname} .= ' ' . $Preferences{OutOfOfficeMessage}; 314 } 315 316 # Reduce CacheTTL to one hour for users that are out of office to make sure the cache expires timely 317 # even if there is no update action. 318 $CacheTTL = 60 * 60 * 1; 319 } 320 } 321 322 # merge hash 323 %Data = ( %Data, %Preferences ); 324 325 # add preferences defaults 326 my $Config = $ConfigObject->Get('PreferencesGroups'); 327 if ( $Config && ref $Config eq 'HASH' ) { 328 329 KEY: 330 for my $Key ( sort keys %{$Config} ) { 331 332 next KEY if !defined $Config->{$Key}->{DataSelected}; 333 334 # check if data is defined 335 next KEY if defined $Data{ $Config->{$Key}->{PrefKey} }; 336 337 # set default data 338 $Data{ $Config->{$Key}->{PrefKey} } = $Config->{$Key}->{DataSelected}; 339 } 340 } 341 342 # set cache 343 $Kernel::OM->Get('Kernel::System::Cache')->Set( 344 Type => $Self->{CacheType}, 345 TTL => $CacheTTL, 346 Key => $CacheKey, 347 Value => \%Data, 348 ); 349 350 return %Data; 351} 352 353=head2 UserAdd() 354 355to add new users 356 357 my $UserID = $UserObject->UserAdd( 358 UserFirstname => 'Huber', 359 UserLastname => 'Manfred', 360 UserLogin => 'mhuber', 361 UserPw => 'some-pass', # not required 362 UserEmail => 'email@example.com', 363 UserMobile => '1234567890', # not required 364 ValidID => 1, 365 ChangeUserID => 123, 366 ); 367 368=cut 369 370sub UserAdd { 371 my ( $Self, %Param ) = @_; 372 373 # check needed stuff 374 for (qw(UserFirstname UserLastname UserLogin UserEmail ValidID ChangeUserID)) { 375 if ( !$Param{$_} ) { 376 $Kernel::OM->Get('Kernel::System::Log')->Log( 377 Priority => 'error', 378 Message => "Need $_!", 379 ); 380 return; 381 } 382 } 383 384 # check if a user with this login (username) already exits 385 if ( $Self->UserLoginExistsCheck( UserLogin => $Param{UserLogin} ) ) { 386 $Kernel::OM->Get('Kernel::System::Log')->Log( 387 Priority => 'error', 388 Message => "A user with the username '$Param{UserLogin}' already exists.", 389 ); 390 return; 391 } 392 393 # check email address 394 if ( 395 $Param{UserEmail} 396 && !$Kernel::OM->Get('Kernel::System::CheckItem')->CheckEmail( Address => $Param{UserEmail} ) 397 && grep { $_ eq $Param{ValidID} } $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet() 398 ) 399 { 400 $Kernel::OM->Get('Kernel::System::Log')->Log( 401 Priority => 'error', 402 Message => "Email address ($Param{UserEmail}) not valid (" 403 . $Kernel::OM->Get('Kernel::System::CheckItem')->CheckError() . ")!", 404 ); 405 return; 406 } 407 408 # check password 409 if ( !$Param{UserPw} ) { 410 $Param{UserPw} = $Self->GenerateRandomPassword(); 411 } 412 413 # get database object 414 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 415 416 # Don't store the user's password in plaintext initially. It will be stored in a 417 # hashed version later with SetPassword(). 418 my $RandomPassword = $Self->GenerateRandomPassword(); 419 420 # sql 421 return if !$DBObject->Do( 422 SQL => "INSERT INTO $Self->{UserTable} " 423 . "(title, first_name, last_name, " 424 . " $Self->{UserTableUser}, $Self->{UserTableUserPW}, " 425 . " valid_id, create_time, create_by, change_time, change_by)" 426 . " VALUES " 427 . " (?, ?, ?, ?, ?, ?, current_timestamp, ?, current_timestamp, ?)", 428 Bind => [ 429 \$Param{UserTitle}, \$Param{UserFirstname}, \$Param{UserLastname}, 430 \$Param{UserLogin}, \$RandomPassword, \$Param{ValidID}, 431 \$Param{ChangeUserID}, \$Param{ChangeUserID}, 432 ], 433 ); 434 435 # get new user id 436 my $UserLogin = lc $Param{UserLogin}; 437 return if !$DBObject->Prepare( 438 SQL => "SELECT $Self->{UserTableUserID} FROM $Self->{UserTable} " 439 . " WHERE $Self->{Lower}($Self->{UserTableUser}) = ?", 440 Bind => [ \$UserLogin ], 441 Limit => 1, 442 ); 443 444 # fetch the result 445 my $UserID; 446 while ( my @Row = $DBObject->FetchrowArray() ) { 447 $UserID = $Row[0]; 448 } 449 450 # check if user exists 451 if ( !$UserID ) { 452 $Kernel::OM->Get('Kernel::System::Log')->Log( 453 Priority => 'notice', 454 Message => "Unable to create User: '$Param{UserLogin}' ($Param{ChangeUserID})!", 455 ); 456 return; 457 } 458 459 # log notice 460 $Kernel::OM->Get('Kernel::System::Log')->Log( 461 Priority => 'notice', 462 Message => 463 "User: '$Param{UserLogin}' ID: '$UserID' created successfully ($Param{ChangeUserID})!", 464 ); 465 466 # set password 467 $Self->SetPassword( 468 UserLogin => $Param{UserLogin}, 469 PW => $Param{UserPw} 470 ); 471 472 my @UserPreferences = grep { $_ =~ m{^User}xsi } sort keys %Param; 473 474 USERPREFERENCE: 475 for my $UserPreference (@UserPreferences) { 476 477 # UserEmail is required. 478 next USERPREFERENCE if $UserPreference eq 'UserEmail' && !$Param{UserEmail}; 479 480 # Set user preferences. 481 # Native user data will not be overwriten (handeled by SetPreferences()). 482 $Self->SetPreferences( 483 UserID => $UserID, 484 Key => $UserPreference, 485 Value => $Param{$UserPreference} || '', 486 ); 487 } 488 489 # delete cache 490 $Kernel::OM->Get('Kernel::System::Cache')->CleanUp( 491 Type => $Self->{CacheType}, 492 ); 493 494 return $UserID; 495} 496 497=head2 UserUpdate() 498 499to update users 500 501 $UserObject->UserUpdate( 502 UserID => 4321, 503 UserFirstname => 'Huber', 504 UserLastname => 'Manfred', 505 UserLogin => 'mhuber', 506 UserPw => 'some-pass', # not required 507 UserEmail => 'email@example.com', 508 UserMobile => '1234567890', # not required 509 ValidID => 1, 510 ChangeUserID => 123, 511 ); 512 513=cut 514 515sub UserUpdate { 516 my ( $Self, %Param ) = @_; 517 518 # check needed stuff 519 for (qw(UserID UserFirstname UserLastname UserLogin ValidID ChangeUserID)) { 520 if ( !$Param{$_} ) { 521 $Kernel::OM->Get('Kernel::System::Log')->Log( 522 Priority => 'error', 523 Message => "Need $_!", 524 ); 525 return; 526 } 527 } 528 529 # store old user login for later use 530 my $OldUserLogin = $Self->UserLookup( 531 UserID => $Param{UserID}, 532 ); 533 534 # check if a user with this login (username) already exists 535 if ( 536 $Self->UserLoginExistsCheck( 537 UserLogin => $Param{UserLogin}, 538 UserID => $Param{UserID} 539 ) 540 ) 541 { 542 $Kernel::OM->Get('Kernel::System::Log')->Log( 543 Priority => 'error', 544 Message => "A user with the username '$Param{UserLogin}' already exists.", 545 ); 546 return; 547 } 548 549 # check email address 550 if ( 551 $Param{UserEmail} 552 && !$Kernel::OM->Get('Kernel::System::CheckItem')->CheckEmail( Address => $Param{UserEmail} ) 553 && grep { $_ eq $Param{ValidID} } $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet() 554 ) 555 { 556 $Kernel::OM->Get('Kernel::System::Log')->Log( 557 Priority => 'error', 558 Message => "Email address ($Param{UserEmail}) not valid (" 559 . $Kernel::OM->Get('Kernel::System::CheckItem')->CheckError() . ")!", 560 ); 561 return; 562 } 563 564 # update db 565 return if !$Kernel::OM->Get('Kernel::System::DB')->Do( 566 SQL => "UPDATE $Self->{UserTable} SET title = ?, first_name = ?, last_name = ?, " 567 . " $Self->{UserTableUser} = ?, valid_id = ?, " 568 . " change_time = current_timestamp, change_by = ? " 569 . " WHERE $Self->{UserTableUserID} = ?", 570 Bind => [ 571 \$Param{UserTitle}, \$Param{UserFirstname}, \$Param{UserLastname}, 572 \$Param{UserLogin}, \$Param{ValidID}, \$Param{ChangeUserID}, \$Param{UserID}, 573 ], 574 ); 575 576 # check pw 577 if ( $Param{UserPw} ) { 578 $Self->SetPassword( 579 UserLogin => $Param{UserLogin}, 580 PW => $Param{UserPw} 581 ); 582 } 583 584 my @UserPreferences = grep { $_ =~ m{^User}xsi } sort keys %Param; 585 586 USERPREFERENCE: 587 for my $UserPreference (@UserPreferences) { 588 589 # UserEmail is required. 590 next USERPREFERENCE if $UserPreference eq 'UserEmail' && !$Param{UserEmail}; 591 592 # Set user preferences. 593 # Native user data will not be overwriten (handeled by SetPreferences()). 594 $Self->SetPreferences( 595 UserID => $Param{UserID}, 596 Key => $UserPreference, 597 Value => $Param{$UserPreference} || '', 598 ); 599 } 600 601 # update search profiles if the UserLogin changed 602 if ( lc $OldUserLogin ne lc $Param{UserLogin} ) { 603 $Kernel::OM->Get('Kernel::System::SearchProfile')->SearchProfileUpdateUserLogin( 604 Base => 'TicketSearch', 605 UserLogin => $OldUserLogin, 606 NewUserLogin => $Param{UserLogin}, 607 ); 608 } 609 610 $Self->_UserCacheClear( UserID => $Param{UserID} ); 611 612 # TODO Not needed to delete the cache if ValidID or Name was not changed 613 614 my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache'); 615 my $SystemPermissionConfig = $Kernel::OM->Get('Kernel::Config')->Get('System::Permission') || []; 616 617 for my $Type ( @{$SystemPermissionConfig}, 'rw' ) { 618 619 $CacheObject->Delete( 620 Type => 'GroupPermissionUserGet', 621 Key => 'PermissionUserGet::' . $Param{UserID} . '::' . $Type, 622 ); 623 } 624 625 $CacheObject->CleanUp( 626 Type => 'GroupPermissionGroupGet', 627 ); 628 629 return 1; 630} 631 632=head2 UserSearch() 633 634to search users 635 636 my %List = $UserObject->UserSearch( 637 Search => '*some*', # also 'hans+huber' possible 638 Valid => 1, # not required 639 ); 640 641 my %List = $UserObject->UserSearch( 642 UserLogin => '*some*', 643 Limit => 50, 644 Valid => 1, # not required 645 ); 646 647 my %List = $UserObject->UserSearch( 648 PostMasterSearch => 'email@example.com', 649 Valid => 1, # not required 650 ); 651 652Returns hash of UserID, Login pairs: 653 654 my %List = ( 655 1 => 'root@locahost', 656 4 => 'admin', 657 9 => 'joe', 658 ); 659 660For PostMasterSearch, it returns hash of UserID, Email pairs: 661 662 my %List = ( 663 4 => 'john@example.com', 664 9 => 'joe@example.com', 665 ); 666 667=cut 668 669sub UserSearch { 670 my ( $Self, %Param ) = @_; 671 672 my %Users; 673 my $Valid = $Param{Valid} // 1; 674 675 # check needed stuff 676 if ( !$Param{Search} && !$Param{UserLogin} && !$Param{PostMasterSearch} ) { 677 $Kernel::OM->Get('Kernel::System::Log')->Log( 678 Priority => 'error', 679 Message => 'Need Search, UserLogin or PostMasterSearch!', 680 ); 681 return; 682 } 683 684 # get database object 685 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 686 687 # get like escape string needed for some databases (e.g. oracle) 688 my $LikeEscapeString = $DBObject->GetDatabaseFunction('LikeEscapeString'); 689 690 # build SQL string 691 my $SQL = "SELECT $Self->{UserTableUserID}, login 692 FROM $Self->{UserTable} WHERE "; 693 my @Bind; 694 695 if ( $Param{Search} ) { 696 697 my %QueryCondition = $DBObject->QueryCondition( 698 Key => [qw(login first_name last_name)], 699 Value => $Param{Search}, 700 BindMode => 1, 701 ); 702 $SQL .= $QueryCondition{SQL} . ' '; 703 push @Bind, @{ $QueryCondition{Values} }; 704 } 705 elsif ( $Param{PostMasterSearch} ) { 706 707 my %UserID = $Self->SearchPreferences( 708 Key => 'UserEmail', 709 Value => $Param{PostMasterSearch}, 710 ); 711 712 for ( sort keys %UserID ) { 713 my %User = $Self->GetUserData( 714 UserID => $_, 715 Valid => $Param{Valid}, 716 ); 717 if (%User) { 718 return %UserID; 719 } 720 } 721 722 return; 723 } 724 elsif ( $Param{UserLogin} ) { 725 726 my $UserLogin = lc $Param{UserLogin}; 727 $SQL .= " $Self->{Lower}($Self->{UserTableUser}) LIKE ? $LikeEscapeString"; 728 $UserLogin =~ s/\*/%/g; 729 $UserLogin = $DBObject->Quote( $UserLogin, 'Like' ); 730 push @Bind, \$UserLogin; 731 } 732 733 # add valid option 734 if ($Valid) { 735 $SQL .= "AND valid_id IN (" 736 . join( ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet() ) . ")"; 737 } 738 739 # get data 740 return if !$DBObject->Prepare( 741 SQL => $SQL, 742 Bind => \@Bind, 743 Limit => $Self->{UserSearchListLimit} || $Param{Limit}, 744 ); 745 746 # fetch the result 747 while ( my @Row = $DBObject->FetchrowArray() ) { 748 $Users{ $Row[0] } = $Row[1]; 749 } 750 751 return %Users; 752} 753 754=head2 SetPassword() 755 756to set users passwords 757 758 $UserObject->SetPassword( 759 UserLogin => 'some-login', 760 PW => 'some-new-password' 761 ); 762 763=cut 764 765sub SetPassword { 766 my ( $Self, %Param ) = @_; 767 768 # check needed stuff 769 if ( !$Param{UserLogin} ) { 770 $Kernel::OM->Get('Kernel::System::Log')->Log( 771 Priority => 'error', 772 Message => 'Need UserLogin!' 773 ); 774 return; 775 } 776 777 # get old user data 778 my %User = $Self->GetUserData( User => $Param{UserLogin} ); 779 if ( !$User{UserLogin} ) { 780 $Kernel::OM->Get('Kernel::System::Log')->Log( 781 Priority => 'error', 782 Message => 'No such User!', 783 ); 784 return; 785 } 786 787 my $Pw = $Param{PW} || ''; 788 my $CryptedPw = ''; 789 790 my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); 791 792 my $CryptType = $ConfigObject->Get('AuthModule::DB::CryptType') || 'sha2'; 793 794 # crypt plain (no crypt at all) 795 if ( $CryptType eq 'plain' ) { 796 $CryptedPw = $Pw; 797 } 798 799 # crypt with UNIX crypt 800 elsif ( $CryptType eq 'crypt' ) { 801 802 # encode output, needed by crypt() only non utf8 signs 803 $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); 804 $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Param{UserLogin} ); 805 806 $CryptedPw = crypt( $Pw, $Param{UserLogin} ); 807 } 808 809 # crypt with md5 810 elsif ( $CryptType eq 'md5' || !$CryptType ) { 811 812 # encode output, needed by unix_md5_crypt() only non utf8 signs 813 $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); 814 $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Param{UserLogin} ); 815 816 $CryptedPw = unix_md5_crypt( $Pw, $Param{UserLogin} ); 817 } 818 819 # crypt with md5 (compatible with Apache's .htpasswd files) 820 elsif ( $CryptType eq 'apr1' ) { 821 822 # encode output, needed by unix_md5_crypt() only non utf8 signs 823 $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); 824 $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Param{UserLogin} ); 825 826 $CryptedPw = apache_md5_crypt( $Pw, $Param{UserLogin} ); 827 } 828 829 # crypt with sha1 830 elsif ( $CryptType eq 'sha1' ) { 831 832 my $SHAObject = Digest::SHA->new('sha1'); 833 $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); 834 $SHAObject->add($Pw); 835 $CryptedPw = $SHAObject->hexdigest(); 836 } 837 838 # crypt with sha512 839 elsif ( $CryptType eq 'sha512' ) { 840 841 my $SHAObject = Digest::SHA->new('sha512'); 842 $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); 843 $SHAObject->add($Pw); 844 $CryptedPw = $SHAObject->hexdigest(); 845 } 846 847 # bcrypt 848 elsif ( $CryptType eq 'bcrypt' ) { 849 850 if ( !$Kernel::OM->Get('Kernel::System::Main')->Require('Crypt::Eksblowfish::Bcrypt') ) { 851 $Kernel::OM->Get('Kernel::System::Log')->Log( 852 Priority => 'error', 853 Message => 854 "User: '$User{UserLogin}' tried to store password with bcrypt but 'Crypt::Eksblowfish::Bcrypt' is not installed!", 855 ); 856 return; 857 } 858 859 my $Cost = $ConfigObject->Get('AuthModule::DB::bcryptCost') // 12; 860 861 # Don't allow values smaller than 9 for security. 862 $Cost = 9 if $Cost < 9; 863 864 # Current Crypt::Eksblowfish::Bcrypt limit is 31. 865 $Cost = 31 if $Cost > 31; 866 867 my $Salt = $Kernel::OM->Get('Kernel::System::Main')->GenerateRandomString( Length => 16 ); 868 869 # remove UTF8 flag, required by Crypt::Eksblowfish::Bcrypt 870 $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); 871 872 # calculate password hash 873 my $Octets = Crypt::Eksblowfish::Bcrypt::bcrypt_hash( 874 { 875 key_nul => 1, 876 cost => $Cost, 877 salt => $Salt, 878 }, 879 $Pw 880 ); 881 882 # We will store cost and salt in the password string so that it can be decoded 883 # in future even if we use a higher cost by default. 884 $CryptedPw = "BCRYPT:$Cost:$Salt:" . Crypt::Eksblowfish::Bcrypt::en_base64($Octets); 885 } 886 887 # crypt with sha256 as fallback 888 else { 889 890 my $SHAObject = Digest::SHA->new('sha256'); 891 892 # encode output, needed by sha256_hex() only non utf8 signs 893 $Kernel::OM->Get('Kernel::System::Encode')->EncodeOutput( \$Pw ); 894 895 $SHAObject->add($Pw); 896 $CryptedPw = $SHAObject->hexdigest(); 897 } 898 899 # update db 900 my $UserLogin = lc $Param{UserLogin}; 901 return if !$Kernel::OM->Get('Kernel::System::DB')->Do( 902 SQL => "UPDATE $Self->{UserTable} SET $Self->{UserTableUserPW} = ? " 903 . " WHERE $Self->{Lower}($Self->{UserTableUser}) = ?", 904 Bind => [ \$CryptedPw, \$UserLogin ], 905 ); 906 907 # log notice 908 $Kernel::OM->Get('Kernel::System::Log')->Log( 909 Priority => 'notice', 910 Message => "User: '$Param{UserLogin}' changed password successfully!", 911 ); 912 913 return 1; 914} 915 916=head2 UserLookup() 917 918user login or id lookup 919 920 my $UserLogin = $UserObject->UserLookup( 921 UserID => 1, 922 Silent => 1, # optional, don't generate log entry if user was not found 923 ); 924 925 my $UserID = $UserObject->UserLookup( 926 UserLogin => 'some_user_login', 927 Silent => 1, # optional, don't generate log entry if user was not found 928 ); 929 930=cut 931 932sub UserLookup { 933 my ( $Self, %Param ) = @_; 934 935 # check needed stuff 936 if ( !$Param{UserLogin} && !$Param{UserID} ) { 937 $Kernel::OM->Get('Kernel::System::Log')->Log( 938 Priority => 'error', 939 Message => 'Need UserLogin or UserID!' 940 ); 941 return; 942 } 943 944 # get database object 945 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 946 947 if ( $Param{UserLogin} ) { 948 949 # check cache 950 my $CacheKey = 'UserLookup::ID::' . $Param{UserLogin}; 951 my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get( 952 Type => $Self->{CacheType}, 953 Key => $CacheKey, 954 ); 955 return $Cache if $Cache; 956 957 # build sql query 958 my $UserLogin = lc $Param{UserLogin}; 959 960 return if !$DBObject->Prepare( 961 SQL => "SELECT $Self->{UserTableUserID} FROM $Self->{UserTable} " 962 . " WHERE $Self->{Lower}($Self->{UserTableUser}) = ?", 963 Bind => [ \$UserLogin ], 964 Limit => 1, 965 ); 966 967 # fetch the result 968 my $ID; 969 while ( my @Row = $DBObject->FetchrowArray() ) { 970 $ID = $Row[0]; 971 } 972 973 if ( !$ID ) { 974 if ( !$Param{Silent} ) { 975 $Kernel::OM->Get('Kernel::System::Log')->Log( 976 Priority => 'error', 977 Message => "No UserID found for '$Param{UserLogin}'!", 978 ); 979 } 980 return; 981 } 982 983 # set cache 984 $Kernel::OM->Get('Kernel::System::Cache')->Set( 985 Type => $Self->{CacheType}, 986 TTL => $Self->{CacheTTL}, 987 Key => $CacheKey, 988 Value => $ID, 989 ); 990 991 return $ID; 992 } 993 994 else { 995 996 # check cache 997 my $CacheKey = 'UserLookup::Login::' . $Param{UserID}; 998 my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get( 999 Type => $Self->{CacheType}, 1000 Key => $CacheKey, 1001 ); 1002 return $Cache if $Cache; 1003 1004 # build sql query 1005 return if !$DBObject->Prepare( 1006 SQL => "SELECT $Self->{UserTableUser} FROM $Self->{UserTable} " 1007 . " WHERE $Self->{UserTableUserID} = ?", 1008 Bind => [ \$Param{UserID} ], 1009 Limit => 1, 1010 ); 1011 1012 # fetch the result 1013 my $Login; 1014 while ( my @Row = $DBObject->FetchrowArray() ) { 1015 $Login = $Row[0]; 1016 } 1017 1018 if ( !$Login ) { 1019 if ( !$Param{Silent} ) { 1020 $Kernel::OM->Get('Kernel::System::Log')->Log( 1021 Priority => 'error', 1022 Message => "No UserLogin found for '$Param{UserID}'!", 1023 ); 1024 } 1025 return; 1026 } 1027 1028 # set cache 1029 $Kernel::OM->Get('Kernel::System::Cache')->Set( 1030 Type => $Self->{CacheType}, 1031 TTL => $Self->{CacheTTL}, 1032 Key => $CacheKey, 1033 Value => $Login, 1034 ); 1035 1036 return $Login; 1037 } 1038} 1039 1040=head2 UserName() 1041 1042get user name 1043 1044 my $Name = $UserObject->UserName( 1045 User => 'some-login', 1046 ); 1047 1048 or 1049 1050 my $Name = $UserObject->UserName( 1051 UserID => 123, 1052 ); 1053 1054=cut 1055 1056sub UserName { 1057 my ( $Self, %Param ) = @_; 1058 1059 my %User = $Self->GetUserData(%Param); 1060 1061 return if !%User; 1062 return $User{UserFullname}; 1063} 1064 1065=head2 UserList() 1066 1067return a hash with all users 1068 1069 my %List = $UserObject->UserList( 1070 Type => 'Short', # Short|Long, default Short 1071 Valid => 1, # default 1 1072 NoOutOfOffice => 1, # (optional) default 0 1073 ); 1074 1075=cut 1076 1077sub UserList { 1078 my ( $Self, %Param ) = @_; 1079 1080 my $Type = $Param{Type} || 'Short'; 1081 1082 # set valid option 1083 my $Valid = $Param{Valid} // 1; 1084 1085 # get config object 1086 my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); 1087 1088 # get configuration for the full name order 1089 my $FirstnameLastNameOrder = $ConfigObject->Get('FirstnameLastnameOrder') || 0; 1090 my $NoOutOfOffice = $Param{NoOutOfOffice} || 0; 1091 1092 # check cache 1093 my $CacheKey = join '::', 'UserList', $Type, $Valid, $FirstnameLastNameOrder, $NoOutOfOffice; 1094 my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get( 1095 Type => $Self->{CacheType}, 1096 Key => $CacheKey, 1097 ); 1098 return %{$Cache} if $Cache; 1099 1100 my $SelectStr; 1101 if ( $Type eq 'Short' ) { 1102 $SelectStr = "$ConfigObject->{DatabaseUserTableUserID}, " 1103 . " $ConfigObject->{DatabaseUserTableUser}"; 1104 } 1105 else { 1106 $SelectStr = "$ConfigObject->{DatabaseUserTableUserID}, " 1107 . " last_name, first_name, " 1108 . " $ConfigObject->{DatabaseUserTableUser}"; 1109 } 1110 1111 my $SQL = "SELECT $SelectStr FROM $ConfigObject->{DatabaseUserTable}"; 1112 1113 # sql query 1114 if ($Valid) { 1115 $SQL 1116 .= " WHERE valid_id IN ( ${\(join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet())} )"; 1117 } 1118 1119 # get database object 1120 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 1121 1122 return if !$DBObject->Prepare( SQL => $SQL ); 1123 1124 # fetch the result 1125 my %UsersRaw; 1126 my %Users; 1127 while ( my @Row = $DBObject->FetchrowArray() ) { 1128 $UsersRaw{ $Row[0] } = \@Row; 1129 } 1130 1131 if ( $Type eq 'Short' ) { 1132 for my $CurrentUserID ( sort keys %UsersRaw ) { 1133 $Users{$CurrentUserID} = $UsersRaw{$CurrentUserID}->[1]; 1134 } 1135 } 1136 else { 1137 for my $CurrentUserID ( sort keys %UsersRaw ) { 1138 my @Data = @{ $UsersRaw{$CurrentUserID} }; 1139 my $UserFullname = $Self->_UserFullname( 1140 UserFirstname => $Data[2], 1141 UserLastname => $Data[1], 1142 UserLogin => $Data[3], 1143 NameOrder => $FirstnameLastNameOrder, 1144 ); 1145 1146 $Users{$CurrentUserID} = $UserFullname; 1147 } 1148 } 1149 1150 # check vacation option 1151 if ( !$NoOutOfOffice ) { 1152 1153 USERID: 1154 for my $UserID ( sort keys %Users ) { 1155 next USERID if !$UserID; 1156 1157 my %User = $Self->GetUserData( 1158 UserID => $UserID, 1159 ); 1160 if ( $User{OutOfOfficeMessage} ) { 1161 $Users{$UserID} .= ' ' . $User{OutOfOfficeMessage}; 1162 } 1163 } 1164 } 1165 1166 # set cache 1167 $Kernel::OM->Get('Kernel::System::Cache')->Set( 1168 Type => $Self->{CacheType}, 1169 TTL => $Self->{CacheTTL}, 1170 Key => $CacheKey, 1171 Value => \%Users, 1172 ); 1173 1174 return %Users; 1175} 1176 1177=head2 GenerateRandomPassword() 1178 1179generate a random password 1180 1181 my $Password = $UserObject->GenerateRandomPassword(); 1182 1183 or 1184 1185 my $Password = $UserObject->GenerateRandomPassword( 1186 Size => 16, 1187 ); 1188 1189=cut 1190 1191sub GenerateRandomPassword { 1192 my ( $Self, %Param ) = @_; 1193 1194 # generated passwords are eight characters long by default. 1195 my $Size = $Param{Size} || 8; 1196 1197 my $Password = $Kernel::OM->Get('Kernel::System::Main')->GenerateRandomString( 1198 Length => $Size, 1199 ); 1200 1201 return $Password; 1202} 1203 1204=head2 SetPreferences() 1205 1206set user preferences 1207 1208 $UserObject->SetPreferences( 1209 Key => 'UserComment', 1210 Value => 'some comment', 1211 UserID => 123, 1212 ); 1213 1214=cut 1215 1216sub SetPreferences { 1217 my ( $Self, %Param ) = @_; 1218 1219 # check needed stuff 1220 for (qw(Key UserID)) { 1221 if ( !$Param{$_} ) { 1222 $Kernel::OM->Get('Kernel::System::Log')->Log( 1223 Priority => 'error', 1224 Message => "Need $_!" 1225 ); 1226 return; 1227 } 1228 } 1229 1230 # Don't allow overwriting of native user data. 1231 my %Blacklisted = ( 1232 UserID => 1, 1233 UserLogin => 1, 1234 UserPw => 1, 1235 UserFirstname => 1, 1236 UserLastname => 1, 1237 UserFullname => 1, 1238 UserTitle => 1, 1239 ChangeTime => 1, 1240 CreateTime => 1, 1241 ValidID => 1, 1242 ); 1243 1244 return 0 if $Blacklisted{ $Param{Key} }; 1245 1246 # get current setting 1247 my %User = $Self->GetUserData( 1248 UserID => $Param{UserID}, 1249 NoOutOfOffice => 1, 1250 ); 1251 1252 # no updated needed 1253 return 1 1254 if defined $User{ $Param{Key} } 1255 && defined $Param{Value} 1256 && $User{ $Param{Key} } eq $Param{Value}; 1257 1258 $Self->_UserCacheClear( UserID => $Param{UserID} ); 1259 1260 # get user preferences config 1261 my $GeneratorModule = $Kernel::OM->Get('Kernel::Config')->Get('User::PreferencesModule') 1262 || 'Kernel::System::User::Preferences::DB'; 1263 1264 # get generator preferences module 1265 my $PreferencesObject = $Kernel::OM->Get($GeneratorModule); 1266 1267 # set preferences 1268 return $PreferencesObject->SetPreferences(%Param); 1269} 1270 1271sub _UserCacheClear { 1272 my ( $Self, %Param ) = @_; 1273 1274 if ( !$Param{UserID} ) { 1275 $Kernel::OM->Get('Kernel::System::Log')->Log( 1276 Priority => 'error', 1277 Message => "Need UserID!" 1278 ); 1279 return; 1280 } 1281 1282 my $Login = $Self->UserLookup( UserID => $Param{UserID} ); 1283 1284 my @CacheKeys; 1285 1286 # Delete cache for all possible FirstnameLastNameOrder settings as this might be overridden by users. 1287 for my $FirstnameLastNameOrder ( 0 .. 8 ) { 1288 for my $ActiveLevel1 ( 0 .. 1 ) { 1289 for my $ActiveLevel2 ( 0 .. 1 ) { 1290 push @CacheKeys, ( 1291 "GetUserData::User::${Login}::${ActiveLevel1}::${FirstnameLastNameOrder}::${ActiveLevel2}", 1292 "GetUserData::UserID::$Param{UserID}::${ActiveLevel1}::${FirstnameLastNameOrder}::${ActiveLevel2}", 1293 "UserList::Short::${ActiveLevel1}::${FirstnameLastNameOrder}::${ActiveLevel2}", 1294 "UserList::Long::${ActiveLevel1}::${FirstnameLastNameOrder}::${ActiveLevel2}", 1295 ); 1296 } 1297 } 1298 push @CacheKeys, ( 1299 'UserLookup::ID::' . $Login, 1300 'UserLookup::Login::' . $Param{UserID}, 1301 ); 1302 } 1303 1304 my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache'); 1305 1306 for my $CacheKey (@CacheKeys) { 1307 $CacheObject->Delete( 1308 Type => $Self->{CacheType}, 1309 Key => $CacheKey, 1310 ); 1311 } 1312 1313 return 1; 1314} 1315 1316=head2 GetPreferences() 1317 1318get user preferences 1319 1320 my %Preferences = $UserObject->GetPreferences( 1321 UserID => 123, 1322 ); 1323 1324=cut 1325 1326sub GetPreferences { 1327 my ( $Self, %Param ) = @_; 1328 1329 # get user preferences config 1330 my $GeneratorModule = $Kernel::OM->Get('Kernel::Config')->Get('User::PreferencesModule') 1331 || 'Kernel::System::User::Preferences::DB'; 1332 1333 # get generator preferences module 1334 my $PreferencesObject = $Kernel::OM->Get($GeneratorModule); 1335 1336 return $PreferencesObject->GetPreferences(%Param); 1337} 1338 1339=head2 SearchPreferences() 1340 1341search in user preferences 1342 1343 my %UserList = $UserObject->SearchPreferences( 1344 Key => 'UserEmail', 1345 Value => 'email@example.com', # optional, limit to a certain value/pattern 1346 ); 1347 1348=cut 1349 1350sub SearchPreferences { 1351 my ( $Self, %Param ) = @_; 1352 1353 # get user preferences config 1354 my $GeneratorModule = $Kernel::OM->Get('Kernel::Config')->Get('User::PreferencesModule') 1355 || 'Kernel::System::User::Preferences::DB'; 1356 1357 # get generator preferences module 1358 my $PreferencesObject = $Kernel::OM->Get($GeneratorModule); 1359 1360 return $PreferencesObject->SearchPreferences(%Param); 1361} 1362 1363=head2 TokenGenerate() 1364 1365generate a random token 1366 1367 my $Token = $UserObject->TokenGenerate( 1368 UserID => 123, 1369 ); 1370 1371=cut 1372 1373sub TokenGenerate { 1374 my ( $Self, %Param ) = @_; 1375 1376 # check needed stuff 1377 if ( !$Param{UserID} ) { 1378 $Kernel::OM->Get('Kernel::System::Log')->Log( 1379 Priority => 'error', 1380 Message => "Need UserID!" 1381 ); 1382 return; 1383 } 1384 my $Token = $Kernel::OM->Get('Kernel::System::Main')->GenerateRandomString( 1385 Length => 15, 1386 ); 1387 1388 # save token in preferences 1389 $Self->SetPreferences( 1390 Key => 'UserToken', 1391 Value => $Token, 1392 UserID => $Param{UserID}, 1393 ); 1394 1395 return $Token; 1396} 1397 1398=head2 TokenCheck() 1399 1400check password token 1401 1402 my $Valid = $UserObject->TokenCheck( 1403 Token => $Token, 1404 UserID => 123, 1405 ); 1406 1407=cut 1408 1409sub TokenCheck { 1410 my ( $Self, %Param ) = @_; 1411 1412 # check needed stuff 1413 if ( !$Param{Token} || !$Param{UserID} ) { 1414 $Kernel::OM->Get('Kernel::System::Log')->Log( 1415 Priority => 'error', 1416 Message => 'Need Token and UserID!' 1417 ); 1418 return; 1419 } 1420 1421 # get preferences token 1422 my %Preferences = $Self->GetPreferences( 1423 UserID => $Param{UserID}, 1424 ); 1425 1426 # check requested vs. stored token 1427 if ( $Preferences{UserToken} && $Preferences{UserToken} eq $Param{Token} ) { 1428 1429 # reset password token 1430 $Self->SetPreferences( 1431 Key => 'UserToken', 1432 Value => '', 1433 UserID => $Param{UserID}, 1434 ); 1435 1436 # return true if token is valid 1437 return 1; 1438 } 1439 1440 # return false if token is invalid 1441 return; 1442} 1443 1444=begin Internal: 1445 1446=head2 _UserFullname() 1447 1448Builds the user fullname based on firstname, lastname and login. The order 1449can be configured. 1450 1451 my $Fullname = $Object->_UserFullname( 1452 UserFirstname => 'Test', 1453 UserLastname => 'Person', 1454 UserLogin => 'tp', 1455 NameOrder => 0, # optional 0, 1, 2, 3, 4, 5 1456 ); 1457 1458=cut 1459 1460sub _UserFullname { 1461 my ( $Self, %Param ) = @_; 1462 1463 for my $Needed (qw(UserFirstname UserLastname UserLogin)) { 1464 if ( !$Param{$Needed} ) { 1465 $Kernel::OM->Get('Kernel::System::Log')->Log( 1466 Priority => 'error', 1467 Message => "Need $Needed!", 1468 ); 1469 1470 return; 1471 } 1472 } 1473 1474 my $FirstnameLastNameOrder = $Param{NameOrder} || 0; 1475 1476 my $UserFullname; 1477 if ( $FirstnameLastNameOrder eq '0' ) { 1478 $UserFullname = $Param{UserFirstname} . ' ' 1479 . $Param{UserLastname}; 1480 } 1481 elsif ( $FirstnameLastNameOrder eq '1' ) { 1482 $UserFullname = $Param{UserLastname} . ', ' 1483 . $Param{UserFirstname}; 1484 } 1485 elsif ( $FirstnameLastNameOrder eq '2' ) { 1486 $UserFullname = $Param{UserFirstname} . ' ' 1487 . $Param{UserLastname} . ' (' 1488 . $Param{UserLogin} . ')'; 1489 } 1490 elsif ( $FirstnameLastNameOrder eq '3' ) { 1491 $UserFullname = $Param{UserLastname} . ', ' 1492 . $Param{UserFirstname} . ' (' 1493 . $Param{UserLogin} . ')'; 1494 } 1495 elsif ( $FirstnameLastNameOrder eq '4' ) { 1496 $UserFullname = '(' . $Param{UserLogin} 1497 . ') ' . $Param{UserFirstname} 1498 . ' ' . $Param{UserLastname}; 1499 } 1500 elsif ( $FirstnameLastNameOrder eq '5' ) { 1501 $UserFullname = '(' . $Param{UserLogin} 1502 . ') ' . $Param{UserLastname} 1503 . ', ' . $Param{UserFirstname}; 1504 } 1505 elsif ( $FirstnameLastNameOrder eq '6' ) { 1506 $UserFullname = $Param{UserLastname} . ' ' 1507 . $Param{UserFirstname}; 1508 } 1509 elsif ( $FirstnameLastNameOrder eq '7' ) { 1510 $UserFullname = $Param{UserLastname} . ' ' 1511 . $Param{UserFirstname} . ' (' 1512 . $Param{UserLogin} . ')'; 1513 } 1514 elsif ( $FirstnameLastNameOrder eq '8' ) { 1515 $UserFullname = '(' . $Param{UserLogin} 1516 . ') ' . $Param{UserLastname} 1517 . ' ' . $Param{UserFirstname}; 1518 } 1519 elsif ( $FirstnameLastNameOrder eq '9' ) { 1520 $UserFullname = $Param{UserLastname} . $Param{UserFirstname}; 1521 } 1522 return $UserFullname; 1523} 1524 1525=end Internal: 1526 1527=cut 1528 1529=head2 UserLoginExistsCheck() 1530 1531return 1 if another user with this login (username) already exists 1532 1533 $Exist = $UserObject->UserLoginExistsCheck( 1534 UserLogin => 'Some::UserLogin', 1535 UserID => 1, # optional 1536 ); 1537 1538=cut 1539 1540sub UserLoginExistsCheck { 1541 my ( $Self, %Param ) = @_; 1542 1543 # get database object 1544 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 1545 1546 return if !$DBObject->Prepare( 1547 SQL => 1548 "SELECT $Self->{UserTableUserID} FROM $Self->{UserTable} WHERE $Self->{UserTableUser} = ?", 1549 Bind => [ \$Param{UserLogin} ], 1550 ); 1551 1552 # fetch the result 1553 my $Flag; 1554 while ( my @Row = $DBObject->FetchrowArray() ) { 1555 if ( !$Param{UserID} || $Param{UserID} ne $Row[0] ) { 1556 $Flag = 1; 1557 } 1558 } 1559 if ($Flag) { 1560 return 1; 1561 } 1562 return 0; 1563} 1564 15651; 1566 1567=head1 TERMS AND CONDITIONS 1568 1569This software is part of the OTRS project (L<https://otrs.org/>). 1570 1571This software comes with ABSOLUTELY NO WARRANTY. For details, see 1572the enclosed file COPYING for license information (GPL). If you 1573did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>. 1574 1575=cut 1576