From 131767872159da444963c3c05ea041b0f1c1a2d1 Mon Sep 17 00:00:00 2001 From: simith Date: Wed, 11 Mar 2015 13:52:59 -0400 Subject: [PATCH] Bug 8753 - Add forgot password link to OPAC This redo includes the following - usage of the template letters for the email instead of a .tt (that feature didn't exist when the functionnality was initially coded for our client) - removal of the prog version - removal of the code that was initially put into Members.pm - Added a letter into updatedatabase.pl and sample_notices.sql - Of course, rebase to latest master. The rest remain unchanged since the previous comments/approvals. As such, what worked before should still work. TEST PLAN: 1) apply the patch 2) go to system preferences OPAC>>Privacy and set 'OpacResetPassword' to ON. That will cause the link 'Forgot yo 2b) make sure that OpacPasswordChange is also ON. 3) refresh front page, click on 'Forgot your password' and enter a VALID address (one that is associated to an en 3b) Also try an INVALID address (valid yet not in your koha db). An error message will show up. 4) An email should be received at that address with a link. 5) Follow the link in the mail to fill the new password. Until a satisfactory new password is entered, the old password is not reset. 6) Go to main page try the new password. http://bugs.koha-community.org/show_bug.cgi?id=13068 --- C4/Passwordrecovery.pm | 159 +++++++++++++++++++++ Koha/Schema/Result/BorrowerPasswordRecovery.pm | 66 +++++++++ .../data/mysql/en/mandatory/sample_notices.sql | 6 +- installer/data/mysql/kohastructure.sql | 11 ++ installer/data/mysql/sysprefs.sql | 1 + installer/data/mysql/updatedatabase.pl | 17 +++ .../prog/en/modules/admin/preferences/opac.pref | 8 ++ .../opac-tmpl/bootstrap/en/includes/masthead.inc | 3 + .../opac-tmpl/bootstrap/en/modules/opac-auth.tt | 3 + .../bootstrap/en/modules/opac-password-recovery.tt | 132 +++++++++++++++++ opac/opac-password-recovery.pl | 156 ++++++++++++++++++++ 11 files changed, 561 insertions(+), 1 deletion(-) create mode 100644 C4/Passwordrecovery.pm create mode 100644 Koha/Schema/Result/BorrowerPasswordRecovery.pm create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-password-recovery.tt create mode 100755 opac/opac-password-recovery.pl diff --git a/C4/Passwordrecovery.pm b/C4/Passwordrecovery.pm new file mode 100644 index 0000000..f1b26e9 --- /dev/null +++ b/C4/Passwordrecovery.pm @@ -0,0 +1,159 @@ +package C4::Passwordrecovery; + +# Copyright 2014 PTFS Europe +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; +use C4::Context; + +use vars qw($VERSION @ISA @EXPORT); + +BEGIN { + # set the version for version checking + $VERSION = 3.07.00.049; + require Exporter; + @ISA = qw(Exporter); + push @EXPORT, qw( + &ValidateBorrowernumber + &SendPasswordRecoveryEmail + &GetValidLinkInfo + ); +} + +=head1 NAME + +C4::Passwordrecovery - Koha password recovery module + +=head1 SYNOPSIS + +use C4::Passwordrecovery; + +=head1 FUNCTIONS + +=head2 ValidateBorrowernumber + +$alread = ValidateBorrowernumber( $borrower_number ); + +Check if the system already start recovery + +Returns true false + +=cut + +sub ValidateBorrowernumber { + my ($borrower_number) = @_; + my $schema = Koha::Database->new->schema; + + my $rs = $schema->resultset('BorrowerPasswordRecovery')->search( + { + borrowernumber => $borrower_number, + valid_until => \'> NOW()' + }, { + columns => 'borrowernumber' + }); + + if ($rs->next){ + return 1; + } + + return 0; +} + +=head2 GetValidLinkInfo + + Check if the link is still valid and return some info. + +=cut + +sub GetValidLinkInfo { + my ($uniqueKey) = @_; + my $dbh = C4::Context->dbh; + my $query = ' + SELECT borrower_password_recovery.borrowernumber, userid + FROM borrower_password_recovery, borrowers + WHERE borrowers.borrowernumber = borrower_password_recovery.borrowernumber + AND NOW() < valid_until + AND uuid = ? + '; + my $sth = $dbh->prepare($query); + $sth->execute($uniqueKey); + return $sth->fetchrow; +} + +=head2 SendPasswordRecoveryEmail + + It creates an email using the templates and send it to the user, using the specified email + +=cut + +sub SendPasswordRecoveryEmail { + my $borrower = shift; # from GetMember + my $userEmail = shift; #to_address (the one specified in the request) + my $protocol = shift; #only required to determine if 'http' or 'https' + my $update = shift; + + my $schema = Koha::Database->new->schema; + + # generate UUID + my @chars = ("A".."Z", "a".."z", "0".."9"); + my $uuid_str; + $uuid_str .= $chars[rand @chars] for 1..32; + + # insert into database + my $expirydate = DateTime->now(time_zone => C4::Context->tz())->add( days => 2 ); + if($update){ + my $rs = $schema->resultset('BorrowerPasswordRecovery')->search( + { + borrowernumber => $borrower->{'borrowernumber'}, + }); + $rs->update({uuid => $uuid_str, valid_until => $expirydate->datetime()}); + } else { + my $rs = $schema->resultset('BorrowerPasswordRecovery')->create({ + borrowernumber=>$borrower->{'borrowernumber'}, + uuid => $uuid_str, + valid_until=> $expirydate->datetime() + }); + } + + # create link + my $uuidLink = $protocol . C4::Context->preference( 'OPACBaseURL' ) . "/cgi-bin/koha/opac-password-recovery.pl?uniqueKey=$uuid_str"; + + # prepare the email + my $letter = C4::Letters::GetPreparedLetter ( + module => 'members', + letter_code => 'PASSWORD_RESET', + branchcode => $borrower->{branchcode}, + substitute => {passwordreseturl => $uuidLink, user => $borrower->{userid} }, + ); + + # define to/from emails + my $kohaEmail = C4::Context->preference( 'KohaAdminEmailAddress' ); # from + + C4::Letters::EnqueueLetter( { + letter => $letter, + borrowernumber => $borrower->{borrowernumber}, + to_address => $userEmail, + from_address => $kohaEmail, + message_transport_type => 'email', + } ); + + return 1; +} + +END { } # module clean-up code here (global destructor) + +1; \ No newline at end of file diff --git a/Koha/Schema/Result/BorrowerPasswordRecovery.pm b/Koha/Schema/Result/BorrowerPasswordRecovery.pm new file mode 100644 index 0000000..5b41fbf --- /dev/null +++ b/Koha/Schema/Result/BorrowerPasswordRecovery.pm @@ -0,0 +1,66 @@ +use utf8; +package Koha::Schema::Result::BorrowerPasswordRecovery; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +=head1 NAME + +Koha::Schema::Result::BorrowerPasswordRecovery + +=cut + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +=head1 TABLE: C + +=cut + +__PACKAGE__->table("borrower_password_recovery"); + +=head1 ACCESSORS + +=head2 borrowernumber + + data_type: 'integer' + is_nullable: 0 + +=head2 uuid + + data_type: 'varchar' + is_nullable: 0 + size: 128 + +=head2 valid_until + + data_type: 'timestamp' + datetime_undef_if_invalid: 1 + default_value: current_timestamp + is_nullable: 0 + +=cut + +__PACKAGE__->add_columns( + "borrowernumber", + { data_type => "integer", is_nullable => 0 }, + "uuid", + { data_type => "varchar", is_nullable => 0, size => 128 }, + "valid_until", + { + data_type => "timestamp", + datetime_undef_if_invalid => 1, + default_value => \"current_timestamp", + is_nullable => 0, + }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07039 @ 2014-11-03 12:08:20 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ORAWxUHIkefSfPSqrcfeXA + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/installer/data/mysql/en/mandatory/sample_notices.sql b/installer/data/mysql/en/mandatory/sample_notices.sql index 378be05..f527e37 100644 --- a/installer/data/mysql/en/mandatory/sample_notices.sql +++ b/installer/data/mysql/en/mandatory/sample_notices.sql @@ -144,4 +144,8 @@ Your library.' ); INSERT INTO letter(module, code, branchcode, name, title, content, message_transport_type) -VALUES ('acquisition', 'ACQ_NOTIF_ON_RECEIV', '', 'Notification on receiving', 'Order received', 'Dear <> <>,\n\n The order <> (<>) has been received.\n\nYour library.', 'email') +VALUES ('acquisition', 'ACQ_NOTIF_ON_RECEIV', '', 'Notification on receiving', 'Order received', 'Dear <> <>,\n\n The order <> (<>) has been received.\n\nYour library.', 'email'); + +INSERT INTO `letter` (module, code, branchcode, name, is_html, title, content, message_transport_type) +VALUES ('members','PASSWORD_RESET','','Online password reset',1,'Koha password recovery','\r\n

This email has been sent in response to your password recovery request for the account <>.\r\n

\r\n

\r\nYou can now create your new password using the following link:\r\n
>\"><>\r\n

\r\n

This link will be valid for 2 days from this email\'s reception, then you must reapply if you do not change your password.

\r\n

Thank you.

\r\n\r\n','email' +); diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 6ddba43..74e0c60 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -3520,6 +3520,17 @@ CREATE TABLE items_search_fields ( ON DELETE SET NULL ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +-- Table structure for table 'borrower_password_recovery' +-- this stores the unique ID sent by email to the patron, for future validation +-- + +CREATE TABLE IF NOT EXISTS borrower_password_recovery ( + borrowernumber int(11) NOT NULL, + uuid varchar(128) NOT NULL, + valid_until timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + KEY borrowernumber (borrowernumber) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql index 1e07e3c..bbd397c 100644 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -292,6 +292,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('opacreadinghistory','1','','If ON, enables display of Patron Circulation History in OPAC','YesNo'), ('OpacRenewalAllowed','0',NULL,'If ON, users can renew their issues directly from their OPAC account','YesNo'), ('OpacRenewalBranch','checkoutbranch','itemhomebranch|patronhomebranch|checkoutbranch|null','Choose how the branch for an OPAC renewal is recorded in statistics','Choice'), +('OpacResetPassword','1','','Shows the \'Forgot your password?\' link in the OPAC','YesNo'), ('OPACResultsSidebar','','70|10','Define HTML to be included on the search results page, underneath the facets sidebar','Textarea'), ('OPACSearchForTitleIn','
  • Other Libraries (WorldCat)
  • \n
  • Other Databases (Google Scholar)
  • \n
  • Online Stores (Bookfinder.com)
  • \n
  • Open Library (openlibrary.org)
  • ','70|10','Enter the HTML that will appear in the \'Search for this title in\' box on the detail page in the OPAC. Enter {TITLE}, {AUTHOR}, or {ISBN} in place of their respective variables in the URL. Leave blank to disable \'More Searches\' menu.','Textarea'), ('OpacSeparateHoldings','0',NULL,'Separate current branch holdings from other holdings (OPAC)','YesNo'), diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 0592a94..ed76a8f 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -9971,6 +9971,23 @@ if ( CheckVersion($DBversion) ) { SetVersion($DBversion); } +$DBversion = "XXX"; +if ( CheckVersion($DBversion) ) { + $dbh->do("INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('OpacResetPassword', '1','','Shows the ''Forgot your password?'' link in the OPAC','YesNo')"); + $dbh->do(q{ + CREATE TABLE IF NOT EXISTS borrower_password_recovery ( + borrowernumber int(11) NOT NULL, + uuid varchar(128) NOT NULL, + valid_until timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + KEY borrowernumber (borrowernumber) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + }); + $dbh->do(q{ + INSERT INTO `letter` (module, code, branchcode, name, is_html, title, content, message_transport_type) VALUES ('members','PASSWORD_RESET','','Online password reset',1,'Koha password recovery','\r\n

    This email has been sent in response to your password recovery request for the account << borrowers.userid>>.\r\n

    \r\n

    \r\nYou can now create your new password using the following link:\r\n
    >\"><>\r\n

    \r\n

    This link will be valid for 2 days from this email\'s reception, then you must reapply if you do not change your password.

    \r\n

    Thank you.

    \r\n\r\n','email') + }); + print "Upgrade to $DBversion done (Bug 8753: Add forgot password link to OPAC)\n"; + SetVersion ($DBversion); +} # DEVELOPER PROCESS, search for anything to execute in the db_update directory # SEE bug 13068 diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref index c26d048..83f78eb 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref @@ -339,6 +339,14 @@ OPAC: no: "Don't allow" - patrons to change their own password on the OPAC. Note that this must be off to use LDAP authentication. - + - "The user " + - pref: OpacResetPassword + default: 1 + choices: + yes: "can reset" + no: "can not reset" + - " their password on OPAC." + - - pref: OPACPatronDetails choices: yes: Allow diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc index aeca007..12efd90 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc +++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc @@ -309,6 +309,9 @@ [% END %] [% IF PatronSelfRegistration && PatronSelfRegistrationDefaultCategory %]

    Don't have an account? Register here.

    [% END %] + [% IF Koha.Preference('OpacPasswordChange') && Koha.Preference('OpacResetPassword') %] +

    Forgot your password?

    + [% END %]