From f448f902222b7a953fa5bf39e0d561c02cfbe807 Mon Sep 17 00:00:00 2001
From: Dan Scott <dan@coffeecode.net>
Date: Thu, 3 May 2012 21:58:09 -0400
Subject: [PATCH] SIP: Option to enable patrons to log in via username

In the interests of making it easier for patrons to log in, add an
option to the SIP configuration that, if enabled, will check the
incoming patron key and treat it as a username if it does not match the
barcode regex.

Signed-off-by: Dan Scott <dan@coffeecode.net>
---
 Open-ILS/examples/oils_sip.xml.example          |  4 ++++
 Open-ILS/src/perlmods/lib/OpenILS/SIP.pm        | 25 +++++++++++++++++++-
 Open-ILS/src/perlmods/lib/OpenILS/SIP/Patron.pm | 31 +++++++++++++++++++++----
 3 files changed, 54 insertions(+), 6 deletions(-)

diff --git a/Open-ILS/examples/oils_sip.xml.example b/Open-ILS/examples/oils_sip.xml.example
index 467cc99..37a67e8 100644
--- a/Open-ILS/examples/oils_sip.xml.example
+++ b/Open-ILS/examples/oils_sip.xml.example
@@ -103,6 +103,10 @@
 						If enabled, the PC field in patron-info requests will return the non-translated profile name
 					<option name='patron_type_uses_code' value='true' />
 					-->
+					<!--
+						If enabled, patrons can log in via username or barcode
+					<option name='patron_login_by_username' value='true' />
+					-->
 				</options>
 
                 <checkin_override>
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/SIP.pm b/Open-ILS/src/perlmods/lib/OpenILS/SIP.pm
index fe312ff..ae63a37 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/SIP.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/SIP.pm
@@ -28,6 +28,7 @@ my $U = 'OpenILS::Application::AppUtils';
 my $editor;
 my $config;
 my $target_encoding;    # FIXME: this is configured at the institution level. 
+my $barcode_regex;
 
 use Digest::MD5 qw(md5_hex);
 
@@ -60,6 +61,14 @@ sub new {
 	return undef unless 
 		$self->login( $login->{id}, $login->{password} );
 
+    if (!$barcode_regex) {
+        my $e = $self->editor();
+        my $org_id = id_from_shortname($self->institution_id());
+        $barcode_regex = $U->ou_ancestor_setting_value(
+            $org_id, 'opac.barcode_regex', $e
+        ) || '';
+    }
+
 	return $self;
 }
 
@@ -157,6 +166,12 @@ sub shortname_from_id {
     return $org_sn_cache{$id} if $org_sn_cache{$id};
     return $org_sn_cache{$id} = editor()->retrieve_actor_org_unit($id)->shortname;
 }
+my %org_id_cache;
+sub id_from_shortname {
+    my $shortname = shift or return;
+    return $org_id_cache{$shortname} if $org_id_cache{$shortname};
+    return $org_id_cache{$shortname} = editor()->search_actor_org_unit({shortname => $shortname})->[0]->id;
+}
 sub patron_barcode_from_id {
     my $id = shift or return;
     return editor()->search_actor_card({ usr => $id, active => 't' })->[0]->barcode;
@@ -228,7 +243,15 @@ sub login {
 
 sub find_patron {
 	my $self = shift;
-	return OpenILS::SIP::Patron->new(@_);
+
+    if ($barcode_regex) {
+        # Force the "barcode => barcode" form so that we can add the barcode regex
+        if (@_ == 1) {
+            unshift(@_, 'barcode');
+        }
+        push (@_, regex => $barcode_regex);
+    }
+    return OpenILS::SIP::Patron->new(@_);
 }
 
 
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/SIP/Patron.pm b/Open-ILS/src/perlmods/lib/OpenILS/SIP/Patron.pm
index c628820..163bd76 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/SIP/Patron.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/SIP/Patron.pm
@@ -32,7 +32,8 @@ my $INET_PRIVS;
 #
 # OpenILS::SIP::Patron->new($barcode);
 # OpenILS::SIP::Patron->new(barcode => $barcode);   # same as above
-# OpenILS::SIP::Patron->new(    usr => $id);       
+# OpenILS::SIP::Patron->new(usr => $id);       
+# OpenILS::SIP::Patron->new(username => $username);
 
 sub new {
     my $class = shift;
@@ -40,8 +41,21 @@ sub new {
     my $patron_id = shift;
     my %args = @_;
 
-    if ($key ne 'usr' and $key ne 'barcode') {
-        syslog("LOG_ERROR", "Patron (card) lookup requested by illegeal key '$key'");
+    # Does this institution want to enable logins via username?
+    my $patron_login_by_username = OpenILS::SIP->get_option_value('patron_login_by_username') || '';
+    syslog("LOG_DEBUG", "enable login by username? $patron_login_by_username");
+
+    # If so, then check the "barcode" to see if it is actually a username
+    if ($key eq "barcode" and $patron_login_by_username =~ /true/i and $args{regex}) {
+
+        # If the value doesn't match the regex, it's a username
+        if ($patron_id !~ /$args{regex}/) {
+            $key = "username";
+        }
+    }
+
+    if ($key ne 'usr' and $key ne 'barcode' and $key ne 'username') {
+        syslog("LOG_ERROR", "Patron (card) lookup requested by illegal key '$key'");
         return undef;
     }
 
@@ -55,8 +69,6 @@ sub new {
 
     syslog("LOG_DEBUG", "OILS: new OpenILS Patron(%s => %s): searching...", $key, $patron_id);
 
-    my $e = OpenILS::SIP->editor();
-
     my $usr_flesh = {
         flesh => 2,
         flesh_fields => {
@@ -73,6 +85,8 @@ sub new {
     # in some cases, we don't need all of this data.  Only fetch the user + barcode
     $usr_flesh = {flesh => 1, flesh_fields => {au => ['card']}} if $args{slim_user};
     
+    my $e = OpenILS::SIP->editor();
+
     my $user;
     if($key eq 'barcode') { # retrieve user by barcode
 
@@ -88,6 +102,13 @@ sub new {
 
         $user = $card->usr;
 
+    } elsif($key eq 'username') { # retrieve user by username
+        $user = $e->search_actor_user([{usrname => $patron_id}, $usr_flesh])->[0];
+
+        if(!$user) {
+            syslog("LOG_WARNING", "No such patron username: $patron_id");
+            return undef;
+        }
     } else {
 	    $user = $e->retrieve_actor_user([$patron_id, $usr_flesh]);
     }
-- 
1.9.3

