Bug 18616 - The "Add forgot password link to OPAC" should allow patrons to use their...
[koha.git] / opac / opac-password-recovery.pl
1 #!/usr/bin/perl
2
3 use Modern::Perl;
4 use CGI;
5
6 use C4::Auth;
7 use C4::Koha;
8 use C4::Output;
9 use C4::Context;
10 use Koha::Patron::Password::Recovery
11   qw(SendPasswordRecoveryEmail ValidateBorrowernumber GetValidLinkInfo CompletePasswordRecovery DeleteExpiredPasswordRecovery);
12 use Koha::Patrons;
13 use Koha::AuthUtils qw(hash_password);
14 use Koha::Patrons;
15 my $query = new CGI;
16 use HTML::Entities;
17
18 my ( $template, $dummy, $cookie ) = get_template_and_user(
19     {
20         template_name   => "opac-password-recovery.tt",
21         query           => $query,
22         type            => "opac",
23         authnotrequired => 1,
24         debug           => 1,
25     }
26 );
27
28 my $email          = $query->param('email') // q{};
29 my $password       = $query->param('password');
30 my $repeatPassword = $query->param('repeatPassword');
31 my $minPassLength  = C4::Context->preference('minPasswordLength');
32 my $id             = $query->param('id');
33 my $uniqueKey      = $query->param('uniqueKey');
34 my $username       = $query->param('username');
35 my $borrower_number;
36
37 #errors
38 my $hasError;
39
40 #email form error
41 my $errNoBorrowerFound;
42 my $errNoBorrowerEmail;
43 my $errMultipleAccountsForEmail;
44 my $errAlreadyStartRecovery;
45 my $errTooManyEmailFound;
46 my $errBadEmail;
47
48 #new password form error
49 my $errLinkNotValid;
50 my $errPassNotMatch;
51 my $errPassTooShort;
52
53 if ( $query->param('sendEmail') || $query->param('resendEmail') ) {
54
55     #try with the main email
56     $email ||= '';    # avoid undef
57     my $borrower;
58     my $search_results;
59
60     # Find the borrower by userid, card number, or email
61     if ($username) {
62         $search_results = Koha::Patrons->search( { -or => { userid => $username, cardnumber => $username } } );
63     }
64     elsif ($email) {
65         $search_results = Koha::Patrons->search( { -or => { email => $email, emailpro => $email, B_email  => $email } } );
66     }
67
68     if ( not $search_results || $search_results->count < 1) {
69         $hasError           = 1;
70         $errNoBorrowerFound = 1;
71     }
72     elsif ( $username && $search_results->count > 1) { # Multiple accounts for username
73         $hasError           = 1;
74         $errNoBorrowerFound = 1;
75     }
76     elsif ( $email && $search_results->count > 1) { # Muliple accounts for E-Mail
77         $hasError           = 1;
78         $errMultipleAccountsForEmail = 1;
79     }
80     elsif ( $borrower = $search_results->next() ) {    # One matching borrower
81         $username ||= $borrower->userid;
82         my @emails = ( $borrower->email, $borrower->emailpro, $borrower->B_email );
83
84         my $firstNonEmptyEmail = '';
85         foreach my $address ( @emails ) {
86             $firstNonEmptyEmail = $address if length $address;
87             last if $firstNonEmptyEmail;
88         }
89
90         # Is the given email one of the borrower's ?
91         if ( $email && !( grep { $_ eq $email } @emails ) ) {
92             $hasError    = 1;
93             $errNoBorrowerFound = 1;
94         }
95
96 # If we dont have an email yet. Get one of the borrower's email or raise an error.
97         elsif ( !$email && !( $email = $firstNonEmptyEmail ) ) {
98             $hasError           = 1;
99             $errNoBorrowerEmail = 1;
100         }
101
102 # Check if a password reset already issued for this borrower AND we are not asking for a new email
103         elsif ( not $query->param('resendEmail') ) {
104             if ( ValidateBorrowernumber( $borrower->borrowernumber ) ) {
105                 $hasError                = 1;
106                 $errAlreadyStartRecovery = 1;
107             }
108             else {
109                 DeleteExpiredPasswordRecovery( $borrower->borrowernumber );
110             }
111         }
112     }
113     else {    # 0 matching borrower
114         $hasError           = 1;
115         $errNoBorrowerFound = 1;
116     }
117     if ($hasError) {
118         $template->param(
119             hasError                => 1,
120             errNoBorrowerFound      => $errNoBorrowerFound,
121             errTooManyEmailFound    => $errTooManyEmailFound,
122             errAlreadyStartRecovery => $errAlreadyStartRecovery,
123             errBadEmail             => $errBadEmail,
124             errNoBorrowerEmail      => $errNoBorrowerEmail,
125             errMultipleAccountsForEmail => $errMultipleAccountsForEmail,
126             password_recovery       => 1,
127             email                   => HTML::Entities::encode($email),
128             username                => $username
129         );
130     }
131     elsif ( SendPasswordRecoveryEmail( $borrower, $email, $query->param('resendEmail') ) ) {    # generate uuid and send recovery email
132         $template->param(
133             mail_sent => 1,
134             email     => $email
135         );
136     }
137     else {    # if it doesn't work....
138         $template->param(
139             password_recovery => 1,
140             sendmailError     => 1
141         );
142     }
143 }
144 elsif ( $query->param('passwordReset') ) {
145     ( $borrower_number, $username ) = GetValidLinkInfo($uniqueKey);
146
147     #validate password length & match
148     if (   ($borrower_number)
149         && ( $password eq $repeatPassword )
150         && ( length($password) >= $minPassLength ) )
151     {    #apply changes
152         Koha::Patrons->find($borrower_number)->update_password( $username, hash_password($password) );
153         CompletePasswordRecovery($uniqueKey);
154         $template->param(
155             password_reset_done => 1,
156             username            => $username
157         );
158     }
159     else {    #errors
160         if ( !$borrower_number ) {    #parameters not valid
161             $errLinkNotValid = 1;
162         }
163         elsif ( $password ne $repeatPassword ) {    #passwords does not match
164             $errPassNotMatch = 1;
165         }
166         elsif ( length($password) < $minPassLength ) {    #password too short
167             $errPassTooShort = 1;
168         }
169         $template->param(
170             new_password    => 1,
171             minPassLength   => $minPassLength,
172             email           => $email,
173             uniqueKey       => $uniqueKey,
174             errLinkNotValid => $errLinkNotValid,
175             errPassNotMatch => $errPassNotMatch,
176             errPassTooShort => $errPassTooShort,
177             hasError        => 1
178         );
179     }
180 }
181 elsif ($uniqueKey) {    #reset password form
182                         #check if the link is valid
183     ( $borrower_number, $username ) = GetValidLinkInfo($uniqueKey);
184
185     if ( !$borrower_number ) {
186         $errLinkNotValid = 1;
187     }
188
189     $template->param(
190         new_password    => 1,
191         minPassLength   => $minPassLength,
192         email           => $email,
193         uniqueKey       => $uniqueKey,
194         username        => $username,
195         errLinkNotValid => $errLinkNotValid,
196         hasError        => ( $errLinkNotValid ? 1 : 0 ),
197     );
198 }
199 else {    #password recovery form (to send email)
200     $template->param( password_recovery => 1 );
201 }
202
203 output_html_with_http_headers $query, $cookie, $template->output;