Bug 7067 - OPAC Borrower Self Registration
authorKyle M Hall <kyle@bywatersolutions.com>
Tue, 31 Jul 2012 14:07:04 +0000 (10:07 -0400)
committerJared Camins-Esakov <jcamins@cpbibliography.com>
Fri, 14 Dec 2012 13:08:59 +0000 (08:08 -0500)
This development will add the ability for a new patron to register
himself or herself. The self-registration will attempt to match this
newly inputted data to any existing patrons and if any possible matches
are found, ask if the patron is sure he or she doesn't already have an
account at the library. A system preference may be set to prevent patron
self-registration if the system detects the possibility that the person
may already have an account.

Once the patron has registered, passing a captcha (or similar
bot-stopper), the patron will then be optionally verified a second time
via email. At this point, the patron will be able to print a temporary
library card (optional by system preference), and will be provided any
details necessary to access electronic resources (this body of text
would be a template in the slips and notices system). At the library's
choice, this new patron would either be set to a temporary patron status
(patron type set via system preference), or a fully-fledged patron
(allow patron type to be determined by age and/or other attributes).
Assuming the library uses temporary patron types for OPAC registrations,
this patron will next enter a queue and would need to physically enter
the library to verify himself and become a fully-fledged patron (most
likely by bringing in physical proof of address, etc.). The librarian
would look up the patron record and modify the patron type. If a
temporary patron has not been verified within a certain time frame
(defined by a system preference), the patron record will be deleted
from the system via a cron job.

For registered patrons, the system will allow each person to also
update his or her personal data via the OPAC. When a patron updates his
or her information, the changes will be entered into a queue to be
verified by a librarian (preventing a patron from inputting obviously
bogus data). The staff client home page will display the number of
patron records with changes awaiting approval. A librarian would then be
able to click through a list of modification requests, and approve or
deny each (with approval and denial alerts being sent to the patron via
the standard messaging system).

NEW SYSTEM PREFERENCES
* PatronSelfRegistration
* PatronSelfRegistrationDetectDuplicates
* PatronSelfRegistrationVerifyByEmail
* PatronSelfRegistrationPrintTemporaryCard
* PatronSelfRegistrationUseTemporaryStatus
* PatronSelfRegistrationExpireTemporaryAccountsDelay

NEW NOTICE
* Verify by email notice

NEW SLIP
* Temporary card slip

NEW CRON JOB
* delete_expired_opac_registrations.pl
  - Deletes patrons that have not been upgraded from the temporary
    status within the specified delay
* delete_unverified_opac_registrations.pl
  - Deletes the unverified patrons based on the length of time specified
    in the PatronSelfRegistrationExpireTemporaryAccountsDelay

The patron will register from self_registration.pl, linked off opac-main.pl if enabled. The registration page will be translatable to other languages in the same way that existing templates are.

Test Plan:
1) Enable PatronSelfRegistration
2) Set PatronSelfRegistrationExpireTemporaryAccountsDelay to a number
   of days
3) Create a self-registered borrower category
4) Set PatronSelfRegistrationUseTemporaryStatus
5) Set PatronSelfRegistrationVerifyByEmail to "Don't require"
6) Go to OPAC, log out if logged in.
7) You should see the "Register here" link below the login box
8) Attempt to register yourself
9) Verify you can log in with your temporary password.
10) Set PatronSelfRegistrationVerifyByEmail to "Require"
11) Attempt another self-registration
12) Check the messages table, you should see a new message with a
    verification link.
13) Copy and paste the link into a web browser to verify the registration
14) Log in with the given credentials to verify the account was created.

Test Plan - Part 2 - Borrower Modifications

1) Log in to OPAC, go to "my personal details" tab.
2) Make some modifications to your details.
3) Repeat steps 1 and 2 for two more borrowers.
4) Log in to Koha intranet with a user that can modify borrowers.
5) At the bottom of mainpage.pl, you should see:
  Patrons requesting modifications: 3
6) Click the link
7) Approve one change, deny a different one, and ignore the third, then
   submit.
8) Check the records, you should see the changes take affect on the
   approved one, and no changes to the other two. You should also see
   "Patrons requesting modifications: 1" at the bottom of mainpage.pl
   now.

Signed-off-by: Jonathan Druart <jonathan.druart@biblibre.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>

Bug 7067 - OPAC Borrower Self Registration - Followup

* Rename PatronSelfRegistrationUseTemporaryStatus to PatronSelfRegistrationDefaultCategory
* Hide register link unless PatronSelfRegistrationDefaultCategory is set.
* Add invalid token page
* Add documentation and switches to cron scripts
* Add required fields check for editing exiting patrons
* Don't force require email address for existing patrons when
  PatronSelfRegistrationVerifyByEmail is enabled.

Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Passed-QA-by: Jonathan Druart <jonathan.druart@biblibre.com>
Signed-off-by: Jared Camins-Esakov <jcamins@cpbibliography.com>

30 files changed:
C4/Auth.pm
C4/Installer/PerlDependencies.pm
C4/Letters.pm
C4/Log.pm
C4/Members.pm
Koha/Borrower/Modifications.pm [new file with mode: 0644]
installer/data/mysql/en/mandatory/sample_notices.sql
installer/data/mysql/kohastructure.sql
installer/data/mysql/sysprefs.sql
installer/data/mysql/updatedatabase.pl
koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref
koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt
koha-tmpl/intranet-tmpl/prog/en/modules/members/members-update.tt [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/en/includes/opac-bottom.inc
koha-tmpl/opac-tmpl/prog/en/includes/usermenu.inc
koha-tmpl/opac-tmpl/prog/en/modules/opac-auth.tt
koha-tmpl/opac-tmpl/prog/en/modules/opac-main.tt
koha-tmpl/opac-tmpl/prog/en/modules/opac-memberentry-update-submitted.tt [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/en/modules/opac-memberentry.tt [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/en/modules/opac-registration-confirmation.tt [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/en/modules/opac-registration-email-sent.tt [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/en/modules/opac-registration-invalid.tt [new file with mode: 0644]
mainpage.pl
members/members-update-do.pl [new file with mode: 0755]
members/members-update.pl [new file with mode: 0755]
misc/cronjobs/delete_expired_opac_registrations.pl [new file with mode: 0755]
misc/cronjobs/delete_unverified_opac_registrations.pl [new file with mode: 0755]
opac/opac-memberentry.pl [new file with mode: 0755]
opac/opac-registration-verify.pl [new file with mode: 0755]
opac/opac-user.pl

index 705eda0..4ea03c0 100644 (file)
@@ -462,6 +462,8 @@ sub get_template_and_user {
             SyndeticsSeries              => C4::Context->preference("SyndeticsSeries"),
             SyndeticsCoverImageSize      => C4::Context->preference("SyndeticsCoverImageSize"),
             OPACLocalCoverImages         => C4::Context->preference("OPACLocalCoverImages"),
+            PatronSelfRegistration       => C4::Context->preference("PatronSelfRegistration"),
+            PatronSelfRegistrationDefaultCategory => C4::Context->preference("PatronSelfRegistrationDefaultCategory"),
         );
 
         $template->param(OpacPublic => '1') if ($user || C4::Context->preference("OpacPublic"));
@@ -967,10 +969,9 @@ sub checkauth {
         OpacAuthorities      => C4::Context->preference("OpacAuthorities"),
         OpacBrowser          => C4::Context->preference("OpacBrowser"),
         opacheader           => C4::Context->preference("opacheader"),
-        TagsEnabled                  => C4::Context->preference("TagsEnabled"),
+        TagsEnabled          => C4::Context->preference("TagsEnabled"),
         OPACUserCSS           => C4::Context->preference("OPACUserCSS"),
-        intranetcolorstylesheet =>
-                                                               C4::Context->preference("intranetcolorstylesheet"),
+        intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
         intranetstylesheet => C4::Context->preference("intranetstylesheet"),
         intranetbookbag    => C4::Context->preference("intranetbookbag"),
         IntranetNav        => C4::Context->preference("IntranetNav"),
@@ -978,7 +979,9 @@ sub checkauth {
         intranetuserjs     => C4::Context->preference("intranetuserjs"),
         IndependantBranches=> C4::Context->preference("IndependantBranches"),
         AutoLocation       => C4::Context->preference("AutoLocation"),
-               wrongip            => $info{'wrongip'},
+        wrongip            => $info{'wrongip'},
+        PatronSelfRegistration => C4::Context->preference("PatronSelfRegistration"),
+        PatronSelfRegistrationDefaultCategory => C4::Context->preference("PatronSelfRegistrationDefaultCategory"),
     );
 
     $template->param( OpacPublic => C4::Context->preference("OpacPublic"));
index 71f35d4..16144f9 100644 (file)
@@ -629,6 +629,11 @@ our $PERL_DEPS = {
         'required' => '0',
         'min_ver'  => '1.09',
       },
+    'String::Random' => {
+        'usage'    => 'OpacSelfRegistration',
+        'required' => '0',
+        'min_ver'  => '1.4',
+    },
 };
 
 1;
index f646241..a585ff8 100644 (file)
@@ -540,6 +540,9 @@ sub GetProcessedLetter {
        }
     }
 
+    my $OPACBaseURL = C4::Context->preference('OPACBaseURL');
+    $letter->{content} =~ s/<<OPACBaseURL>>/$OPACBaseURL/go;
+
     if ($want_librarian) {
         # parsing librarian name
         my $userenv = C4::Context->userenv;
@@ -638,18 +641,19 @@ sub _parseletter_sth {
     # check cache first
     (defined $handles{$table}) and return $handles{$table};
     my $query = 
-    ($table eq 'biblio'       ) ? "SELECT * FROM $table WHERE   biblionumber = ?"                                 :
-    ($table eq 'biblioitems'  ) ? "SELECT * FROM $table WHERE   biblionumber = ?"                                 :
-    ($table eq 'items'        ) ? "SELECT * FROM $table WHERE     itemnumber = ?"                                 :
-    ($table eq 'issues'       ) ? "SELECT * FROM $table WHERE     itemnumber = ?"                                 :
-    ($table eq 'old_issues'   ) ? "SELECT * FROM $table WHERE     itemnumber = ? ORDER BY timestamp DESC LIMIT 1" :
-    ($table eq 'reserves'     ) ? "SELECT * FROM $table WHERE borrowernumber = ? and biblionumber = ?"            :
-    ($table eq 'borrowers'    ) ? "SELECT * FROM $table WHERE borrowernumber = ?"                                 :
-    ($table eq 'branches'     ) ? "SELECT * FROM $table WHERE     branchcode = ?"                                 :
-    ($table eq 'suggestions'  ) ? "SELECT * FROM $table WHERE   suggestionid = ?"                                 :
-    ($table eq 'aqbooksellers') ? "SELECT * FROM $table WHERE             id = ?"                                 :
-    ($table eq 'aqorders'     ) ? "SELECT * FROM $table WHERE    ordernumber = ?"                                 :
-    ($table eq 'opac_news'    ) ? "SELECT * FROM $table WHERE          idnew = ?"                                 :
+    ($table eq 'biblio'       ) ? "SELECT * FROM $table WHERE   biblionumber = ?"                                  :
+    ($table eq 'biblioitems'  ) ? "SELECT * FROM $table WHERE   biblionumber = ?"                                  :
+    ($table eq 'items'        ) ? "SELECT * FROM $table WHERE     itemnumber = ?"                                  :
+    ($table eq 'issues'       ) ? "SELECT * FROM $table WHERE     itemnumber = ?"                                  :
+    ($table eq 'old_issues'   ) ? "SELECT * FROM $table WHERE     itemnumber = ? ORDER BY timestamp DESC LIMIT 1"  :
+    ($table eq 'reserves'     ) ? "SELECT * FROM $table WHERE borrowernumber = ? and biblionumber = ?"             :
+    ($table eq 'borrowers'    ) ? "SELECT * FROM $table WHERE borrowernumber = ?"                                  :
+    ($table eq 'branches'     ) ? "SELECT * FROM $table WHERE     branchcode = ?"                                  :
+    ($table eq 'suggestions'  ) ? "SELECT * FROM $table WHERE   suggestionid = ?"                                  :
+    ($table eq 'aqbooksellers') ? "SELECT * FROM $table WHERE             id = ?"                                  :
+    ($table eq 'aqorders'     ) ? "SELECT * FROM $table WHERE    ordernumber = ?"                                  :
+    ($table eq 'opac_news'    ) ? "SELECT * FROM $table WHERE          idnew = ?"                                  :
+    ($table eq 'borrower_modifications') ? "SELECT * FROM $table WHERE borrowernumber = ? OR verification_token =?":
     undef ;
     unless ($query) {
         warn "ERROR: No _parseletter_sth query for table '$table'";
@@ -756,7 +760,7 @@ sub EnqueueLetter {
     my $params = shift or return;
 
     return unless exists $params->{'letter'};
-    return unless exists $params->{'borrowernumber'};
+#   return unless exists $params->{'borrowernumber'};
     return unless exists $params->{'message_transport_type'};
 
     my $content = $params->{letter}->{content};
index 14448e3..671fcdb 100644 (file)
--- a/C4/Log.pm
+++ b/C4/Log.pm
@@ -73,6 +73,7 @@ sub logaction {
     # the scalar '0'.
     my $userenv = C4::Context->userenv();
     my $usernumber = (ref($userenv) eq 'HASH') ? $userenv->{'number'} : 0;
+    $usernumber ||= 0;
 
     my $dbh = C4::Context->dbh;
     my $sth=$dbh->prepare("Insert into action_logs (timestamp,user,module,action,object,info) values (now(),?,?,?,?,?)");
index f381a41..81b014b 100644 (file)
@@ -25,6 +25,7 @@ use strict;
 use C4::Context;
 use C4::Dates qw(format_date_in_iso format_date);
 use Digest::MD5 qw(md5_base64);
+use String::Random qw( random_string );
 use Date::Calc qw/Today Add_Delta_YM check_date Date_to_Days/;
 use C4::Log; # logaction
 use C4::Overdues;
@@ -118,6 +119,7 @@ BEGIN {
     #Insert data
     push @EXPORT, qw(
         &AddMember
+        &AddMember_Opac
         &add_member_orgs
         &MoveMemberToDeleted
         &ExtendMemberSubscriptionTo
@@ -751,11 +753,25 @@ Returns as undef upon any db error without further processing
 sub AddMember {
     my (%data) = @_;
     my $dbh = C4::Context->dbh;
-       # generate a proper login if none provided
-       $data{'userid'} = Generate_Userid($data{'borrowernumber'}, $data{'firstname'}, $data{'surname'}) if $data{'userid'} eq '';
-       # create a disabled account if no password provided
-       $data{'password'} = ($data{'password'})? md5_base64($data{'password'}) : '!';
-       $data{'borrowernumber'}=InsertInTable("borrowers",\%data);      
+
+    # generate a proper login if none provided
+    $data{'userid'} = Generate_Userid($data{'borrowernumber'}, $data{'firstname'}, $data{'surname'}) if $data{'userid'} eq '';
+
+    # add expiration date if it isn't already there
+    unless ( $data{'dateexpiry'} ) {
+        $data{'dateexpiry'} = GetExpiryDate( $data{'categorycode'}, C4::Dates->new()->output("iso") );
+    }
+
+    # add enrollment date if it isn't already there
+    unless ( $data{'dateenrolled'} ) {
+        $data{'dateenrolled'} = C4::Dates->new()->output("iso");
+    }
+
+    # create a disabled account if no password provided
+    $data{'password'} = ($data{'password'})? md5_base64($data{'password'}) : '!';
+    $data{'borrowernumber'}=InsertInTable("borrowers",\%data);
+
+
     # mysql_insertid is probably bad.  not necessarily accurate and mysql-specific at best.
     logaction("MEMBERS", "CREATE", $data{'borrowernumber'}, "") if C4::Context->preference("BorrowersLog");
     
@@ -2379,6 +2395,22 @@ sub GetBorrowersWithEmail {
     return @result;
 }
 
+sub AddMember_Opac {
+    my ( %borrower ) = @_;
+
+    $borrower{'categorycode'} = C4::Context->preference('PatronSelfRegistrationDefaultCategory');
+
+    my $sr = new String::Random;
+    $sr->{'A'} = [ 'A'..'Z', 'a'..'z' ];
+    my $password = $sr->randpattern("AAAAAAAAAA");
+    $borrower{'password'} = $password;
+
+    $borrower{'cardnumber'} = fixup_cardnumber();
+
+    my $borrowernumber = AddMember(%borrower);
+
+    return ( $borrowernumber, $password );
+}
 
 END { }    # module clean-up code here (global destructor)
 
diff --git a/Koha/Borrower/Modifications.pm b/Koha/Borrower/Modifications.pm
new file mode 100644 (file)
index 0000000..f83b61d
--- /dev/null
@@ -0,0 +1,369 @@
+package Koha::Borrower::Modifications;
+
+# Copyright 2012 ByWater Solutions
+# 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 2 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+=head1 NAME
+
+C4::Borrowers::Modifications
+
+=cut
+
+use Modern::Perl;
+
+use C4::Context;
+use C4::Debug;
+use C4::SQLHelper qw(InsertInTable UpdateInTable);
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+BEGIN {
+
+    # set the version for version checking
+    $VERSION = 0.01;
+    require Exporter;
+    @ISA    = qw(Exporter);
+    @EXPORT = qw(
+
+    );
+
+    my $debug = C4::Context->preference("DebugLevel");
+}
+
+sub new {
+    my ( $class, %args ) = @_;
+    my $self = bless( {}, $class );
+
+    $self->{'verification_token'} = $args{'verification_token'};
+    $self->{'borrowernumber'}     = $args{'borrowernumber'};
+
+    return $self;
+}
+
+=head AddModifications
+
+Koha::Borrower::Modifications->AddModifications( %data );
+
+Adds or updates modifications for a borrower.
+
+Requires either the key borrowernumber, or verification_token
+to be part of the passed in hash.
+
+=cut
+
+sub AddModifications {
+    my ( $self, %data ) = @_;
+
+    if ( $self->{'borrowernumber'} ) {
+        delete $data{'borrowernumber'};
+
+        if ( keys %data ) {
+            $data{'borrowernumber'} = $self->{'borrowernumber'};
+            my $dbh = C4::Context->dbh;
+
+            my $query = "
+                SELECT COUNT(*) AS count
+                FROM borrower_modifications
+                WHERE borrowernumber = ?
+            ";
+
+            my $sth = $dbh->prepare($query);
+            $sth->execute( $self->{'borrowernumber'} );
+            my $result = $sth->fetchrow_hashref();
+
+            if ( $result->{'count'} ) {
+                $data{'verification_token'} = q{};
+                return UpdateInTable( "borrower_modifications", \%data );
+            }
+            else {
+                return InsertInTable( "borrower_modifications", \%data );
+            }
+        }
+
+    }
+    elsif ( $self->{'verification_token'} ) {
+        delete $data{'borrowernumber'};
+        $data{'verification_token'} = $self->{'verification_token'};
+
+        return InsertInTable( "borrower_modifications", \%data );
+    }
+    else {
+        return;
+    }
+}
+
+=head Verify
+
+$verified = Koha::Borrower::Modifications->Verify( $verification_token );
+
+Returns true if the passed in token is valid.
+
+=cut
+
+sub Verify {
+    my ( $self, $verification_token ) = @_;
+
+    if ( ref($self) ) {
+        $verification_token =
+          ($verification_token)
+          ? $verification_token
+          : $self->{'verification_token'};
+    }
+
+    my $dbh   = C4::Context->dbh;
+    my $query = "
+        SELECT COUNT(*) AS count
+        FROM borrower_modifications
+        WHERE verification_token = ?
+    ";
+    my $sth = $dbh->prepare($query);
+    $sth->execute($verification_token);
+    my $result = $sth->fetchrow_hashref();
+
+    return $result->{'count'};
+}
+
+=head GetPendingModificationsCount
+
+$count = Koha::Borrower::Modifications->GetPendingModificationsCount();
+
+Returns the number of pending modifications for existing borrowers.
+=cut
+
+sub GetPendingModificationsCount {
+    my ( $self, $branchcode ) = @_;
+
+    my $dbh   = C4::Context->dbh;
+    my $query = "
+        SELECT COUNT(*) AS count
+        FROM borrower_modifications, borrowers
+        WHERE borrower_modifications.borrowernumber > 0
+        AND borrower_modifications.borrowernumber = borrowers.borrowernumber
+    ";
+
+    my @params;
+    if ($branchcode) {
+        $query .= " AND borrowers.branchcode = ? ";
+        push( @params, $branchcode );
+    }
+
+    my $sth = $dbh->prepare($query);
+    $sth->execute(@params);
+    my $result = $sth->fetchrow_hashref();
+
+    return $result->{'count'};
+}
+
+=head GetPendingModifications
+
+$arrayref = Koha::Borrower::Modifications->GetPendingModifications();
+
+Returns an arrayref of hashrefs for all pending modifications for existing borrowers.
+
+=cut
+
+sub GetPendingModifications {
+    my ( $self, $branchcode ) = @_;
+
+    my $dbh   = C4::Context->dbh;
+    my $query = "
+        SELECT borrower_modifications.*
+        FROM borrower_modifications, borrowers
+        WHERE borrower_modifications.borrowernumber > 0
+        AND borrower_modifications.borrowernumber = borrowers.borrowernumber
+    ";
+
+    my @params;
+    if ($branchcode) {
+        $query .= " AND borrowers.branchcode = ? ";
+        push( @params, $branchcode );
+    }
+
+    my $sth = $dbh->prepare($query);
+    $sth->execute(@params);
+
+    my @m;
+    while ( my $row = $sth->fetchrow_hashref() ) {
+        foreach my $key ( keys %$row ) {
+            delete $row->{$key} unless defined $row->{$key};
+        }
+
+        push( @m, $row );
+    }
+
+    return \@m;
+}
+
+=head ApproveModifications
+
+Koha::Borrower::Modifications->ApproveModifications( $borrowernumber );
+
+Commits the pending modifications to the borrower record and removes
+them from the modifications table.
+
+=cut
+
+sub ApproveModifications {
+    my ( $self, $borrowernumber ) = @_;
+
+    if ( ref($self) ) {
+        $borrowernumber =
+          ($borrowernumber) ? $borrowernumber : $self->{'borrowernumber'};
+    }
+
+    return unless $borrowernumber;
+
+    my $data = $self->GetModifications( borrowernumber => $borrowernumber );
+
+    if ( UpdateInTable( "borrowers", $data ) ) {
+        $self->DelModifications( borrowernumber => $borrowernumber );
+    }
+}
+
+=head DenyModifications
+
+Koha::Borrower::Modifications->DenyModifications( $borrowernumber );
+
+Removes the modifications from the table for the given borrower,
+without commiting the changes to the borrower record.
+
+=cut
+
+sub DenyModifications {
+    my ( $self, $borrowernumber ) = @_;
+
+    if ( ref($self) ) {
+        $borrowernumber =
+          ($borrowernumber) ? $borrowernumber : $self->{'borrowernumber'};
+    }
+
+    return unless $borrowernumber;
+
+    return $self->DelModifications( borrowernumber => $borrowernumber );
+}
+
+=head DelModifications
+
+Koha::Borrower::Modifications->DelModifications(
+  [ borrowernumber => $borrowernumber ],
+  [ verification_token => $verification_token ]
+);
+
+Deletes the modifications for the given borrowernumber or verification token.
+
+=cut
+
+sub DelModifications {
+    my ( $self, %params ) = @_;
+
+    my ( $field, $value );
+
+    if ( $params{'borrowernumber'} ) {
+        $field = 'borrowernumber';
+        $value = $params{'borrowernumber'};
+    }
+    elsif ( $params{'verification_token'} ) {
+        $field = 'verification_token';
+        $value = $params{'verification_token'};
+    }
+
+    if ( ref($self) && !$value ) {
+        if ( $self->{'borrowernumber'} ) {
+            $field = 'borrowernumber';
+            $value = $self->{'borrowernumber'};
+        }
+        elsif ( $self->{'verification_token'} ) {
+            $field = 'verification_token';
+            $value = $self->{'verification_token'};
+        }
+    }
+
+    return unless $value;
+
+    my $dbh = C4::Context->dbh;
+
+    $field = $dbh->quote_identifier($field);
+
+    my $query = "
+        DELETE
+        FROM borrower_modifications
+        WHERE $field = ?
+    ";
+
+    my $sth = $dbh->prepare($query);
+    return $sth->execute($value);
+}
+
+=head GetModifications
+
+$hashref = Koha::Borrower::Modifications->GetModifications(
+  [ borrowernumber => $borrowernumber ],
+  [ verification_token => $verification_token ]
+);
+
+Gets the modifications for the given borrowernumber or verification token.
+
+=cut
+
+sub GetModifications {
+    my ( $self, %params ) = @_;
+
+    my ( $field, $value );
+
+    if ( $params{'borrowernumber'} ) {
+        $field = 'borrowernumber';
+        $value = $params{'borrowernumber'};
+    }
+    elsif ( $params{'verification_token'} ) {
+        $field = 'verification_token';
+        $value = $params{'verification_token'};
+    }
+
+    if ( ref($self) && !$value ) {
+        if ( $self->{'borrowernumber'} ) {
+            $field = 'borrowernumber';
+            $value = $self->{'borrowernumber'};
+        }
+        elsif ( $self->{'verification_token'} ) {
+            $field = 'verification_token';
+            $value = $self->{'verification_token'};
+        }
+    }
+
+    return unless $value;
+
+    my $dbh = C4::Context->dbh;
+
+    $field = $dbh->quote_identifier($field);
+
+    my $query = "
+        SELECT *
+        FROM borrower_modifications
+        WHERE $field = ?
+    ";
+
+    my $sth = $dbh->prepare($query);
+    $sth->execute($value);
+    my $data = $sth->fetchrow_hashref();
+
+    foreach my $key ( keys %$data ) {
+        delete $data->{$key} unless ( defined( $data->{$key} ) );
+    }
+
+    return $data;
+}
+
+1;
index 6fa0a54..e6e9df0 100644 (file)
@@ -105,3 +105,15 @@ Date due: <<issues.date_due>><br />
    <li><<items.barcode>></li>
    <li><<items.itemcallnumber>></li>
 </ul>', 1);
+
+
+INSERT INTO `letter` (`module`,`code`,`branchcode`,`name`,`is_html`,`title`,`content`)
+VALUES (
+'members',  'OPAC_REG_VERIFY',  '',  'Opac Self-Registration Verification Email',  '1',  'Verify Your Account',  'Hello!
+
+Your library account has been created. Please verify your email address by clicking this link to complete the signup process:
+
+http://<<OPACBaseURL>>/cgi-bin/koha/opac-registration-verify.pl?token=<<borrower_modifications.verification_token>>
+
+If you did not initiate this request, you may safely ignore this one-time message. The request will expire shortly.'
+);
\ No newline at end of file
index ddf4b0f..ed673da 100644 (file)
@@ -2977,6 +2977,84 @@ CREATE TABLE borrower_attribute_types_branches( -- association table between bor
     FOREIGN KEY (b_branchcode) REFERENCES branches(branchcode) ON DELETE CASCADE
 ) ENGINE=INNODB DEFAULT CHARSET=utf8;
 
+--
+-- Table structure for table `borrower_modifications`
+--
+
+CREATE TABLE IF NOT EXISTS `borrower_modifications` (
+  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `verification_token` varchar(255) NOT NULL DEFAULT '',
+  `borrowernumber` int(11) NOT NULL DEFAULT '0',
+  `cardnumber` varchar(16) DEFAULT NULL,
+  `surname` mediumtext,
+  `firstname` text,
+  `title` mediumtext,
+  `othernames` mediumtext,
+  `initials` text,
+  `streetnumber` varchar(10) DEFAULT NULL,
+  `streettype` varchar(50) DEFAULT NULL,
+  `address` mediumtext,
+  `address2` text,
+  `city` mediumtext,
+  `state` text,
+  `zipcode` varchar(25) DEFAULT NULL,
+  `country` text,
+  `email` mediumtext,
+  `phone` text,
+  `mobile` varchar(50) DEFAULT NULL,
+  `fax` mediumtext,
+  `emailpro` text,
+  `phonepro` text,
+  `B_streetnumber` varchar(10) DEFAULT NULL,
+  `B_streettype` varchar(50) DEFAULT NULL,
+  `B_address` varchar(100) DEFAULT NULL,
+  `B_address2` text,
+  `B_city` mediumtext,
+  `B_state` text,
+  `B_zipcode` varchar(25) DEFAULT NULL,
+  `B_country` text,
+  `B_email` text,
+  `B_phone` mediumtext,
+  `dateofbirth` date DEFAULT NULL,
+  `branchcode` varchar(10) DEFAULT NULL,
+  `categorycode` varchar(10) DEFAULT NULL,
+  `dateenrolled` date DEFAULT NULL,
+  `dateexpiry` date DEFAULT NULL,
+  `gonenoaddress` tinyint(1) DEFAULT NULL,
+  `lost` tinyint(1) DEFAULT NULL,
+  `debarred` date DEFAULT NULL,
+  `debarredcomment` varchar(255) DEFAULT NULL,
+  `contactname` mediumtext,
+  `contactfirstname` text,
+  `contacttitle` text,
+  `guarantorid` int(11) DEFAULT NULL,
+  `borrowernotes` mediumtext,
+  `relationship` varchar(100) DEFAULT NULL,
+  `ethnicity` varchar(50) DEFAULT NULL,
+  `ethnotes` varchar(255) DEFAULT NULL,
+  `sex` varchar(1) DEFAULT NULL,
+  `password` varchar(30) DEFAULT NULL,
+  `flags` int(11) DEFAULT NULL,
+  `userid` varchar(75) DEFAULT NULL,
+  `opacnote` mediumtext,
+  `contactnote` varchar(255) DEFAULT NULL,
+  `sort1` varchar(80) DEFAULT NULL,
+  `sort2` varchar(80) DEFAULT NULL,
+  `altcontactfirstname` varchar(255) DEFAULT NULL,
+  `altcontactsurname` varchar(255) DEFAULT NULL,
+  `altcontactaddress1` varchar(255) DEFAULT NULL,
+  `altcontactaddress2` varchar(255) DEFAULT NULL,
+  `altcontactaddress3` varchar(255) DEFAULT NULL,
+  `altcontactstate` text,
+  `altcontactzipcode` varchar(50) DEFAULT NULL,
+  `altcontactcountry` text,
+  `altcontactphone` varchar(50) DEFAULT NULL,
+  `smsalertnumber` varchar(50) DEFAULT NULL,
+  `privacy` int(11) DEFAULT NULL,
+  PRIMARY KEY (`verification_token`,`borrowernumber`),
+  KEY `verification_token` (`verification_token`),
+  KEY `borrowernumber` (`borrowernumber`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
 /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
index 0cc5a54..2fb5bd4 100644 (file)
@@ -388,3 +388,10 @@ INSERT INTO systempreferences (variable, value, options, explanation, type) VALU
 INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('HoldsToPullStartDate','2','Set the default start date for the Holds to pull list to this many days ago',NULL,'Integer');
 INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('alphabet','A B C D E F G H I J K L M N O P Q R S T U V W X Y Z','Alphabet than can be expanded into browse links, e.g. on Home > Patrons',NULL,'free');
 INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('RefundLostItemFeeOnReturn', '1', 'If enabled, the lost item fee charged to a borrower will be refunded when the lost item is returned.', NULL, 'YesNo');
+INSERT INTO systempreferences (`variable`, `value`, `options`, `explanation`, `type`) VALUES
+('PatronSelfRegistration', '0', NULL, 'If enabled, patrons will be able to register themselves via the OPAC.', 'YesNo'),
+('PatronSelfRegistrationVerifyByEmail', '0', NULL, 'If enabled, any patron attempting to register themselves via the OPAC will be required to verify themselves via email to activate his or her account.', 'YesNo'),
+('PatronSelfRegistrationDefaultCategory', '', '', 'A patron registered via the OPAC will receive a borrower category code set in this system preference.', 'free'),
+('PatronSelfRegistrationExpireTemporaryAccountsDelay', '0', NULL, 'If PatronSelfRegistrationDefaultCategory is enabled, this system preference controls how long a patron can have a temporary status before the account is deleted automatically. It is an integer value representing a number of days to wait before deleting a temporary patron account. Setting it to 0 disables the deleting of temporary accounts.', 'Integer'),
+('PatronSelfRegistrationBorrowerMandatoryField',  'surname|firstname', NULL ,  'Choose the mandatory fields for a patron''s account, when registering via the OPAC.',  'free'),
+('PatronSelfRegistrationBorrowerUnwantedField',  '', NULL ,  'Name the fields you don''t want to display when registering a new patron via the OPAC.',  'free');
index 39e4bde..8328192 100755 (executable)
@@ -5714,6 +5714,110 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
           ) ENGINE=InnoDB DEFAULT CHARSET=utf8");
 
     print "Upgrade to $DBversion done (creating `transport_cost` table; adding UseTransportCostMatrix systempref, in circulation)\n";
+    SetVersion($DBversion);
+}
+
+$DBversion = '3.09.00.XXX';
+if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
+    $dbh->do("
+        CREATE TABLE IF NOT EXISTS `borrower_modifications` (
+          `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+          `verification_token` varchar(255) NOT NULL DEFAULT '',
+          `borrowernumber` int(11) NOT NULL DEFAULT '0',
+          `cardnumber` varchar(16) DEFAULT NULL,
+          `surname` mediumtext,
+          `firstname` text,
+          `title` mediumtext,
+          `othernames` mediumtext,
+          `initials` text,
+          `streetnumber` varchar(10) DEFAULT NULL,
+          `streettype` varchar(50) DEFAULT NULL,
+          `address` mediumtext,
+          `address2` text,
+          `city` mediumtext,
+          `state` text,
+          `zipcode` varchar(25) DEFAULT NULL,
+          `country` text,
+          `email` mediumtext,
+          `phone` text,
+          `mobile` varchar(50) DEFAULT NULL,
+          `fax` mediumtext,
+          `emailpro` text,
+          `phonepro` text,
+          `B_streetnumber` varchar(10) DEFAULT NULL,
+          `B_streettype` varchar(50) DEFAULT NULL,
+          `B_address` varchar(100) DEFAULT NULL,
+          `B_address2` text,
+          `B_city` mediumtext,
+          `B_state` text,
+          `B_zipcode` varchar(25) DEFAULT NULL,
+          `B_country` text,
+          `B_email` text,
+          `B_phone` mediumtext,
+          `dateofbirth` date DEFAULT NULL,
+          `branchcode` varchar(10) DEFAULT NULL,
+          `categorycode` varchar(10) DEFAULT NULL,
+          `dateenrolled` date DEFAULT NULL,
+          `dateexpiry` date DEFAULT NULL,
+          `gonenoaddress` tinyint(1) DEFAULT NULL,
+          `lost` tinyint(1) DEFAULT NULL,
+          `debarred` date DEFAULT NULL,
+          `debarredcomment` varchar(255) DEFAULT NULL,
+          `contactname` mediumtext,
+          `contactfirstname` text,
+          `contacttitle` text,
+          `guarantorid` int(11) DEFAULT NULL,
+          `borrowernotes` mediumtext,
+          `relationship` varchar(100) DEFAULT NULL,
+          `ethnicity` varchar(50) DEFAULT NULL,
+          `ethnotes` varchar(255) DEFAULT NULL,
+          `sex` varchar(1) DEFAULT NULL,
+          `password` varchar(30) DEFAULT NULL,
+          `flags` int(11) DEFAULT NULL,
+          `userid` varchar(75) DEFAULT NULL,
+          `opacnote` mediumtext,
+          `contactnote` varchar(255) DEFAULT NULL,
+          `sort1` varchar(80) DEFAULT NULL,
+          `sort2` varchar(80) DEFAULT NULL,
+          `altcontactfirstname` varchar(255) DEFAULT NULL,
+          `altcontactsurname` varchar(255) DEFAULT NULL,
+          `altcontactaddress1` varchar(255) DEFAULT NULL,
+          `altcontactaddress2` varchar(255) DEFAULT NULL,
+          `altcontactaddress3` varchar(255) DEFAULT NULL,
+          `altcontactstate` text,
+          `altcontactzipcode` varchar(50) DEFAULT NULL,
+          `altcontactcountry` text,
+          `altcontactphone` varchar(50) DEFAULT NULL,
+          `smsalertnumber` varchar(50) DEFAULT NULL,
+          `privacy` int(11) DEFAULT NULL,
+          PRIMARY KEY (`verification_token`,`borrowernumber`),
+          KEY `verification_token` (`verification_token`),
+          KEY `borrowernumber` (`borrowernumber`)
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+");
+
+    $dbh->do("
+        INSERT INTO systempreferences (`variable`, `value`, `options`, `explanation`, `type`) VALUES
+        ('PatronSelfRegistration', '0', NULL, 'If enabled, patrons will be able to register themselves via the OPAC.', 'YesNo'),
+        ('PatronSelfRegistrationVerifyByEmail', '0', NULL, 'If enabled, any patron attempting to register themselves via the OPAC will be required to verify themselves via email to activate his or her account.', 'YesNo'),
+        ('PatronSelfRegistrationDefaultCategory', '', '', 'A patron registered via the OPAC will receive a borrower category code set in this system preference.', 'free'),
+        ('PatronSelfRegistrationExpireTemporaryAccountsDelay', '0', NULL, 'If PatronSelfRegistrationDefaultCategory is enabled, this system preference controls how long a patron can have a temporary status before the account is deleted automatically. It is an integer value representing a number of days to wait before deleting a temporary patron account. Setting it to 0 disables the deleting of temporary accounts.', 'Integer'),
+        ('PatronSelfRegistrationBorrowerMandatoryField',  'surname|firstname', NULL ,  'Choose the mandatory fields for a patron''s account, when registering via the OPAC.',  'free'),
+        ('PatronSelfRegistrationBorrowerUnwantedField',  '', NULL ,  'Name the fields you don''t want to display when registering a new patron via the OPAC.',  'free');
+    ");
+
+    $dbh->do("
+    INSERT INTO  letter ( `module`, `code`, `branchcode`, `name`, `is_html`, `title`, `content` )
+    VALUES ( 'members', 'OPAC_REG_VERIFY', '', 'Opac Self-Registration Verification Email', '1', 'Verify Your Account', 'Hello!
+
+    Your library account has been created. Please verify your email address by clicking this link to complete the signup process:
+
+    http://<<OPACBaseURL>>/cgi-bin/koha/opac-registration-verify.pl?token=<<borrower_modifications.verification_token>>
+
+    If you did not initiate this request, you may safely ignore this one-time message. The request will expire shortly.'
+    )");
+
+    print "Upgrade to $DBversion done (Add Patron Self Registration)\n";
     SetVersion ($DBversion);
 }
 
index 2866f8d..bcf7124 100644 (file)
@@ -527,3 +527,37 @@ OPAC:
                   yes: Use
                   no: "Don't use"
             - "the item collection code when finding items for the shelf browser."      
+
+    Self Registration:
+        -
+            - pref: PatronSelfRegistration
+              choices:
+                  yes: Allow
+                  no: "Don't allow"
+            - "library patrons to register an account via the OPAC."
+        -
+            - pref: PatronSelfRegistrationVerifyByEmail
+              choices:
+                  yes: Require
+                  no: "Don't require"
+            - "that a self-registering patron verify his or herself via email."
+        -
+            - "Use the patron category code"
+            - pref: PatronSelfRegistrationDefaultCategory
+              class: short
+            - "as the default patron category for patrons registered via the OPAC."
+        -
+            - "Delete patrons registered via the OPAC, but not yet verified after"
+            - pref: PatronSelfRegistrationExpireTemporaryAccountsDelay
+              class: integer
+            - "days."
+        -
+            - "The following <a href='http://schema.koha-community.org/tables/borrowers.html' target='blank'>database columns</a> must be filled in on the patron entry screen:"
+            - pref: PatronSelfRegistrationBorrowerMandatoryField
+              class: multi
+            - (separate columns with |)
+        -
+            - "The following <a href='http://schema.koha-community.org/tables/borrowers.html' target='blank'>database columns</a> will not appear on the patron entry screen:"
+            - pref: PatronSelfRegistrationBorrowerUnwantedField
+              class: multi
+            - (separate columns with |)
index 4e91e06..e7363b0 100644 (file)
 <div class="yui-g">
             [% IF ( ( CAN_user_tools_moderate_comments  && pendingcomments ) 
                     || ( CAN_user_tools_moderate_tags && pendingtags )
+                    || ( CAN_user_borrowers && pending_borrower_modifications )
                     || ( CAN_user_acquisition && pendingsuggestions ) ) %]
                 <div id="area-pending">
                     [% IF ( CAN_user_acquisition && pendingsuggestions ) %]
                         <span class="pending-number-link">[% pendingtags %]</span>
                     </div>
                     [% END %]
+
+
+                    [% IF ( CAN_user_borrowers && pending_borrower_modifications ) %]
+                    <div class="pending-info">
+                        <a href="/cgi-bin/koha/members/members-update.pl">Patrons requesting modifications</a>:
+                        <span class="pending-number-link">[% pending_borrower_modifications %]</span>
+                    </div>
+                    [% END %]
+
                 </div>
-            [% END %]
 
+            [% END %]
 
 </div>
             [% IF ( IntranetmainUserblock ) %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/members-update.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/members-update.tt
new file mode 100644 (file)
index 0000000..228ccf2
--- /dev/null
@@ -0,0 +1,140 @@
+[% INCLUDE 'doc-head-open.inc' %]
+<title>Koha &rsaquo; Patrons [% IF ( searching ) %]&rsaquo; Search results[% END %]</title>
+[% INCLUDE 'doc-head-close.inc' %]
+</head>
+<body id="pat_member" class="pat">
+[% INCLUDE 'header.inc' %]
+[% INCLUDE 'patron-search.inc' %]
+
+[%
+    SET field_display_names = {
+        surname         => "Surname"
+        firstname       => "First name"
+        title           => "Title"
+        othernames      => "Other names"
+        initials        => "Initials"
+        streetnumber    => "Street number"
+        streettype      => "Street type"
+        address         => "Address"
+        address2        => "Address 2"
+        city            => "City"
+        state           => "State"
+        zipcode         => "Zip code"
+        country         => "Country"
+        email           => "Email"
+        phone           => "Primary Phone"
+        mobile          => "Primary Mobile Phone"
+        fax             => "Fax"
+        emailpro        => "Secondary email"
+        phonepro        => "Secondary phone"
+        B_streetnumber  => "Alternate address - street number"
+        B_streettype    => "Alternate address - street type"
+        B_address       => "Alternate address"
+        B_address2      => "Alternate address 2"
+        B_city          => "Alternate address - city"
+        B_state         => "Alternate address - state"
+        B_zipcode       => "Alternate address - zip code"
+        B_email         => "Alternate address - email"
+        B_phone         => "Alertnate address - phone"
+        dateofbirth     => "Date of birth"
+        contactname     => "Contact - last name"
+        contactfirstname=> "Contact - first name"
+        contacttitle    => "Contact - title"
+        relationship    => "Contact - relationship"
+        ethnicity       => "Ethnicity"
+        ethnotes        => "Ethnicity notes"
+        sex             => "Sex"
+        altcontactfirstname => "Alternate contact - first name"
+        altcontactsurname   => "Alternate contact - surname"
+        altcontactaddress1  => "Alternate contact - address"
+        altcontactaddress2  => "Alternate contact - address 2"
+        altcontactaddress3  => "Alternate contact - city"
+        altcontactstate     => "Alternate contact - state"
+        altcontactzipcode   => "Alternate contact - zip code"
+        altcontactcounty    => "Alternate contact - county"
+        altcontactphone     => "Alternate contact - phone"
+        smsalertnumber      => "SMS alert number"
+    }
+%]
+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; Patrons &rsaquo; Modifications</div>
+
+<div id="doc2" class="yui-t7">
+
+   <div id="bd">
+        <div id="yui-main">
+            <div class="yui-b">
+                <div class="yui-g">
+                    [% IF PendingModifications %]
+                        <form method="post" action="members-update-do.pl">
+
+                            <table>
+                                <thead>
+                                    <tr>
+                                        <th colspan="3">Action</th>
+                                        <th rowspan="2">Patron</th>
+                                        <th rowspan="2">Changes</th>
+                                    </tr>
+
+                                    <tr>
+                                        <th>Approve</th>
+                                        <th>Deny</th>
+                                        <th>Ignore</th>
+                                    </tr>
+                                </thead>
+
+                                <tbody>
+                                    [% FOREACH pm IN PendingModifications %]
+                                        [% SET borrowernumber = pm.borrowernumber %]
+                                        <tr>
+                                            <td>
+                                                <input type="radio" name="modify_[% pm.borrowernumber %]" value="approve" />
+                                            </td>
+                                            <td>
+                                                <input type="radio" name="modify_[% pm.borrowernumber %]" value="deny" />
+                                            </td>
+                                            <td>
+                                                <input type="radio" name="modify_[% pm.borrowernumber %]" value="ignore" checked="checked"/>
+                                            </td>
+
+                                            <td>
+                                                [% borrowers.$borrowernumber.firstname %] [% borrowers.$borrowernumber.surname %]
+                                            </td>
+
+                                            <td>
+                                                <table>
+                                                    <tr>
+                                                        <th>Field</th>
+                                                        <th>From</th>
+                                                        <th>To</th>
+                                                    </tr>
+
+
+                                                    [% FOREACH key IN pm.keys %]
+                                                        [% IF field_display_names.$key %]
+                                                            [% IF ( ( pm.$key OR borrowers.$borrowernumber.$key ) && ( pm.$key != borrowers.$borrowernumber.$key ) ) %]
+                                                                <tr>
+                                                                    <td>[% field_display_names.$key %]</td>
+                                                                    <td>[% borrowers.$borrowernumber.$key %]</td>
+                                                                    <td>[% pm.$key %]</td>
+                                                                </tr>
+                                                            [% END %]
+                                                        [% END %]
+                                                    [% END %]
+                                                </table>
+                                            </td>
+                                        </tr>
+                                    [% END %]
+                                </tbody>
+                            </table>
+
+                            <p><input type="submit" /></p>
+
+                        </form>
+                    [% ELSE %]
+                        <p>There are no pending patron modifications.</p>
+                    [% END %]
+                </div>
+            </div>
+        </div>
+    </div>
+[% INCLUDE 'intranet-bottom.inc' %]
index 295eb5b..3df0221 100644 (file)
@@ -1,7 +1,7 @@
 [% IF ( opaccredits ) %]
        <div class="ft">
-        [% opaccredits %]
-    </div>
+            [% opaccredits %]
+        </div>
 [% END %]
 </div>
 
index 352d6b3..5a07d95 100644 (file)
@@ -5,7 +5,7 @@
   [% IF ( OPACFinesTab ) %]
   [% IF ( accountview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/opac-account.pl">my fines</a></li>
   [% END %]
-  [% IF ( userupdateview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/opac-userupdate.pl">my personal details</a></li>
+  [% IF ( userupdateview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/opac-memberentry.pl">my personal details</a></li>
   [% IF ( TagsEnabled ) %]
     [% IF ( tagsview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/opac-tags.pl?mine=1">my tags</a></li>
   [% END %]
index a73c8bb..6a6e1ee 100644 (file)
@@ -84,8 +84,10 @@ please choose against which one you would like to authenticate: </p>
 </ol></fieldset>
 
 <input type="submit" value="Log In" class="submit" />
-<div id="nologininstructions">  <h5>Don't have a password yet?</h5><p> If you don't have a password yet, stop by the circulation desk the next time you're in the library. We'll happily set one up for you.</p>
-<h5>Don't have a library card?</h5><p> If you don't have a library card, stop by your local library to sign up.  </p></div>
+<div id="nologininstructions">
+    <h5>Don't have a password yet?</h5><p> If you don't have a password yet, stop by the circulation desk the next time you're in the library. We'll happily set one up for you.</p>
+    <h5>Don't have a library card?</h5><p> If you don't have a library card, stop by your local library to sign up[% IF PatronSelfRegistration && PatronSelfRegistrationDefaultCategory %] or  <a href="/cgi-bin/koha/opac-memberentry.pl">register here</a>[% END %].</p>
+</div>
 </form>
 
 
index cc67ff2..1ae7bf5 100644 (file)
@@ -56,6 +56,8 @@
                <li><label for="password">Password:</label><input type="password" id="password" size="10" name="password" /></li>
                </ol>    <fieldset class="action">
         <input type="submit" value="Log In" class="submit" />
+        [% IF PatronSelfRegistration && PatronSelfRegistrationDefaultCategory %]<div>Don't have an account? <a href="/cgi-bin/koha/opac-memberentry.pl">Register here.</a></div>[% END %]
+
         </fieldset></fieldset>
        </form>
        </div>
diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-memberentry-update-submitted.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-memberentry-update-submitted.tt
new file mode 100644 (file)
index 0000000..9183824
--- /dev/null
@@ -0,0 +1,29 @@
+[% INCLUDE 'doc-head-open.inc' %]
+[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog
+[% INCLUDE 'doc-head-close.inc' %]
+</head>
+<body id="opac-main">
+[% IF ( OpacNav ) %]<div id="doc3" class="yui-t1">[% ELSE %]<div id="doc3" class="yui-t7">[% END %]
+   <div id="bd">
+[% INCLUDE 'masthead.inc' %]
+
+<div id="yui-main">
+    <div class="yui-b">
+        <div id="loggedin" class="yui-ge">
+            <div class="yui-u first">
+
+                <p>Your updates have been submitted. A librarian will now review you updates before applying them.</p>
+
+            </div>
+        </div>
+    </div>
+</div>
+
+[% IF ( OpacNav ) %]<div class="yui-b">
+    <div id="opacnav" class="container">
+        [% INCLUDE 'navigation.inc' %]
+    </div>
+[% END %]
+
+</div>
+[% INCLUDE 'opac-bottom.inc' %]
diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-memberentry.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-memberentry.tt
new file mode 100644 (file)
index 0000000..ac2cb02
--- /dev/null
@@ -0,0 +1,736 @@
+[% USE KohaDates %]
+[% SET userupdateview = 1 %]
+
+    [% INCLUDE 'doc-head-open.inc' %]
+        [% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog &rsaquo; Your fines and charges
+    [% INCLUDE 'doc-head-close.inc' %]
+
+    <script type="text/javascript">
+        $(document).ready(function() {
+            [% IF action == 'edit' && !OPACPatronDetails %]
+                $("#memberentry-form :input").attr('readonly', true);
+                $("#borrower_branchcode").attr('disabled',true);
+                $("#borrower_title").attr('disabled',true);
+                $('#memberentry-form :radio').attr('disabled',true);
+                $('span.required').remove();
+                $('label.required').removeClass('required');
+            [% ELSE %]
+                $( "#borrower_dateofbirth" ).datepicker({ yearRange: "c-120:c" });
+            [% END %]
+        });
+    </script>
+</head>
+
+<body id="opac-account">
+    <div id="doc3" class="yui-t1">
+        <div id="bd">
+            [% INCLUDE 'masthead.inc' %]
+
+            <div id="yui-main">
+                <div class="yui-b">
+                    <div class="yui-g">
+                        <div id="useraccount" class="container">
+                            [% UNLESS OPACPatronDetails %]
+                                <div>To make changes to your record please contact the library.</div>
+                            [% END %]
+
+                            [% IF empty_mandatory_fields %]
+                                <div class="dialog alert">You have not filled out all required fields. Please fill in all missing fields and resubmit.</div>
+                            [% END %]
+
+                            [% IF failed_captcha %]
+                                <div class="dialog alert">You typed in the wrong characters in the box before submitting. Please try again.</div>
+                            [% END %]
+
+                            <form method="post" id="memberentry-form">
+
+                                [% UNLESS
+                                    hidden.defined('branchcode')
+                                %]
+
+                                <fieldset class="rows" id="memberentry_library">
+
+                                    <legend id="library_legend">Library</legend>
+                                        <ol>
+                                            [% UNLESS hidden.defined('branchcode') %]
+                                                <li>
+                                                    [% IF mandatory.defined('branchcode') %]
+                                                        <label for="borrower_branchcode" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_branchcode">
+                                                    [% END %]
+                                                    Home Library:</label>
+
+                                                    <select id="borrower_branchcode" name="borrower_branchcode">
+                                                        [% FOREACH b IN branches %]
+                                                            [% IF b.value == borrower.branchcode %]
+                                                                <option value="[% b.value %]" selected="selected">[% b.branchname %]</option>
+                                                            [% ELSE %]
+                                                                <option value="[% b.value %]">[% b.branchname %]</option>
+                                                            [% END %]
+                                                        [% END %]
+                                                    </select>
+                                                </li>
+                                            [% END %]
+                                        </ol>
+                                    </fieldset>
+                                [% END %]
+
+                                [% UNLESS
+                                    hidden.defined('title') && hidden.defined('surname') && hidden.defined('firstname') &&
+                                    hidden.defined('dateofbirth') && hidden.defined('initials') && hidden.defined('othernames') &&
+                                    hidden.defined('sex')
+                                %]
+                                    <fieldset class="rows" id="memberentry_identity">
+                                        <legend id="identity_legend">Identity</legend>
+
+                                        <ol>
+                                            [% UNLESS hidden.defined('title') %]
+                                                <li>
+                                                    [% IF mandatory.defined('title') %]
+                                                        <label for="borrower_title" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_title">
+                                                    [% END %]
+                                                    Salutation:</label>
+
+                                                    <select id="borrower_title" name="borrower_title">
+                                                        <option value="">&nbsp;</option>
+                                                        [% FOREACH mt IN member_titles %]
+                                                            [% IF mt == borrower.title %]
+                                                                <option value="[% mt %]" selected="selected">[% mt %]</option>
+                                                            [% ELSE %]
+                                                                <option value="[% mt %]">[% mt %]</option>
+                                                            [% END %]
+                                                        [% END %]
+                                                    </select>
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('surname') %]
+                                                <li>
+                                                    [% IF mandatory.defined('surname') %]
+                                                        <label for="borrower_surname" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_surname">
+                                                    [% END %]
+                                                    Surname:</label>
+
+                                                    <input type="text" id="borrower_surname" name="borrower_surname" value="[% borrower.surname %]" />
+                                                    [% IF mandatory.defined('surname') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('firstname') %]
+                                                <li>
+                                                    [% IF mandatory.defined('firstname') %]
+                                                        <label for="borrower_firstname" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_firstname">
+                                                    [% END %]
+                                                    First name:</label>
+
+                                                    <input type="text" id="borrower_firstname" name="borrower_firstname" value="[% borrower.firstname %]" />
+                                                    [% IF mandatory.defined('firstname') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('dateofbirth') %]
+                                                <li>
+                                                    [% IF mandatory.defined('dateofbirth') %]
+                                                        <label for="borrower_dateofbirth" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_dateofbirth">
+                                                    [% END %]
+                                                    Date of birth:</label>
+
+                                                    <input type="text" id="borrower_dateofbirth" name="borrower_dateofbirth" value="[% borrower.dateofbirth | $KohaDates %]" size="10" />
+
+                                                    [% UNLESS action == 'edit' && !OPACPatronDetails %]
+                                                        <a href="#" style="font-size:85%;text-decoration:none;" onclick="document.getElementById('borrower_dateofbirth').value='';return false;">Clear date</a><p></p>
+                                                    [% END %]
+
+                                                    [% IF mandatory.defined('dateofbirth') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('initials') %]
+                                                <li>
+                                                    [% IF mandatory.defined('initials') %]
+                                                        <label for="borrower_initials" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_initials">
+                                                    [% END %]
+                                                    Initials:</label>
+
+                                                    <input type="text" id="borrower_initials" name="borrower_initials" value="[% borrower.initials %]" />
+                                                    [% IF mandatory.defined('initials') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('othernames') %]
+                                                <li>
+                                                    [% IF mandatory.defined('othernames') %]
+                                                        <label for="borrower_othernames" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_othernames">
+                                                    [% END %]
+                                                    Other names:</label>
+
+                                                    <input type="text" id="borrower_othernames" name="borrower_othernames" value="[% borrower.othernames %]" />
+                                                    [% IF mandatory.defined('othernames') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('sex') %]
+                                                <li class="radio">
+                                                    <label for="sex-female">Female:</label>
+                                                    [% IF borrower.sex == 'F' %]
+                                                        <input type="radio" name="borrower_sex" id="sex-female" value="F" checked="checked" />
+                                                    [% ELSE %]
+                                                        <input type="radio" name="borrower_sex" id="sex-female" value="F" />
+                                                    [% END %]
+
+                                                    <label for="sex-male">Male:</label>
+                                                    [% IF borrower.sex == 'M' %]
+                                                        <input type="radio" name="borrower_sex" id="sex-male" value="M" checked="checked" />
+                                                    [% ELSE %]
+                                                        <input type="radio" name="borrower_sex" id="sex-male" value="M" />
+                                                    [% END %]
+
+                                                    <label for="sex-none">N/A:</label>
+                                                    [% IF borrower.sex == '' %]
+                                                        <input type="radio" name="borrower_sex" id="sex-none" value="" checked="checked" />
+                                                    [% ELSE %]
+                                                        <input type="radio" name="borrower_sex" id="sex-none" value="" />
+                                                    [% END %]
+
+                                                    [% IF mandatory.defined('sex') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+                                        </ol>
+                                    </fieldset>
+                                [% END %]
+
+                                [% UNLESS
+                                    hidden.defined('streetnumber') && hidden.defined('address') && hidden.defined('address2') &&
+                                    hidden.defined('city') && hidden.defined('state') && hidden.defined('zipcode') &&
+                                    hidden.defined('country')
+                                %]
+                                    <fieldset class="rows" id="memberentry_mainaddress">
+                                        <legend id="mainaddress_legend">Main address</legend>
+
+                                        <ol>
+                                            [% UNLESS hidden.defined('streetnumber') %]
+                                                <li>
+                                                    [% IF mandatory.defined('streetnumber') %]
+                                                        <label for="borrower_streetnumber" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_streetnumber">
+                                                    [% END %]
+                                                    Street number:</label>
+
+                                                    <input type="text" id="borrower_streetnumber" name="borrower_streetnumber" value="[% borrower.streetnumber %]" />
+                                                    [% IF mandatory.defined('streetnumber') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('address') %]
+                                                <li>
+                                                    [% IF mandatory.defined('address') %]
+                                                        <label for="borrower_address" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_address">
+                                                    [% END %]
+                                                    Address:</label>
+
+                                                    <input type="text" id="borrower_address" name="borrower_address" value="[% borrower.address %]" />
+                                                    [% IF mandatory.defined('address') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('address2') %]
+                                                <li>
+                                                    [% IF mandatory.defined('address2') %]
+                                                        <label for="borrower_address2" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_address2">
+                                                    [% END %]
+                                                    Address 2:</label>
+
+                                                    <input type="text" id="borrower_address2" name="borrower_address2" value="[% borrower.address2 %]" />
+                                                    [% IF mandatory.defined('address2') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('city') %]
+                                                <li>
+                                                    [% IF mandatory.defined('city') %]
+                                                        <label for="borrower_city" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_city">
+                                                    [% END %]
+                                                    City:</label>
+
+                                                    <input type="text" id="borrower_city" name="borrower_city" value="[% borrower.city %]" />
+                                                    [% IF mandatory.defined('city') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('state') %]
+                                                <li>
+                                                    [% IF mandatory.defined('state') %]
+                                                        <label for="borrower_state" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_state">
+                                                    [% END %]
+                                                    State:</label>
+
+                                                    <input type="text" id="borrower_state" name="borrower_state" value="[% borrower.state %]" />
+                                                    [% IF mandatory.defined('state') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('zipcode') %]
+                                                <li>
+                                                    [% IF mandatory.defined('zipcode') %]
+                                                        <label for="borrower_zipcode" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_zipcode">
+                                                    [% END %]
+                                                    Zip/Postal code:</label>
+
+                                                    <input type="text" id="borrower_zipcode" name="borrower_zipcode" value="[% borrower.zipcode %]" />
+                                                    [% IF mandatory.defined('zipcode') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('country') %]
+                                                <li>
+                                                    [% IF mandatory.defined('country') %]
+                                                        <label for="borrower_country" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_country">
+                                                    [% END %]
+                                                    Country:</label>
+
+                                                    <input type="text" id="borrower_country" name="borrower_country" value="[% borrower.country %]" />
+                                                    [% IF mandatory.defined('country') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                        </ol>
+                                    </fieldset>
+                                [% END %]
+
+                                [% UNLESS
+                                    hidden.defined('phone') && hidden.defined('phonepro') && hidden.defined('mobile') &&
+                                    hidden.defined('email') && hidden.defined('emailpro') && hidden.defined('fax')
+                                %]
+                                    <fieldset class="rows" id="memberentry_contact">
+                                        <legend id="contact_legend">Contact information</legend>
+
+                                        <ol>
+                                            [% UNLESS hidden.defined('phone') %]
+                                                <li>
+                                                    [% IF mandatory.defined('phone') %]
+                                                        <label for="borrower_phone" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_phone">
+                                                    [% END %]
+                                                    Primary phone:</label>
+
+                                                    <input type="text" id="borrower_phone" name="borrower_phone" value="[% borrower.phone %]" />
+                                                    [% IF mandatory.defined('phone') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('phonepro') %]
+                                                <li>
+                                                    [% IF mandatory.defined('phonepro') %]
+                                                        <label for="borrower_phonepro" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_phonepro">
+                                                    [% END %]
+                                                    Secondary phone:</label>
+
+                                                    <input type="text" id="borrower_phonepro" name="borrower_phonepro" value="[% borrower.phonepro %]" />
+                                                    [% IF mandatory.defined('phonepro') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('mobile') %]
+                                                <li>
+                                                    [% IF mandatory.defined('mobile') %]
+                                                        <label for="borrower_mobile" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_mobile">
+                                                    [% END %]
+                                                    Mobile phone:</label>
+
+                                                    <input type="text" id="borrower_mobile" name="borrower_mobile" value="[% borrower.mobile %]" />
+                                                    [% IF mandatory.defined('mobile') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('email') %]
+                                                <li>
+                                                    [% IF mandatory.defined('email') %]
+                                                        <label for="borrower_email" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_email">
+                                                    [% END %]
+                                                    Primary email:</label>
+
+                                                    <input type="text" id="borrower_email" name="borrower_email" value="[% borrower.email %]" />
+                                                    [% IF mandatory.defined('email') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('emailpro') %]
+                                                <li>
+                                                    [% IF mandatory.defined('emailpro') %]
+                                                        <label for="borrower_emailpro" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_emailpro">
+                                                    [% END %]
+                                                    Secondary email:</label>
+
+                                                    <input type="text" id="borrower_emailpro" name="borrower_emailpro" value="[% borrower.emailpro %]" />
+                                                    [% IF mandatory.defined('emailpro') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('fax') %]
+                                                <li>
+                                                    [% IF mandatory.defined('fax') %]
+                                                        <label for="borrower_fax" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_fax">
+                                                    [% END %]
+                                                    Fax:</label>
+
+                                                    <input type="text" id="borrower_fax" name="borrower_fax" value="[% borrower.fax %]" />
+                                                    [% IF mandatory.defined('fax') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+                                        </ol>
+                                    </fieldset>
+                                [% END %]
+
+                                [% UNLESS
+                                    hidden.defined('B_address') && hidden.defined('B_address2') && hidden.defined('B_city') &&
+                                    hidden.defined('B_state') && hidden.defined('B_zipcode') && hidden.defined('B_county') &&
+                                    hidden.defined('B_phone') && hidden.defined('B_email') && hidden.defined('contactnote')
+                                %]
+                                    <fieldset class="rows" id="memberentry_alternateaddress">
+                                        <legend id="alternateaddress_legend">Alternate address</legend>
+
+                                        <ol>
+                                            [% UNLESS hidden.defined('B_address') %]
+                                                <li>
+                                                    [% IF mandatory.defined('B_address') %]
+                                                        <label for="borrower_B_address" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_B_address">
+                                                    [% END %]
+                                                    Address:</label>
+
+                                                    <input type="text" id="borrower_B_address" name="borrower_B_address" value="[% borrower.B_address %]" />
+                                                    [% IF mandatory.defined('B_address') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('B_address2') %]
+                                                <li>
+                                                    [% IF mandatory.defined('B_address2') %]
+                                                        <label for="borrower_B_address2" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_B_address2">
+                                                    [% END %]
+                                                    Address 2:</label>
+
+                                                    <input type="text" id="borrower_B_address2" name="borrower_B_address2" value="[% borrower.B_address2 %]" />
+                                                    [% IF mandatory.defined('B_address2') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('B_city') %]
+                                                <li>
+                                                    [% IF mandatory.defined('B_city') %]
+                                                        <label for="borrower_B_city" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_B_city">
+                                                    [% END %]
+                                                    City:</label>
+
+                                                    <input type="text" id="borrower_B_city" name="borrower_B_city" value="[% borrower.B_city %]" />
+                                                    [% IF mandatory.defined('B_city') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('B_state') %]
+                                                <li>
+                                                    [% IF mandatory.defined('B_state') %]
+                                                        <label for="borrower_B_state" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_B_state">
+                                                    [% END %]
+                                                    State:</label>
+
+                                                    <input type="text" id="borrower_B_state" name="borrower_B_state" value="[% borrower.B_state %]" />
+                                                    [% IF mandatory.defined('B_state') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('B_zipcode') %]
+                                                <li>
+                                                    [% IF mandatory.defined('B_zipcode') %]
+                                                        <label for="borrower_B_zipcode" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_B_zipcode">
+                                                    [% END %]
+                                                    Zip/Postal code:</label>
+
+                                                    <input type="text" id="borrower_B_zipcode" name="borrower_B_zipcode" value="[% borrower.B_zipcode %]" />
+                                                    [% IF mandatory.defined('B_zipcode') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('B_country') %]
+                                                <li>
+                                                    [% IF mandatory.defined('B_country') %]
+                                                        <label for="borrower_B_country" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_B_country">
+                                                    [% END %]
+                                                    Country:</label>
+
+                                                    <input type="text" id="borrower_B_country" name="borrower_B_country" value="[% borrower.B_country %]" />
+                                                    [% IF mandatory.defined('B_country') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('B_phone') %]
+                                                <li>
+                                                    [% IF mandatory.defined('B_phone') %]
+                                                        <label for="borrower_B_phone" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_B_phone">
+                                                    [% END %]
+                                                    Phone:</label>
+
+                                                    <input type="text" id="borrower_B_phone" name="borrower_B_phone" value="[% borrower.B_phone %]" />
+                                                    [% IF mandatory.defined('B_phone') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('B_email') %]
+                                                <li>
+                                                    [% IF mandatory.defined('B_email') %]
+                                                        <label for="borrower_B_email" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_B_email">
+                                                    [% END %]
+                                                    Email:</label>
+
+                                                    <input type="text" id="borrower_B_email" name="borrower_B_email" value="[% borrower.B_email %]" />
+                                                    [% IF mandatory.defined('B_email') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('contactnote') %]
+                                                <li>
+                                                    [% IF mandatory.defined('contactnote') %]
+                                                        <label for="borrower_contactnote" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_contactnote">
+                                                    [% END %]
+                                                    Contact Note:</label>
+
+                                                    <textarea id="borrower_contactnote" name="borrower_contactnote" cols="40" rows="2">[% borrower.contactnote %]</textarea>
+                                                    [% IF mandatory.defined('contactnote') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                        </ol>
+                                    </fieldset>
+                                [% END %]
+
+                                [% UNLESS
+                                    hidden.defined('altcontactsurname') && hidden.defined('altcontactfirstname') && hidden.defined('altcontactaddress1') &&
+                                    hidden.defined('altcontactaddress2') && hidden.defined('altcontactaddress3') && hidden.defined('altcontactstate') &&
+                                    hidden.defined('altcontactzipcode') && hidden.defined('altcontactcountry') && hidden.defined('altcontactphone')
+                                %]
+                                    <fieldset class="rows" id="memberentry_alternatecontact">
+                                        <legend id="alternatecontact_legend">Alternate contact</legend>
+
+                                        <ol>
+                                            [% UNLESS hidden.defined('altcontactsurname') %]
+                                                <li>
+                                                    [% IF mandatory.defined('altcontactsurname') %]
+                                                        <label for="borrower_altcontactsurname" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_altcontactsurname">
+                                                    [% END %]
+                                                    Surname:</label>
+
+                                                    <input type="text" id="borrower_altcontactsurname" name="borrower_altcontactsurname" value="[% borrower.altcontactsurname %]" />
+                                                    [% IF mandatory.defined('altcontactsurname') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('altcontactfirstname') %]
+                                                <li>
+                                                    [% IF mandatory.defined('altcontactfirstname') %]
+                                                        <label for="borrower_altcontactfirstname" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_altcontactfirstname">
+                                                    [% END %]
+                                                    First name:</label>
+
+                                                    <input type="text" id="borrower_altcontactfirstname" name="borrower_altcontactfirstname" value="[% borrower.altcontactfirstname %]" />
+                                                    [% IF mandatory.defined('altcontactfirstname') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('altcontactaddress1') %]
+                                                <li>
+                                                    [% IF mandatory.defined('altcontactaddress1') %]
+                                                        <label for="borrower_altcontactaddress1" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_altcontactaddress1">
+                                                    [% END %]
+                                                    Address:</label>
+
+                                                    <input type="text" id="borrower_altcontactaddress1" name="borrower_altcontactaddress1" value="[% borrower.altcontactaddress1 %]" />
+                                                    [% IF mandatory.defined('altcontactaddress1') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('altcontactaddress2') %]
+                                                <li>
+                                                    [% IF mandatory.defined('altcontactaddress2') %]
+                                                        <label for="borrower_altcontactaddress2" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_altcontactaddress2">
+                                                    [% END %]
+                                                    Address 2:</label>
+
+                                                    <input type="text" id="borrower_altcontactaddress2" name="borrower_altcontactaddress2" value="[% borrower.altcontactaddress2 %]" />
+                                                    [% IF mandatory.defined('altcontactaddress2') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('altcontactaddress3') %]
+                                                <li>
+                                                    [% IF mandatory.defined('altcontactaddress3') %]
+                                                        <label for="borrower_altcontactaddress3" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_altcontactaddress3">
+                                                    [% END %]
+                                                    City:</label>
+
+                                                    <input type="text" id="borrower_altcontactaddress3" name="borrower_altcontactaddress3" value="[% borrower.altcontactaddress3 %]" />
+                                                    [% IF mandatory.defined('altcontactaddress3') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('altcontactstate') %]
+                                                <li>
+                                                    [% IF mandatory.defined('altcontactstate') %]
+                                                        <label for="borrower_altcontactstate" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_altcontactstate">
+                                                    [% END %]
+                                                    State:</label>
+
+                                                    <input type="text" id="borrower_altcontactstate" name="borrower_altcontactstate" value="[% borrower.altcontactstate %]" />
+                                                    [% IF mandatory.defined('altcontactstate') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('altcontactzipcode') %]
+                                                <li>
+                                                    [% IF mandatory.defined('altcontactzipcode') %]
+                                                        <label for="borrower_altcontactzipcode" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_altcontactzipcode">
+                                                    [% END %]
+                                                    Zip/Postal code:</label>
+
+                                                    <input type="text" id="borrower_altcontactzipcode" name="borrower_altcontactzipcode" value="[% borrower.altcontactzipcode %]" />
+                                                    [% IF mandatory.defined('altcontactzipcode') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('altcontactcountry') %]
+                                                <li>
+                                                    [% IF mandatory.defined('altcontactcountry') %]
+                                                        <label for="borrower_altcontactcountry" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_altcontactcountry">
+                                                    [% END %]
+                                                    Country:</label>
+
+                                                    <input type="text" id="borrower_altcontactcountry" name="borrower_altcontactcountry" value="[% borrower.altcontactcountry %]" />
+                                                    [% IF mandatory.defined('altcontactcountry') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+
+                                            [% UNLESS hidden.defined('altcontactphone') %]
+                                                <li>
+                                                    [% IF mandatory.defined('altcontactphone') %]
+                                                        <label for="borrower_altcontactphone" class="required">
+                                                    [% ELSE %]
+                                                        <label for="borrower_altcontactphone">
+                                                    [% END %]
+                                                    Phone:</label>
+
+                                                    <input type="text" id="borrower_altcontactphone" name="borrower_altcontactphone" value="[% borrower.altcontactphone %]" />
+                                                    [% IF mandatory.defined('altcontactphone') %]<span class="required">Required</span>[% END %]
+                                                </li>
+                                            [% END %]
+                                        </ol>
+                                    </fieldset>
+                                [% END %]
+
+                                [% UNLESS action == 'edit' %]
+                                    <fieldset class="rows" id="memberentry_captcha">
+                                        <ol>
+                                            <li>
+                                                <label for="borrower_altcontactphone" class="required">Verification</label>
+
+                                                <input type="text" name="captcha" id="captcha" />
+                                                <input type="hidden" name="captcha_digest" value="[% captcha_digest %]" />
+
+                                                <span class="required">Please type this following characters into the preceding box: <strong>[% captcha %]</strong></span>
+                                            </li>
+                                        </ol>
+                                    </fieldset>
+                                [% END %]
+
+                                [% IF action == 'edit' %]
+                                    [% IF OPACPatronDetails %]
+                                        <input type="hidden" name="action" value="update" />
+                                        <input type="submit" value="Submit Update Request" />
+                                    [% END %]
+                                [% ELSE %]
+                                    <input type="hidden" name="action" value="create" />
+                                    <input type="submit" value="Submit" />
+                                [% END %]
+
+                            </form>
+
+                        </div><!--/div id="useraccount" -->
+                    </div>
+                </div>
+            </div>
+
+            <div class="yui-b">
+                <div id="leftmenus" class="container">
+                    [% INCLUDE 'navigation.inc' IsPatronPage=1 %]
+                </div>
+            </div>
+        </div>
+[% INCLUDE 'opac-bottom.inc' %]
diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-registration-confirmation.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-registration-confirmation.tt
new file mode 100644 (file)
index 0000000..968faa0
--- /dev/null
@@ -0,0 +1,70 @@
+[% INCLUDE 'doc-head-open.inc' %]
+[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog
+[% INCLUDE 'doc-head-close.inc' %]
+</head>
+<body id="opac-main">
+[% IF ( OpacNav ) %]<div id="doc3" class="yui-t1">[% ELSE %]<div id="doc3" class="yui-t7">[% END %]
+   <div id="bd">
+[% INCLUDE 'masthead.inc' %]
+
+<div id="yui-main">
+    <div class="yui-b">
+        <div id="loggedin" class="yui-ge">
+            <div class="yui-u first">
+                <h1>Registration Complete!</h1>
+
+                <p>You have successfully registered your new account. To log in, use the following credentials:</p>
+
+                <p>
+                    Username: [% borrower.userid %]
+                    <br/>
+                    Password: [% password_cleartext %]
+                </p>
+
+                <p>For your convenience, the login box on this page has been pre-filled with this data. Please log in[% IF OpacPasswordChange %] and change your password[% END %].</p>
+
+                <div id="PatronSelfRegistrationAdditionalInstructions">[% PatronSelfRegistrationAdditionalInstructions %]</div>
+            </div>
+
+            [% IF ( opacuserlogin || OpacNavRight ) %]
+                <div class="yui-u">
+                    [% IF ( opacuserlogin ) %]
+                        [% UNLESS ( loggedinusername ) %]
+                            [% UNLESS ( casAuthentication ) %]
+                                <div id="login" class="container clearfix">
+                                    <form action="/cgi-bin/koha/opac-user.pl" method="post" name="auth" id="auth">
+                                        <input type="hidden" name="koha_login_context" value="opac" />
+
+                                        <fieldset class="brief">
+                                            <legend>Log in to your account:</legend>
+
+                                            <ol>
+                                                <li><label for="userid">Login:</label><input type="text" id="userid" size="10" name="userid" value="[% borrower.userid %]" /></li>
+                                                <li><label for="password">Password:</label><input type="password" id="password" size="10" name="password" value="[% password_cleartext %]" /></li>
+                                            </ol>
+
+                                            <fieldset class="action">
+                                                <input type="submit" value="Log In" class="submit" />
+                                            </fieldset>
+                                        </fieldset>
+                                    </form>
+                                </div>
+                            [% END %]
+                        [% END %]
+                    [% END %]
+
+                    [% IF ( OpacNavRight ) %]<div id="opacrightsidebar" class="container">[% OpacNavRight %]</div>[% END %]
+                </div>
+            [% END %]
+        </div>
+    </div>
+</div>
+
+[% IF ( OpacNav ) %]<div class="yui-b">
+    <div id="opacnav" class="container">
+        [% INCLUDE 'navigation.inc' %]
+    </div>
+[% END %]
+
+</div>
+[% INCLUDE 'opac-bottom.inc' %]
diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-registration-email-sent.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-registration-email-sent.tt
new file mode 100644 (file)
index 0000000..bdad739
--- /dev/null
@@ -0,0 +1,31 @@
+[% INCLUDE 'doc-head-open.inc' %]
+[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog
+[% INCLUDE 'doc-head-close.inc' %]
+</head>
+<body id="opac-main">
+[% IF ( OpacNav ) %]<div id="doc3" class="yui-t1">[% ELSE %]<div id="doc3" class="yui-t7">[% END %]
+   <div id="bd">
+[% INCLUDE 'masthead.inc' %]
+
+<div id="yui-main">
+    <div class="yui-b">
+        <div id="loggedin" class="yui-ge">
+            <div class="yui-u first">
+                <h1>Please Confirm Registration</h1>
+
+                <p>A confirmation email has been sent to the email address <strong>[% email %]</strong>.</p>
+
+                <p>Your account will not be activated until you follow the link provided in the confirmation email.</p>
+            </div>
+        </div>
+    </div>
+</div>
+
+[% IF ( OpacNav ) %]<div class="yui-b">
+    <div id="opacnav" class="container">
+        [% INCLUDE 'navigation.inc' %]
+    </div>
+[% END %]
+
+</div>
+[% INCLUDE 'opac-bottom.inc' %]
diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-registration-invalid.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-registration-invalid.tt
new file mode 100644 (file)
index 0000000..12dac1d
--- /dev/null
@@ -0,0 +1,30 @@
+[% INCLUDE 'doc-head-open.inc' %]
+[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog
+[% INCLUDE 'doc-head-close.inc' %]
+</head>
+<body id="opac-main">
+[% IF ( OpacNav ) %]<div id="doc3" class="yui-t1">[% ELSE %]<div id="doc3" class="yui-t7">[% END %]
+   <div id="bd">
+[% INCLUDE 'masthead.inc' %]
+
+<div id="yui-main">
+    <div class="yui-b">
+        <div id="loggedin" class="yui-ge">
+            <div class="yui-u first">
+                <h1>Registration invalid!</h1>
+
+                <p>There were problems processing your registration. Please contact your library for help.</p>
+
+            </div>
+        </div>
+    </div>
+</div>
+
+[% IF ( OpacNav ) %]<div class="yui-b">
+    <div id="opacnav" class="container">
+        [% INCLUDE 'navigation.inc' %]
+    </div>
+[% END %]
+
+</div>
+[% INCLUDE 'opac-bottom.inc' %]
index 78daf38..9085630 100755 (executable)
@@ -28,17 +28,17 @@ use C4::NewsChannels;
 use C4::Review qw/numberofreviews/;
 use C4::Suggestions qw/CountSuggestion/;
 use C4::Tags qw/get_count_by_tag_status/;
-my $query     = new CGI;
+use Koha::Borrower::Modifications;
 
-my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
+my $query = new CGI;
+
+my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user(
     {
         template_name   => "intranet-main.tmpl",
         query           => $query,
         type            => "intranet",
         authnotrequired => 0,
-        flagsrequired   => {
-            catalogue => 1,
-        },
+        flagsrequired   => { catalogue => 1, },
     }
 );
 
@@ -50,14 +50,23 @@ $template->param(
     koha_news_count => $koha_news_count
 );
 
-my $pendingcomments = numberofreviews(0);
-my $pendingtags = get_count_by_tag_status(0);
-my $pendingsuggestions       = CountSuggestion("ASKED");
+my $branch =
+  C4::Context->preference("IndependantBranches")
+  && !$flags->{'superlibrarian'}
+  ? C4::Context->userenv()->{'branch'}
+  : undef;
+
+my $pendingcomments    = numberofreviews(0);
+my $pendingtags        = get_count_by_tag_status(0);
+my $pendingsuggestions = CountSuggestion("ASKED");
+my $pending_borrower_modifications =
+  Koha::Borrower::Modifications->GetPendingModificationsCount( $branch );
 
 $template->param(
-    pendingcomments    => $pendingcomments,
-    pendingtags        => $pendingtags,
-    pendingsuggestions => $pendingsuggestions
+    pendingcomments                => $pendingcomments,
+    pendingtags                    => $pendingtags,
+    pendingsuggestions             => $pendingsuggestions,
+    pending_borrower_modifications => $pending_borrower_modifications,
 );
 
 #
diff --git a/members/members-update-do.pl b/members/members-update-do.pl
new file mode 100755 (executable)
index 0000000..e7b7b28
--- /dev/null
@@ -0,0 +1,64 @@
+#!/usr/bin/perl
+
+# Parts Copyright Biblibre 2010
+# 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 2 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use strict;
+use warnings;
+
+use CGI;
+use C4::Auth;
+use C4::Output;
+use C4::Context;
+use C4::Members;
+use C4::Branch;
+use C4::Category;
+use Koha::Borrower::Modifications;
+
+my $query = new CGI;
+
+my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
+    {
+        template_name   => "about.tmpl",
+        query           => $query,
+        type            => "intranet",
+        authnotrequired => 0,
+        flagsrequired   => { borrowers => 1 },
+        debug           => 1,
+    }
+);
+
+my @params = $query->param;
+
+foreach my $param (@params) {
+    if ( $param =~ "^modify_" ) {
+        my (undef, $borrowernumber) = split( /_/, $param );
+
+        my $action = $query->param($param);
+
+        if ( $action eq 'approve' ) {
+            Koha::Borrower::Modifications->ApproveModifications( $borrowernumber );
+        }
+        elsif ( $action eq 'deny' ) {
+            Koha::Borrower::Modifications->DenyModifications( $borrowernumber );
+        }
+        elsif ( $action eq 'ignore' ) {
+
+        }
+    }
+}
+
+print $query->redirect("/cgi-bin/koha/members/members-update.pl");
diff --git a/members/members-update.pl b/members/members-update.pl
new file mode 100755 (executable)
index 0000000..334d83b
--- /dev/null
@@ -0,0 +1,65 @@
+#!/usr/bin/perl
+
+# Parts Copyright Biblibre 2010
+# 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 2 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use strict;
+use warnings;
+
+use CGI;
+use C4::Auth;
+use C4::Output;
+use C4::Context;
+use C4::Members;
+use C4::Branch;
+use C4::Category;
+use Koha::Borrower::Modifications;
+
+my $query = new CGI;
+
+my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user(
+    {
+        template_name   => "members/members-update.tmpl",
+        query           => $query,
+        type            => "intranet",
+        authnotrequired => 0,
+        flagsrequired   => { borrowers => 1 },
+        debug           => 1,
+    }
+);
+
+my $branch =
+  C4::Context->preference("IndependantBranches")
+  && !$flags->{'superlibrarian'}
+  ? C4::Context->userenv()->{'branch'}
+  : undef;
+
+my $pending_modifications =
+  Koha::Borrower::Modifications->GetPendingModifications($branch);
+
+my $borrowers;
+foreach my $pm (@$pending_modifications) {
+    $borrowers->{ $pm->{'borrowernumber'} } =
+      GetMember( borrowernumber => $pm->{'borrowernumber'} );
+
+}
+
+$template->param(
+    PendingModifications => $pending_modifications,
+    borrowers            => $borrowers,
+);
+
+output_html_with_http_headers $query, $cookie, $template->output;
diff --git a/misc/cronjobs/delete_expired_opac_registrations.pl b/misc/cronjobs/delete_expired_opac_registrations.pl
new file mode 100755 (executable)
index 0000000..86f47c5
--- /dev/null
@@ -0,0 +1,80 @@
+#!/usr/bin/perl
+
+# Copyright 2009-2010 Kyle Hall
+#
+# 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 2 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use Modern::Perl;
+use Getopt::Long;
+
+BEGIN {
+
+    # find Koha's Perl modules
+    # test carefully before changing this
+    use FindBin;
+    eval { require "$FindBin::Bin/../kohalib.pl" };
+}
+
+use C4::Context;
+use C4::Members qw/ DelMember /;
+
+my $help;
+my $confirm;
+
+GetOptions(
+    'h|help'    => \$help,
+    'c|confirm' => \$confirm,
+);
+my $usage = << 'ENDUSAGE';
+
+This script remove confirmed OPAC based patron registrations
+that have not been changed from the patron category specified
+in the system preference PatronSelfRegistrationDefaultCategory
+within the required time period.
+
+This script has the following parameters :
+    -h --help:    This message
+
+    -c --confirm: Without this flag set, this script will do nothing.
+ENDUSAGE
+
+if ( $help || !$confirm ) {
+    print $usage;
+    exit;
+}
+
+## Delete accounts that haven't been upgraded from the 'temporary' category code'
+my $delay =
+  C4::Context->preference('PatronSelfRegistrationExpireTemporaryAccountsDelay');
+my $category_code =
+  C4::Context->preference('PatronSelfRegistrationDefaultCategory');
+
+my $query = "
+    SELECT borrowernumber
+    FROM borrowers
+    WHERE
+        categorycode = ?
+      AND
+        DATEDIFF( DATE( NOW() ), DATE(dateenrolled) ) = ? )
+";
+
+my $dbh = C4::Context->dbh;
+my $sth = $dbh->prepare($query);
+$sth->execute( $category_code, $delay );
+
+while ( my ($borrowernumber) = $sth->fetchrow_array() ) {
+    DelMember($borrowernumber);
+}
diff --git a/misc/cronjobs/delete_unverified_opac_registrations.pl b/misc/cronjobs/delete_unverified_opac_registrations.pl
new file mode 100755 (executable)
index 0000000..62816d5
--- /dev/null
@@ -0,0 +1,70 @@
+#!/usr/bin/perl
+
+# Copyright 2009-2010 Kyle Hall
+#
+# 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 2 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use Modern::Perl;
+use Getopt::Long;
+
+BEGIN {
+
+    # find Koha's Perl modules
+    # test carefully before changing this
+    use FindBin;
+    eval { require "$FindBin::Bin/../kohalib.pl" };
+}
+
+use C4::Context;
+use C4::Members qw/ DelMember /;
+
+my $help;
+my $confirm;
+my $hours = 24;
+
+GetOptions(
+    'h|help'    => \$help,
+    'c|confirm' => \$confirm,
+    't|time=i'  => \$hours,
+);
+my $usage = << 'ENDUSAGE';
+
+This script removes unconfirmed OPAC based patron registrations
+that have not been confirmed within the required time period.
+
+This script has the following parameters :
+    -h --help:    This message
+
+    -t --time:    The length in hours to wait before removing an unconfirmed registration.
+                  Defaults to 24 hours if not set.
+
+    -c --confirm: Without this flag set, this script will do nothing.
+ENDUSAGE
+
+if ( $help || !$confirm ) {
+    print $usage;
+    exit;
+}
+
+my $dbh = C4::Context->dbh;
+
+$dbh->do( "
+         DELETE FROM borrower_modifications
+         WHERE
+             borrowernumber = 0
+           AND
+             TIME_TO_SEC( TIMEDIFF( NOW(), timestamp )) / 3600 > ?
+", undef, $hours );
diff --git a/opac/opac-memberentry.pl b/opac/opac-memberentry.pl
new file mode 100755 (executable)
index 0000000..20ec9db
--- /dev/null
@@ -0,0 +1,303 @@
+#!/usr/bin/perl
+
+# 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 2 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use Modern::Perl;
+
+use CGI;
+use Digest::MD5 qw( md5_base64 md5_hex );
+use String::Random qw( random_string );
+
+use C4::Auth;
+use C4::Output;
+use C4::Members;
+use Koha::Borrower::Modifications;
+use C4::Branch qw(GetBranchesLoop);
+
+my $cgi = new CGI;
+my $dbh = C4::Context->dbh;
+
+my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
+    {
+        template_name   => "opac-memberentry.tmpl",
+        type            => "opac",
+        query           => $cgi,
+        authnotrequired => 1,
+    }
+);
+
+unless ( C4::Context->preference('PatronSelfRegistration') || $borrowernumber )
+{
+    print $cgi->redirect("/cgi-bin/koha/opac-main.pl");
+    exit;
+}
+
+my $action = $cgi->param('action') || q{};
+if ( $action eq q{} ) {
+    if ($borrowernumber) {
+        $action = 'edit';
+    }
+    else {
+        $action = 'new';
+    }
+}
+
+$template->param(
+    action            => $action,
+    hidden            => GetHiddenFields(),
+    mandatory         => GetMandatoryFields($action),
+    member_titles     => GetTitles(),
+    branches          => GetBranchesLoop(),
+    OPACPatronDetails => C4::Context->preference('OPACPatronDetails'),
+);
+
+if ( $action eq 'create' ) {
+
+    my %borrower = ParseCgiForBorrower($cgi);
+
+    %borrower = DelEmptyFields(%borrower);
+
+    my @empty_mandatory_fields = CheckMandatoryFields( \%borrower, $action );
+
+    if (@empty_mandatory_fields) {
+        $template->param(
+            empty_mandatory_fields => \@empty_mandatory_fields,
+            borrower               => \%borrower
+        );
+    }
+    elsif (
+        md5_base64( $cgi->param('captcha') ) ne $cgi->param('captcha_digest') )
+    {
+        $template->param(
+            failed_captcha => 1,
+            borrower       => \%borrower
+        );
+    }
+    else {
+        if (
+            C4::Context->boolean_preference(
+                'PatronSelfRegistrationVerifyByEmail')
+          )
+        {
+            ( $template, $borrowernumber, $cookie ) = get_template_and_user(
+                {
+                    template_name   => "opac-registration-email-sent.tmpl",
+                    type            => "opac",
+                    query           => $cgi,
+                    authnotrequired => 1,
+                }
+            );
+            $template->param( 'email' => $borrower{'email'} );
+
+            my $verification_token = md5_hex( \%borrower );
+            $borrower{'password'} = random_string("..........");
+
+            Koha::Borrower::Modifications->new(
+                verification_token => $verification_token )
+              ->AddModifications(%borrower);
+
+            #Send verification email
+            my $letter = C4::Letters::GetPreparedLetter(
+                module      => 'members',
+                letter_code => 'OPAC_REG_VERIFY',
+                tables      => {
+                    borrower_modifications =>
+                      [ $verification_token, $verification_token ],
+                },
+            );
+
+            C4::Letters::EnqueueLetter(
+                {
+                    letter                 => $letter,
+                    message_transport_type => 'email',
+                    to_address             => $borrower{'email'},
+                    from_address =>
+                      C4::Context->preference('KohaAdminEmailAddress'),
+                }
+            );
+        }
+        else {
+            ( $template, $borrowernumber, $cookie ) = get_template_and_user(
+                {
+                    template_name   => "opac-registration-confirmation.tmpl",
+                    type            => "opac",
+                    query           => $cgi,
+                    authnotrequired => 1,
+                }
+            );
+
+            $template->param( OpacPasswordChange =>
+                  C4::Context->preference('OpacPasswordChange') );
+
+            my ( $borrowernumber, $password ) = AddMember_Opac(%borrower);
+
+            $template->param( password_cleartext => $password );
+            $template->param(
+                borrower => GetMember( borrowernumber => $borrowernumber ) );
+            $template->param(
+                PatronSelfRegistrationAdditionalInstructions =>
+                  C4::Context->preference(
+                    'PatronSelfRegistrationAdditionalInstructions')
+            );
+        }
+    }
+}
+elsif ( $action eq 'update' ) {
+
+    my %borrower = ParseCgiForBorrower($cgi);
+
+    my %borrower_changes = DelEmptyFields(%borrower);
+    my @empty_mandatory_fields =
+      CheckMandatoryFields( \%borrower_changes, $action );
+
+    if (@empty_mandatory_fields) {
+        $template->param(
+            empty_mandatory_fields => \@empty_mandatory_fields,
+            borrower               => \%borrower
+        );
+
+        $template->param( action => 'edit' );
+    }
+    else {
+        ( $template, $borrowernumber, $cookie ) = get_template_and_user(
+            {
+                template_name   => "opac-memberentry-update-submitted.tmpl",
+                type            => "opac",
+                query           => $cgi,
+                authnotrequired => 1,
+            }
+        );
+
+        my %borrower_changes = DelUnchangedFields( $borrowernumber, %borrower );
+
+        my $m =
+          Koha::Borrower::Modifications->new(
+            borrowernumber => $borrowernumber );
+
+        $m->DelModifications;
+        $m->AddModifications(%borrower_changes);
+    }
+}
+elsif ( $action eq 'edit' ) {    #Display logged in borrower's data
+    $template->param(
+        borrower => GetMember( borrowernumber => $borrowernumber ), );
+}
+
+my $captcha = random_string("CCCCC");
+
+$template->param(
+    captcha        => $captcha,
+    captcha_digest => md5_base64($captcha)
+);
+
+output_html_with_http_headers $cgi, $cookie, $template->output;
+
+sub GetHiddenFields {
+    my %hidden_fields;
+
+    my $BorrowerUnwantedField =
+      C4::Context->preference("PatronSelfRegistrationBorrowerUnwantedField");
+
+    my @fields = split( /\|/, $BorrowerUnwantedField );
+    foreach (@fields) {
+        next unless m/\w/o;
+        $hidden_fields{$_} = 1;
+    }
+
+    return \%hidden_fields;
+}
+
+sub GetMandatoryFields {
+    my ($action) = @_;
+
+    my %mandatory_fields;
+
+    my $BorrowerMandatoryField =
+      C4::Context->preference("PatronSelfRegistrationBorrowerMandatoryField");
+
+    my @fields = split( /\|/, $BorrowerMandatoryField );
+
+    foreach (@fields) {
+        $mandatory_fields{$_} = 1;
+    }
+
+    if ( $action eq 'create' || $action eq 'new' ) {
+        $mandatory_fields{'email'} = 1
+          if C4::Context->boolean_preference(
+            'PatronSelfRegistrationVerifyByEmail');
+    }
+
+    return \%mandatory_fields;
+}
+
+sub CheckMandatoryFields {
+    my ( $borrower, $action ) = @_;
+
+    my @empty_mandatory_fields;
+
+    my $mandatory_fields = GetMandatoryFields($action);
+    delete $mandatory_fields->{'cardnumber'};
+
+    foreach my $key ( keys %$mandatory_fields ) {
+        push( @empty_mandatory_fields, $key )
+          unless ( defined( $borrower->{$key} ) && $borrower->{$key} );
+    }
+
+    return @empty_mandatory_fields;
+}
+
+sub ParseCgiForBorrower {
+    my ($cgi) = @_;
+
+    my %borrower;
+
+    foreach ( $cgi->param ) {
+        if ( $_ =~ '^borrower_' ) {
+            my ($key) = substr( $_, 9 );
+            $borrower{$key} = $cgi->param($_);
+        }
+    }
+
+    $borrower{'dateofbirth'} =
+      C4::Dates->new( $borrower{'dateofbirth'} )->output("iso")
+      if ( defined( $borrower{'dateofbirth'} ) );
+
+    return %borrower;
+}
+
+sub DelUnchangedFields {
+    my ( $borrowernumber, %new_data ) = @_;
+
+    my $current_data = GetMember( borrowernumber => $borrowernumber );
+
+    foreach my $key ( keys %new_data ) {
+        if ( $current_data->{$key} eq $new_data{$key} ) {
+            delete $new_data{$key};
+        }
+    }
+
+    return %new_data;
+}
+
+sub DelEmptyFields {
+    my (%borrower) = @_;
+
+    foreach my $key ( keys %borrower ) {
+        delete $borrower{$key} unless $borrower{$key};
+    }
+
+    return %borrower;
+}
diff --git a/opac/opac-registration-verify.pl b/opac/opac-registration-verify.pl
new file mode 100755 (executable)
index 0000000..682dacb
--- /dev/null
@@ -0,0 +1,82 @@
+#!/usr/bin/perl
+
+# 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 2 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use Modern::Perl;
+
+use CGI;
+
+use C4::Auth;
+use C4::Output;
+use C4::Members;
+use Koha::Borrower::Modifications;
+
+my $cgi = new CGI;
+my $dbh = C4::Context->dbh;
+
+unless ( C4::Context->preference('PatronSelfRegistration') ) {
+    print $cgi->redirect("/cgi-bin/koha/opac-main.pl");
+    exit;
+}
+
+my $token = $cgi->param('token');
+my $m = Koha::Borrower::Modifications->new( verification_token => $token );
+
+my ( $template, $borrowernumber, $cookie );
+if ( $m->Verify() ) {
+    ( $template, $borrowernumber, $cookie ) = get_template_and_user(
+        {
+            template_name   => "opac-registration-confirmation.tmpl",
+            type            => "opac",
+            query           => $cgi,
+            authnotrequired => 1,
+        }
+    );
+
+    $template->param(
+        OpacPasswordChange => C4::Context->preference('OpacPasswordChange') );
+
+    my $borrower = $m->GetModifications();
+
+    my $password;
+    ( $borrowernumber, $password ) = AddMember_Opac(%$borrower);
+
+    if ($borrowernumber) {
+        $m->DelModifications();
+
+        $template->param( password_cleartext => $password );
+        $template->param(
+            borrower => GetMember( borrowernumber => $borrowernumber ) );
+        $template->param(
+            PatronSelfRegistrationAdditionalInstructions =>
+              C4::Context->preference(
+                'PatronSelfRegistrationAdditionalInstructions')
+        );
+    }
+
+}
+else {
+    ( $template, $borrowernumber, $cookie ) = get_template_and_user(
+        {
+            template_name   => "opac-registration-invalid.tmpl",
+            type            => "opac",
+            query           => $cgi,
+            authnotrequired => 1,
+        }
+    );
+}
+
+output_html_with_http_headers $cgi, $cookie, $template->output;
index 05e8133..1c942d5 100755 (executable)
@@ -368,7 +368,7 @@ $template->param(
 $template->param( DHTMLcalendar_dateformat  => C4::Dates->DHTMLcalendar() );
 $template->param(
     SuspendHoldsOpac => C4::Context->preference('SuspendHoldsOpac'),
-    AutoResumeSuspendedHolds => C4::Context->preference('AutoResumeSuspendedHolds') ,
+    AutoResumeSuspendedHolds => C4::Context->preference('AutoResumeSuspendedHolds'),
 );
 
 output_html_with_http_headers $query, $cookie, $template->output;