Bug 21206: Replace C4::Items::GetItem
[koha.git] / opac / opac-password-recovery.pl
index 0013870..6429f7b 100755 (executable)
@@ -1,16 +1,16 @@
 #!/usr/bin/perl
 
-use strict;
 use Modern::Perl;
 use CGI;
 
 use C4::Auth;
 use C4::Koha;
-use C4::Members qw(changepassword Search);
 use C4::Output;
 use C4::Context;
-use C4::Passwordrecovery qw(SendPasswordRecoveryEmail ValidateBorrowernumber GetValidLinkInfo CompletePasswordRecovery);
-use Koha::AuthUtils qw(hash_password);
+use Koha::Patron::Password::Recovery
+  qw(SendPasswordRecoveryEmail ValidateBorrowernumber GetValidLinkInfo CompletePasswordRecovery DeleteExpiredPasswordRecovery);
+use Koha::Patrons;
+use Koha::Patrons;
 my $query = new CGI;
 use HTML::Entities;
 
@@ -27,10 +27,9 @@ my ( $template, $dummy, $cookie ) = get_template_and_user(
 my $email          = $query->param('email') // q{};
 my $password       = $query->param('password');
 my $repeatPassword = $query->param('repeatPassword');
-my $minPassLength  = C4::Context->preference('minPasswordLength');
 my $id             = $query->param('id');
 my $uniqueKey      = $query->param('uniqueKey');
-my $username       = $query->param('username');
+my $username       = $query->param('username') // q{};
 my $borrower_number;
 
 #errors
@@ -39,57 +38,74 @@ my $hasError;
 #email form error
 my $errNoBorrowerFound;
 my $errNoBorrowerEmail;
+my $errMultipleAccountsForEmail;
 my $errAlreadyStartRecovery;
 my $errTooManyEmailFound;
 my $errBadEmail;
 
 #new password form error
 my $errLinkNotValid;
-my $errPassNotMatch;
-my $errPassTooShort;
 
 if ( $query->param('sendEmail') || $query->param('resendEmail') ) {
-    my $protocol = $query->https() ? "https://" : "http://";
+
     #try with the main email
-    $email ||= ''; # avoid undef
     my $borrower;
     my $search_results;
 
-    # Find the borrower by his userid or email
-    if( $username ){
-        $search_results = Search({ userid => $username });
+    # Find the borrower by userid, card number, or email
+    if ($username) {
+        $search_results = Koha::Patrons->search( { -or => { userid => $username, cardnumber => $username } } );
     }
-    elsif ( $email ){
-        $search_results = Search({ '' => $email }, undef, undef, undef, ['emailpro', 'email', 'B_email']);
+    elsif ($email) {
+        $search_results = Koha::Patrons->search( { -or => { email => $email, emailpro => $email, B_email  => $email } } );
     }
 
-    if(scalar @$search_results > 1){ # Many matching borrowers
-       $hasError             = 1;
-       $errTooManyEmailFound = 1;
+    if ( !defined $search_results || $search_results->count < 1) {
+        $hasError           = 1;
+        $errNoBorrowerFound = 1;
+    }
+    elsif ( $username && $search_results->count > 1) { # Multiple accounts for username
+        $hasError           = 1;
+        $errNoBorrowerFound = 1;
     }
-    elsif( $borrower = shift @$search_results ){ # One matching borrower
-        $username ||= $borrower->{'userid'};
-        my @emails = ( $borrower->{'email'}, $borrower->{'emailpro'}, $borrower->{'B_email'} );
+    elsif ( $email && $search_results->count > 1) { # Muliple accounts for E-Mail
+        $hasError           = 1;
+        $errMultipleAccountsForEmail = 1;
+    }
+    elsif ( $borrower = $search_results->next() ) {    # One matching borrower
+        my @emails = grep { $_ } ( $borrower->email, $borrower->emailpro, $borrower->B_email );
+
+        my $firstNonEmptyEmail;
+        $firstNonEmptyEmail = $emails[0] if @emails;
+
         # Is the given email one of the borrower's ?
-        if( $email && !($email ~~ @emails) ){
-             $hasError    = 1;
-             $errBadEmail = 1;
+        if ( $email && !( grep /^$email$/i, @emails ) ) {
+            $hasError    = 1;
+            $errNoBorrowerFound = 1;
         }
-        # If we dont have an email yet. Get one of the borrower's email or raise an error.
-        # FIXME: That ugly shift-grep contraption.
-        # $email = shift [ grep { length() } @emails ]
-        # It's supposed to get a non-empty string from the @emails array. There's surely a simpler way
-        elsif( !$email && !($email = shift [ grep { length() } @emails ]) ){
-             $hasError           = 1;
-             $errNoBorrowerEmail = 1;
+
+        # If there is no given email, and there is no email on record
+        elsif ( !$email && !$firstNonEmptyEmail ) {
+            $hasError           = 1;
+            $errNoBorrowerEmail = 1;
         }
-        # Check if a password reset already issued for this borrower AND we are not asking for a new email
-        elsif( ValidateBorrowernumber( $borrower->{'borrowernumber'} ) && !$query->param('resendEmail') ){
-            $hasError                = 1;
-            $errAlreadyStartRecovery = 1;
+
+# Check if a password reset already issued for this borrower AND we are not asking for a new email
+        elsif ( not $query->param('resendEmail') ) {
+            if ( ValidateBorrowernumber( $borrower->borrowernumber ) ) {
+                $hasError                = 1;
+                $errAlreadyStartRecovery = 1;
+            }
+            else {
+                DeleteExpiredPasswordRecovery( $borrower->borrowernumber );
+            }
+        }
+        # Set the $email, if we don't have one.
+        if ( !$hasError && !$email ) {
+            $email = $firstNonEmptyEmail;
         }
     }
-    else{ # 0 matching borrower
+    else {    # 0 matching borrower
         $hasError           = 1;
         $errNoBorrowerFound = 1;
     }
@@ -101,19 +117,21 @@ if ( $query->param('sendEmail') || $query->param('resendEmail') ) {
             errAlreadyStartRecovery => $errAlreadyStartRecovery,
             errBadEmail             => $errBadEmail,
             errNoBorrowerEmail      => $errNoBorrowerEmail,
+            errMultipleAccountsForEmail => $errMultipleAccountsForEmail,
             password_recovery       => 1,
             email                   => HTML::Entities::encode($email),
             username                => $username
         );
     }
-    elsif ( SendPasswordRecoveryEmail( $borrower, $email, $protocol, $query->param('resendEmail') ) ) {#generate uuid and send recovery email
+    elsif ( SendPasswordRecoveryEmail( $borrower, $email, scalar $query->param('resendEmail') ) ) {    # generate uuid and send recovery email
         $template->param(
             mail_sent => 1,
             email     => $email
         );
     }
-    else {# if it doesnt work....
+    else {    # if it doesn't work....
         $template->param(
+            hasError          => 1,
             password_recovery => 1,
             sendmailError     => 1
         );
@@ -121,42 +139,46 @@ if ( $query->param('sendEmail') || $query->param('resendEmail') ) {
 }
 elsif ( $query->param('passwordReset') ) {
     ( $borrower_number, $username ) = GetValidLinkInfo($uniqueKey);
-    #validate password length & match
-    if (   ($borrower_number)
-        && ( $password eq $repeatPassword )
-        && ( length($password) >= $minPassLength ) )
-    {  #apply changes
-        changepassword( $username, $borrower_number, hash_password($password) );
-        CompletePasswordRecovery($uniqueKey);
-        $template->param(
-            password_reset_done => 1,
-            username            => $username
-        );
-    }
-    else { #errors
-        if ( !$borrower_number ) { #parameters not valid
-            $errLinkNotValid = 1;
-        }
-        elsif ( $password ne $repeatPassword ) { #passwords does not match
-            $errPassNotMatch = 1;
-        }
-        elsif ( length($password) < $minPassLength ) { #password too short
-            $errPassTooShort = 1;
+
+    my $error;
+    if ( not $borrower_number ) {
+        $error = 'errLinkNotValid';
+    } elsif ( $password ne $repeatPassword ) {
+        $error = 'errPassNotMatch';
+    } else {
+        try {
+            Koha::Patrons->find($borrower_number)->set_password({ password => $password });
+
+            CompletePasswordRecovery($uniqueKey);
+            $template->param(
+                password_reset_done => 1,
+                username            => $username
+            );
         }
+        catch {
+            if ( $_->isa('Koha::Exceptions::Password::TooShort') ) {
+                $error = 'password_too_short';
+            }
+            elsif ( $_->isa('Koha::Exceptions::Password::WhitespaceCharacters') ) {
+                $error = 'password_has_whitespaces';
+            }
+            elsif ( $_->isa('Koha::Exceptions::Password::TooWeak') ) {
+                $error = 'password_too_weak';
+            }
+        };
+    }
+    if ( $error ) {
         $template->param(
-            new_password    => 1,
-            minPassLength   => $minPassLength,
-            email           => $email,
-            uniqueKey       => $uniqueKey,
-            errLinkNotValid => $errLinkNotValid,
-            errPassNotMatch => $errPassNotMatch,
-            errPassTooShort => $errPassTooShort,
-            hasError        => 1
+            new_password => 1,
+            email        => $email,
+            uniqueKey    => $uniqueKey,
+            hasError     => 1,
+            $error       => 1,
         );
     }
 }
-elsif ($uniqueKey) {  #reset password form
-    #check if the link is valid
+elsif ($uniqueKey) {    #reset password form
+                        #check if the link is valid
     ( $borrower_number, $username ) = GetValidLinkInfo($uniqueKey);
 
     if ( !$borrower_number ) {
@@ -165,14 +187,14 @@ elsif ($uniqueKey) {  #reset password form
 
     $template->param(
         new_password    => 1,
-        minPassLength   => $minPassLength,
         email           => $email,
         uniqueKey       => $uniqueKey,
         username        => $username,
-        errLinkNotValid => $errLinkNotValid
+        errLinkNotValid => $errLinkNotValid,
+        hasError        => ( $errLinkNotValid ? 1 : 0 ),
     );
 }
-else { #password recovery form (to send email)
+else {    #password recovery form (to send email)
     $template->param( password_recovery => 1 );
 }