b6c5592e7ef6a8291d7cc502cee9f711ab8ce547
[srvgit] / 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 my $query = CGI->new;
14 use HTML::Entities;
15 use Try::Tiny;
16 use List::Util qw/any/;
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     }
25 );
26
27 my $email          = $query->param('email') // q{};
28 my $password       = $query->param('newPassword');
29 my $repeatPassword = $query->param('repeatPassword');
30 my $id             = $query->param('id');
31 my $uniqueKey      = $query->param('uniqueKey');
32 my $username       = $query->param('username') // q{};
33 my $borrower_number;
34
35 #errors
36 my $hasError;
37
38 #email form error
39 my $errNoBorrowerFound;
40 my $errNoBorrowerEmail;
41 my $errMultipleAccountsForEmail;
42 my $errAlreadyStartRecovery;
43 my $errResetForbidden;
44
45 #new password form error
46 my $errLinkNotValid;
47
48 if ( $query->param('sendEmail') || $query->param('resendEmail') ) {
49
50     #try with the main email
51     my $borrower;
52     my $search_results;
53     # Find the borrower by userid, card number, or email
54     if ($username) {
55         $search_results = Koha::Patrons->search( { -or => { userid => $username, cardnumber => $username }, login_attempts => { '!=', Koha::Patron::ADMINISTRATIVE_LOCKOUT } } );
56     }
57     elsif ($email) {
58         $search_results = Koha::Patrons->search( { -or => { email => $email, emailpro => $email, B_email  => $email }, login_attempts => { '!=', Koha::Patron::ADMINISTRATIVE_LOCKOUT } } );
59     }
60
61     if ( !defined $search_results || $search_results->count < 1) {
62         $hasError           = 1;
63         $errNoBorrowerFound = 1;
64     }
65     elsif ( $username && $search_results->count > 1) { # Multiple accounts for username
66         $hasError           = 1;
67         $errNoBorrowerFound = 1;
68     }
69     elsif ( $email && $search_results->count > 1) { # Muliple accounts for E-Mail
70         $hasError           = 1;
71         $errMultipleAccountsForEmail = 1;
72     }
73     elsif ( $borrower = $search_results->next() ) {    # One matching borrower
74
75         if ( $borrower->category->effective_reset_password ) {
76
77             my @emails = grep { $_ } ( $borrower->email, $borrower->emailpro, $borrower->B_email );
78
79             my $firstNonEmptyEmail;
80             $firstNonEmptyEmail = $emails[0] if @emails;
81
82             # Is the given email one of the borrower's ?
83             if ( $email && !( any { lc($_) eq lc($email) } @emails ) ) {
84                 $hasError    = 1;
85                 $errNoBorrowerFound = 1;
86             }
87
88             # If there is no given email, and there is no email on record
89             elsif ( !$email && !$firstNonEmptyEmail ) {
90                 $hasError           = 1;
91                 $errNoBorrowerEmail = 1;
92             }
93
94             # Check if a password reset already issued for this
95             # borrower AND we are not asking for a new email
96             elsif ( not $query->param('resendEmail') ) {
97                 if ( ValidateBorrowernumber( $borrower->borrowernumber ) ) {
98                     $hasError                = 1;
99                     $errAlreadyStartRecovery = 1;
100                 }
101                 else {
102                     DeleteExpiredPasswordRecovery( $borrower->borrowernumber );
103                 }
104             }
105             # Set the $email, if we don't have one.
106             if ( !$hasError && !$email ) {
107                 $email = $firstNonEmptyEmail;
108             }
109         }
110         else {
111             $hasError          = 1;
112             $errResetForbidden = 1;
113         }
114     }
115     else {    # 0 matching borrower
116         $hasError           = 1;
117         $errNoBorrowerFound = 1;
118     }
119     if ($hasError) {
120         $template->param(
121             hasError                => 1,
122             errNoBorrowerFound      => $errNoBorrowerFound,
123             errAlreadyStartRecovery => $errAlreadyStartRecovery,
124             errNoBorrowerEmail      => $errNoBorrowerEmail,
125             errMultipleAccountsForEmail => $errMultipleAccountsForEmail,
126             errResetForbidden       => $errResetForbidden,
127             password_recovery       => 1,
128             email                   => HTML::Entities::encode($email),
129             username                => $username
130         );
131     }
132     elsif ( SendPasswordRecoveryEmail( $borrower, $email, scalar $query->param('resendEmail') ) ) {    # generate uuid and send recovery email
133         $template->param(
134             mail_sent => 1,
135             email     => $email
136         );
137     }
138     else {    # if it doesn't work....
139         $template->param(
140             hasError          => 1,
141             password_recovery => 1,
142             sendmailError     => 1
143         );
144     }
145 }
146 elsif ( $query->param('passwordReset') ) {
147     ( $borrower_number, $username ) = GetValidLinkInfo($uniqueKey);
148
149     my $error;
150     my $min_password_length = C4::Context->preference('minPasswordPreference');
151     my $require_strong_password = C4::Context->preference('RequireStrongPassword');
152     if ( not $borrower_number ) {
153         $error = 'errLinkNotValid';
154     } elsif ( $password ne $repeatPassword ) {
155         $error = 'errPassNotMatch';
156     } else {
157         my $borrower = Koha::Patrons->find($borrower_number);
158         $min_password_length = $borrower->category->effective_min_password_length;
159         $require_strong_password = $borrower->category->effective_require_strong_password;
160         try {
161             $borrower->set_password({ password => $password });
162
163             CompletePasswordRecovery($uniqueKey);
164             $template->param(
165                 password_reset_done => 1,
166                 username            => $username
167             );
168         }
169         catch {
170             if ( $_->isa('Koha::Exceptions::Password::TooShort') ) {
171                 $error = 'password_too_short';
172             }
173             elsif ( $_->isa('Koha::Exceptions::Password::WhitespaceCharacters') ) {
174                 $error = 'password_has_whitespaces';
175             }
176             elsif ( $_->isa('Koha::Exceptions::Password::TooWeak') ) {
177                 $error = 'password_too_weak';
178             }
179         };
180     }
181     if ( $error ) {
182         $template->param(
183             new_password => 1,
184             email        => $email,
185             uniqueKey    => $uniqueKey,
186             hasError     => 1,
187             $error       => 1,
188             minPasswordLength => $min_password_length,
189             RequireStrongPassword => $require_strong_password
190         );
191     }
192 }
193 elsif ($uniqueKey) {    #reset password form
194                         #check if the link is valid
195     ( $borrower_number, $username ) = GetValidLinkInfo($uniqueKey);
196
197     if ( !$borrower_number ) {
198         $errLinkNotValid = 1;
199     }
200
201     my $borrower = Koha::Patrons->find($borrower_number);
202
203     $template->param(
204         new_password    => 1,
205         email           => $email,
206         uniqueKey       => $uniqueKey,
207         username        => $username,
208         errLinkNotValid => $errLinkNotValid,
209         hasError        => ( $errLinkNotValid ? 1 : 0 ),
210         minPasswordLength => $borrower->category->effective_min_password_length,
211         RequireStrongPassword => $borrower->category->effective_require_strong_password
212     );
213 }
214 else {    #password recovery form (to send email)
215     $template->param( password_recovery => 1 );
216 }
217
218 output_html_with_http_headers $query, $cookie, $template->output;