Quipu Ecard Registration - Squashed for EG 3.10
authorBill Erickson <berickxx@gmail.com>
Tue, 7 Jul 2020 14:41:36 +0000 (10:41 -0400)
committerChris Sharp <csharp@georgialibraries.org>
Wed, 23 Nov 2022 19:03:22 +0000 (14:03 -0500)
KCLS Quipu integration bits

Notes:

1. See constants along the top of Ecard.pm which will need changing.
2. Ecard.pm add_stat_cats() is very kcls-specific
3. The vendor login uses a new password type 'ecard_vendor' which does
   not have the intermediate md5 hashing.
4. Ecard.pm and templates have header/footer stuff that's specific to
   bibliocommons and should be removed.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Chris Sharp <csharp@georgialibraries.org>
Quipu eCard Integration for PINES

Altering KCLS's Quipu eCard implementation to align
with PINES's needs, with an eye towards a generic feature
that could be submitted to Evergreen master.

Signed-off-by: Chris Sharp <csharp@georgialibraries.org>
Quipu Customizations

Move library card application link to top menu instead of bottom menu,
cleaned up a lot of whitespace issues and old commented out text,
added CSS controls for parts of the Quipu form.

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Quipu Self-Registration Form

Edited both ecard.tt2 and register.tt2 to add quipu form javascript
and add intro text.

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Quipu Ecard Form Update

Added CSS to intro text to hide unless Quipu's code tells it to display.

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
OPAC: Quipu changes for Bootstrap OPAC

This commit just modifies the front end registration page and CSS,
not the perl changes.

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
OPAC: fix Quipu ecard for bootstrap

Quipu - Adjust iframe height

The iframe was cutting off the form causing a double scroll
bar in the browser. This increases the height so that additional
scrolling is not needed.

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
PINES Customization: Quipu Spanish Form

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Quipu: check on full DOB, skip address checking

16 files changed:
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Ecard.pm [new file with mode: 0644]
Open-ILS/src/sql/Pg/005.schema.actors.sql
Open-ILS/src/sql/Pg/950.data.seed-values.sql
Open-ILS/src/sql/Pg/upgrade/XXXX-quipu-ecard-integration.sql [new file with mode: 0644]
Open-ILS/src/templates-bootstrap/opac/css/style.css.tt2
Open-ILS/src/templates-bootstrap/opac/register-sp.tt2 [new file with mode: 0644]
Open-ILS/src/templates-bootstrap/opac/register.tt2
Open-ILS/src/templates/opac/css/style.css.tt2
Open-ILS/src/templates/opac/ecard.tt2 [new file with mode: 0644]
Open-ILS/src/templates/opac/ecard/form.tt2 [new file with mode: 0644]
Open-ILS/src/templates/opac/ecard/submit.tt2 [new file with mode: 0644]
Open-ILS/src/templates/opac/ecard/verify.tt2 [new file with mode: 0644]
Open-ILS/src/templates/opac/parts/footer.tt2
Open-ILS/src/templates/opac/parts/topnav_links.tt2
Open-ILS/src/templates/opac/register.tt2

index 629389f..d0a2d8a 100644 (file)
@@ -30,6 +30,7 @@ use OpenILS::WWW::EGCatLoader::Container;
 use OpenILS::WWW::EGCatLoader::SMS;
 use OpenILS::WWW::EGCatLoader::Register;
 use OpenILS::WWW::EGCatLoader::OpenAthens;
+use OpenILS::WWW::EGCatLoader::Ecard;                                          
 
 my $U = 'OpenILS::Application::AppUtils';
 
@@ -185,6 +186,11 @@ sub load {
 
     $self->load_simple("myopac") if $path =~ m:opac/myopac:; # A default page for myopac parts
 
+    # maybe make these optional parts of load_patron_reg?
+    #return $self->load_ecard_form if $path =~ m|opac/ecard/form|;
+    return $self->load_ecard_submit if $path =~ m|opac/ecard/submit|;
+    return $self->load_ecard_verify if $path =~ m|opac/ecard/verify|;
+
     if($path =~ m|opac/login|) {
         return $self->load_login unless $self->editor->requestor; # already logged in?
 
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Ecard.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Ecard.pm
new file mode 100644 (file)
index 0000000..f35c448
--- /dev/null
@@ -0,0 +1,689 @@
+package OpenILS::WWW::EGCatLoader;
+use strict; use warnings;
+use Apache2::Const -compile => qw(OK FORBIDDEN HTTP_INTERNAL_SERVER_ERROR);
+use OpenSRF::Utils::Logger qw/$logger/;
+use OpenSRF::Utils::JSON;
+use OpenSRF::Utils qw/:datetime/;
+use OpenILS::Utils::Fieldmapper;
+use OpenILS::Application::AppUtils;
+use OpenILS::Utils::CStoreEditor qw/:funcs/;
+use OpenILS::Event;
+use Data::Dumper;
+use LWP::UserAgent;
+use DateTime;
+use Digest::MD5 qw(md5_hex);
+$Data::Dumper::Indent = 0;
+my $U = 'OpenILS::Application::AppUtils';
+
+my @api_fields = (
+    {name => 'vendor_username', required => 1},
+    {name => 'vendor_password', required => 1},
+    {name => 'first_given_name', class => 'au', required => 1},
+    {name => 'second_given_name', class => 'au'},
+    {name => 'family_name', class => 'au', required => 1},
+    {name => 'suffix', class => 'au'},
+    {name => 'email', class => 'au', required => 1},
+    {name => 'passwd', class => 'au', required => 1},
+    {name => 'day_phone', class => 'au', required => 1},
+    {name => 'dob', class => 'au', required => 1},
+    {name => 'home_ou', class => 'au', required => 1},
+    {name => 'ident_type', class => 'au', required => 1},
+    {name => 'ident_value', class => 'au', required => 1},
+    {name => 'ident_value2',
+     class => 'au', 
+     notes => "AKA parent/guardian",
+     required_if => 'Patron is less than 18 years old'
+    },
+    {name => 'pref_first_given_name', class => 'au'},
+    {name => 'pref_second_given_name', class => 'au'},
+    {name => 'pref_family_name', class => 'au'},
+    {name => 'pref_suffix', class => 'au'},
+    {name => 'physical_street1', class => 'aua', required => 1},
+    {name => 'physical_street1_name'},
+    {name => 'physical_street2', class => 'aua'},
+    {name => 'physical_city', class => 'aua', required => 1},
+    {name => 'physical_post_code', class => 'aua', required => 1},
+    {name => 'physical_county', class => 'aua', required => 1},
+    {name => 'physical_state', class => 'aua', required => 1},
+    {name => 'physical_country', class => 'aua', required => 1},
+    {name => 'mailing_street1', class => 'aua', required => 1},
+    {name => 'mailing_street1_name'},
+    {name => 'mailing_street2', class => 'aua'},
+    {name => 'mailing_city', class => 'aua', required => 1},
+    {name => 'mailing_post_code', class => 'aua', required => 1},
+    {name => 'mailing_county', class => 'aua', required => 1},
+    {name => 'mailing_state', class => 'aua', required => 1},
+    {name => 'mailing_country', class => 'aua', required => 1},
+    {name => 'voter_registration', class => 'asvr', required => 1},
+    {name => 'in_house_registration', required => 1},
+);
+
+
+# TODO: wrap the following in a check for a library setting as to whether or not
+# to require emailed verification
+
+## Random 6-character alpha-numeric code that avoids look-alike characters
+## https://ux.stackexchange.com/questions/53341/are-there-any-letters-numbers-that-should-be-avoided-in-an-id
+## Also exclude vowels to avoid creating any real (potentially offensive) words.
+#my @code_chars = ('C','D','F','H','J'..'N','P','R','T','V','W','X','3','4','7','9');
+#sub generate_verify_code {
+#    my $string = '';
+#    $string .= $code_chars[rand @code_chars] for 1..6;
+#    return $string;
+#}
+#
+#
+## only if we're verifying the card via email
+#sub load_ecard_verify {
+#    my $self = shift;
+#    my $cgi = $self->cgi;
+#    $self->collect_header_footer;
+#
+#    # Loading the form.
+#    return Apache2::Const::OK if $cgi->request_method eq 'GET';
+#
+#    #$self->verify_ecard;
+#    return Apache2::Const::OK;
+#}
+#
+#sub verify_ecard {
+#    my $self = shift;
+#    my $cgi = $self->cgi;
+#    my $ctx = $self->ctx;
+#    $self->log_params;
+#
+#    my $verify_code = $ctx->{verify_code} = $cgi->param('verification_code');
+#    my $barcode = $ctx->{barcode} = $cgi->param('barcode');
+#
+#    $ctx->{verify_failed} = 1;
+#
+#    my $e = new_editor();
+#
+#    my $au = $e->search_actor_user({
+#        profile => $PROVISIONAL_ECARD_GRP,
+#        ident_type => $ECARD_VERIFY_IDENT,
+#        ident_value => $verify_code
+#    })->[0];
+#
+#    if (!$au) {
+#        $logger->warn(
+#            "ECARD: No provisional ecard found with code $verify_code");
+#        sleep 2; # Mitigate brute-force attacks
+#        return;
+#    }
+#
+#    my $card = $e->search_actor_card({
+#        usr => $au->id,
+#        barcode => $barcode
+#    })->[0];
+#
+#    if (!$card) {
+#        $logger->warn("ECARD: Failed to match verify code ".
+#            "($verify_code) with provided barcode ($barcode)");
+#        sleep 2; # Mitigate brute-force attacks
+#        return;
+#    }
+#
+#    # Verification looks good.  Update the account.
+#
+#    my $grp = new_editor()->retrieve_permission_grp_tree($FULL_ECARD_GRP);
+#
+#    $au->profile($grp->id);
+#    $au->expire_date(
+#        DateTime->now(time_zone => 'local')->add(
+#            seconds => interval_to_seconds($grp->perm_interval))->iso8601()
+#    );
+#
+#    $e->xact_begin;
+#
+#    unless ($e->update_actor_user($au)) {
+#        $logger->error("ECARD update failed for $barcode: " . $e->die_event);
+#        return;
+#    }
+#    
+#    $e->commit;
+#    $logger->info("ECARD: Update to full ecard succeeded for $barcode");
+#
+#    $ctx->{verify_success} = 1;
+#    $ctx->{verify_failed} = 0;
+#
+#    return;
+#}
+
+
+sub log_params {
+    my $self = shift;
+    my $cgi = $self->cgi;
+    my @params = $cgi->param;
+
+    my $msg = '';
+    for my $p (@params) {
+        next if $p =~ /pass/;
+        $msg .= "|" if $msg; 
+        $msg .= "$p=".$cgi->param($p);
+    }
+
+    $logger->info("ECARD: Submit params: $msg");
+}
+
+sub handle_testmode_api {
+    my $self = shift;
+    my $ctx = $self->ctx;
+
+    # Strip data we don't want to publish.
+    my @doc_fields;
+    for my $field_info (@api_fields) {
+        my $doc_info = {};
+        for my $info_key (keys %$field_info) {
+            $doc_info->{$info_key} = $field_info->{$info_key} 
+                unless $info_key eq 'class';
+        }
+        push(@doc_fields, $doc_info);
+    }
+
+    $ctx->{response}->{messages} = [fields => \@doc_fields];
+    $ctx->{response}->{status} = 'API_OK';
+    return $self->compile_response;
+}
+
+sub handle_datamode_api {
+    my $self = shift;
+    my $datamode = shift;
+    my $ctx = $self->ctx;
+
+    if ($datamode =~ /org_units/) {
+        my $orgs = new_editor()->search_actor_org_unit({opac_visible => 't'});
+        my $list = [
+            map { 
+                {name => $_->name, id => $_->id, parent_ou => $_->parent_ou} 
+            } @$orgs
+        ];
+        $ctx->{response}->{messages} = [org_units => $list];
+    }
+
+    $ctx->{response}->{status} = 'DATA_OK';
+    return $self->compile_response;
+}
+
+sub load_ecard_submit {
+    my $self = shift;
+    my $ctx = $self->ctx;
+    my $cgi = $self->cgi;
+
+    $self->log_params;
+
+    my $testmode = $cgi->param('testmode') || '';
+    my $datamode = $cgi->param('datamode') || '';
+
+    my $e = $ctx->{editor} = new_editor();
+    $ctx->{response} = {messages => []};
+
+    if ($testmode eq 'CONNECT') {
+        $ctx->{response}->{status} = 'CONNECT_OK';
+        return $self->compile_response;
+    }
+
+    return Apache2::Const::FORBIDDEN unless 
+        $cgi->request_method eq 'POST' &&
+        $self->verify_vendor_host &&
+        $self->login_vendor;
+
+    if ($testmode eq 'AUTH') {
+        # If we got this far, the caller is authorized.
+        $ctx->{response}->{status} = 'AUTH_OK';
+        return $self->compile_response;
+    }
+
+    return $self->handle_testmode_api if $testmode eq 'API';
+    return $self->handle_datamode_api($datamode) if $datamode;
+
+    return $self->compile_response unless $self->make_user;
+    return $self->compile_response unless $self->add_addresses;
+    return $self->compile_response unless $self->check_dupes;
+    return $self->compile_response unless $self->add_card;
+    return $self->compile_response unless $self->add_survey_responses;
+    return $self->compile_response unless $self->save_user;
+    return $self->compile_response unless $self->add_usr_settings;
+    return $self->compile_response if $ctx->{response}->{status};
+
+    $U->create_events_for_hook(
+        'au.create.ecard', $ctx->{user}, $ctx->{user}->home_ou);
+
+    $ctx->{response}->{status} = 'OK';
+    $ctx->{response}->{barcode} = $ctx->{user}->card->barcode;
+
+    return $self->compile_response;
+}
+
+# E-card vendor is not a regular account.  They must have an entry in 
+# the password table with password type ecard_vendor.
+sub login_vendor {
+    my $self = shift;
+    my $username = $self->cgi->param('vendor_username');
+    my $password = $self->cgi->param('vendor_password');
+
+    my $e = new_editor();
+    my $vendor = $e->search_actor_user({usrname => $username})->[0];
+    return 0 unless $vendor;
+
+    return unless $U->verify_user_password(
+        $e, $vendor->id, $password, 'ecard_vendor');
+
+    # Auth checks out OK.  Manually create an authtoken
+
+    my $auth = $U->simplereq(
+        'open-ils.auth_internal',
+        'open-ils.auth_internal.session.create',
+        {user_id => 1, org_unit => 394, login_type => 'temp'}
+    );
+
+    return unless $auth && $auth->{textcode} eq 'SUCCESS';
+
+    $self->ctx->{authtoken} = $auth->{payload}->{authtoken};
+
+    return 1;
+}
+
+sub verify_vendor_host {
+    my $self = shift;
+    # TODO
+    # Confirm calling host matches AOUS ecard.vendor.host
+    # NOTE: we may not have that information inside the firewall.
+    return 1;
+}
+
+
+sub compile_response {
+    my $self = shift;
+    my $ctx = $self->ctx;
+    $self->apache->content_type("application/json; charset=utf-8");
+    $ctx->{response} = OpenSRF::Utils::JSON->perl2JSON($ctx->{response});
+    $logger->info("ECARD responding with " . $ctx->{response});
+    return Apache2::Const::OK;
+}
+
+my %keep_case = (usrname => 1, passwd => 1, email => 1);
+sub upperclense {
+    my $self = shift;
+    my $field = shift;
+    my $value = shift;
+    $value = uc($value) unless $keep_case{$field};
+    $value = lc($value) if $field eq 'email'; # force it
+    $value =~ s/(^\s*|\s*$)//g;
+    return $value;
+}
+
+# Create actor.usr perl object and populate column data
+sub make_user {
+    my $self = shift;
+    my $ctx = $self->ctx;
+    my $cgi = $self->cgi;
+
+    my $au = Fieldmapper::actor::user->new;
+    my $in_house = $cgi->param('in_house_registration');
+
+    $au->isnew(1);
+    $au->net_access_level(1); # Filtered
+    $au->name_keywords($in_house ? 'quipu_inhouse' : 'quipu_remote');
+    my $home_ou = $cgi->param('home_ou');
+
+    my $perm_grp = $U->ou_ancestor_setting_value(
+        $home_ou,
+        'lib.ecard_patron_profile'
+    );
+
+    $au->profile($perm_grp);
+    my $grp = new_editor()->retrieve_permission_grp_tree($perm_grp);
+
+    $au->expire_date(
+        DateTime->now(time_zone => 'local')->add(
+            seconds => interval_to_seconds($grp->perm_interval))->iso8601()
+    );
+
+    for my $field_info (@api_fields) {
+        my $field = $field_info->{name};
+        next unless $field_info->{class} eq 'au';
+
+        my $val = $cgi->param($field);
+
+        $field = 'guardian' if $field eq 'ident_value2' && $val;
+        $au->juvenile(1) if $field eq 'guardian' && $val;
+
+        if ($field_info->{required} && !$val) {
+            my $msg = "Value required for field: '$field'";
+            $ctx->{response}->{status} = 'INVALID_PARAMS';
+            push(@{$ctx->{response}->{messages}}, $msg);
+            $logger->error("ECARD $msg");
+        }
+
+        $val = undef if $field eq 'day_phone' && $val eq '--';
+        $self->verify_dob($val) if $field eq 'dob' && $val;
+        $au->$field($val);
+    }
+
+    # Usename defaults to the user barcode
+    return undef if $ctx->{response}->{status}; 
+    return $ctx->{user} = $au;
+}
+
+# Card generation must occur after the user is saved in the DB.
+sub add_card {
+    my $self = shift;
+    my $ctx = $self->ctx;
+    my $cgi = $self->cgi;
+    my $user = $ctx->{user};
+    my $home_ou = $cgi->param('home_ou');
+    my $prefix = $U->ou_ancestor_setting_value(
+        $home_ou, 
+        'lib.ecard_barcode_prefix'
+    ) || 'AUTO';
+
+    my $bc = new_editor()->json_query({from => [
+        'actor.generate_barcode', 
+        $prefix, # ecard prefix
+        8, # length of autogenated portion
+        'actor.auto_barcode_ecard_seq' # base sequence for autogeneration.
+    ]})->[0];
+
+    my $barcode = $bc->{'actor.generate_barcode'};
+
+    $logger->info("ECARD using generated barcode: $barcode");
+
+    my $card = Fieldmapper::actor::card->new;
+    $card->id(-1);
+    $card->isnew(1);
+    $card->usr($user->id);
+    $card->barcode($barcode);
+
+    # username defaults to barcode
+    $user->usrname($barcode);
+    $user->card($card);
+    $user->cards([$card]);
+
+    return 1;
+}
+
+# Returns 1 on success, undef on error.
+sub verify_dob {
+    my $self = shift;
+    my $dob = shift;
+    my $ctx = $self->ctx;
+    my $cgi = $self->cgi;
+
+    my @parts = split(/-/, $dob);
+    my $dob_date;
+
+    eval { # avoid dying on funky dates
+        $dob_date = DateTime->new(
+            year => $parts[0], month => $parts[1], day => $parts[2]);
+    };
+
+    if (!$dob_date || $dob_date > DateTime->now) {
+        my $msg = "Invalid dob: '$dob'";
+        $ctx->{response}->{status} = 'INVALID_PARAMS';
+        push(@{$ctx->{response}->{messages}}, $msg);
+        $logger->error("ECARD $msg");
+        return undef;
+    }
+
+    my $comp_date = DateTime->now;
+    $comp_date->set_hour(0);
+    $comp_date->set_minute(0);
+    $comp_date->set_second(0);
+    $comp_date->subtract(years => 18); # juv age
+
+    if (
+        $dob_date > $comp_date # less than 18 years old
+        && !$cgi->param('ident_value2')) {
+
+        my $msg = "Parent/Guardian (ident_value2) is required for patrons ".
+            "under 18 years of age. dob=$dob";
+        $ctx->{response}->{status} = 'INVALID_PARAMS';
+        push(@{$ctx->{response}->{messages}}, $msg);
+        $logger->error("ECARD $msg");
+        return undef;
+    }
+
+    return 1;
+}
+
+# returns true if the addresses contain all of the same values.
+sub addrs_match {
+    my ($self, $addr1, $addr2) = @_;
+    for my $field ($addr1->real_fields) {
+        return 0 if ($addr1->$field() || '') ne ($addr2->$field() || '');
+    }
+    return 1;
+}
+
+
+sub add_addresses {
+    my $self = shift;
+    my $cgi = $self->cgi;
+    my $ctx = $self->ctx;
+    my $e = $ctx->{editor};
+    my $user = $ctx->{user};
+
+    my $physical_addr = Fieldmapper::actor::user_address->new;
+    $physical_addr->isnew(1);
+    $physical_addr->usr($user->id);
+    $physical_addr->address_type('PHYSICAL');
+    $physical_addr->within_city_limits('f');
+
+    my $mailing_addr = Fieldmapper::actor::user_address->new;
+    $mailing_addr->isnew(1);
+    $mailing_addr->usr($user->id);
+    $mailing_addr->address_type('MAILING');
+    $mailing_addr->within_city_limits('f');
+
+   # Use as both billing and mailing via virtual ID.
+    $physical_addr->id(-1);
+    $mailing_addr->id(-2);
+    $user->billing_address(-1);
+    $user->mailing_address(-2);
+
+    # Confirm we have values for all of the required fields.
+    # Apply values to our in-progress address object.
+    for my $field_info (@api_fields) {
+        my $field = $field_info->{name};
+        next unless $field =~ /physical|mailing/;
+        next if $field =~ /street1_/;
+
+        my $val = $cgi->param($field);
+
+        if ($field_info->{required} && !$val) {
+            my $msg = "Value required for field: '$field'";
+            $ctx->{response}->{status} = 'INVALID_PARAMS';
+            push(@{$ctx->{response}->{messages}}, $msg);
+            $logger->error("ECARD $msg");
+        }
+
+        if ($field =~ /physical/) {
+            (my $col_field = $field) =~ s/physical_//g;
+            $physical_addr->$col_field($val) if $val;
+        } else {
+            (my $col_field = $field) =~ s/mailing_//g;
+            $mailing_addr->$col_field($val) if $val;
+        }
+
+    }
+
+    # exit if there were any errors above.
+    return undef if $ctx->{response}->{status}; 
+
+    $user->billing_address($physical_addr);
+    $user->mailing_address($mailing_addr);
+    $user->addresses([$physical_addr, $mailing_addr]);
+
+    return 1;
+}
+
+sub add_usr_settings {
+    my $self = shift;
+    my $cgi = $self->cgi;
+    my $ctx = $self->ctx;
+    my $user = $ctx->{user};
+    my %settings = (
+        'opac.hold_notify' => 'email'
+    );
+
+    $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.patron.settings.update',
+        $self->ctx->{authtoken}, $user->id, \%settings);
+
+    return 1;
+}
+
+sub add_survey_responses {
+    my $self = shift;
+    my $cgi = $self->cgi;
+    my $user = $self->ctx->{user};
+    my $answer = $cgi->param('voter_registration');
+
+    my $survey_response = Fieldmapper::action::survey_response->new;
+    $survey_response->id(-1);
+    $survey_response->isnew(1);
+    $survey_response->survey(1); # voter registration survey
+    $survey_response->question(1);
+    $survey_response->answer($answer);
+
+    $user->survey_responses([$survey_response]);
+    return 1;
+}
+
+# TODO: this is KCLS-specific, but maybe we can make it something
+# generic for adding stat cats to the patron
+
+#sub add_stat_cats {
+#    my $self = shift;
+#    my $cgi = $self->cgi;
+#    my $user = $self->ctx->{user};
+#
+#    my $ds_map = Fieldmapper::actor::stat_cat_entry_user_map->new;
+#    $ds_map->isnew(1);
+#    $ds_map->stat_cat(12);
+#    $ds_map->stat_cat_entry('KCLS');
+#
+#    my $events = $cgi->param('events_mailing');
+#    my $em_map = Fieldmapper::actor::stat_cat_entry_user_map->new;
+#    $em_map->isnew(1);
+#    $em_map->stat_cat(3);
+#    $em_map->stat_cat_entry($events ? 'Y' : 'N');
+#
+#    my $foundation = $cgi->param('foundation_mailing');
+#    my $fm_map = Fieldmapper::actor::stat_cat_entry_user_map->new;
+#    $fm_map->isnew(1);
+#    $fm_map->stat_cat(4);
+#    $fm_map->stat_cat_entry($foundation ? 'Y' : 'N');
+#
+#    $user->stat_cat_entries([$ds_map, $em_map, $fm_map]);
+#    return 1;
+#}
+
+# Returns true if no dupes found, false if dupes are found.
+sub check_dupes {
+    my $self = shift;
+    my $ctx  = $self->ctx;
+    my $user = $ctx->{user};
+    my $addr = $user->addresses->[0];
+    my $e = new_editor();
+
+    my @dupe_patron_fields = 
+        qw/first_given_name family_name dob/;
+
+    my $search = {
+        first_given_name => {value => $user->first_given_name, group => 0},
+        family_name => {value => $user->family_name, group => 0},
+        dob => {value => $user->dob, group => 0} 
+    };
+
+    my $root_org = $e->search_actor_org_unit({parent_ou => undef})->[0];
+
+    my $ids = $U->storagereq(
+        "open-ils.storage.actor.user.crazy_search", 
+        $search,
+        1000,           # search limit
+        undef,          # sort
+        1,              # include inactive
+        $root_org->id,  # ws_ou
+        $root_org->id   # search_ou
+    );
+
+    return 1 if @$ids == 0;
+
+    $logger->info("ECARD found potential duplicate patrons: @$ids");
+
+#    if (my $streetname = $self->cgi->param('physical_street1_name')) {
+#        # We found matching patrons.  Perform a secondary check on the
+#        # address street name only.
+#
+#        $logger->info("ECARD secondary search on street name: $streetname");
+#
+#        my $addr_ids = $e->search_actor_user_address(
+#            {   usr => $ids,
+#                street1 => {'~*' => "(^| )$streetname( |\$)"}
+#            }, {idlist => 1}
+#        );
+#
+#        if (@$addr_ids) {
+#            # we don't really care what patrons match at this point,
+#            # only whether a match is found.
+#            $ids = [1];
+#            $logger->info("ECARD secondary address check match(es) ".
+#                "found on address(es) @$addr_ids");
+#
+#        } else {
+#            $ids = [];
+#            $logger->info(
+#                "ECARD secondary address check found no matches");
+#        }
+#
+#    } else {
+#        $ids = [];
+#        # unclear if this is a possibility -- err on the side of allowing
+#        # the registration.
+#        $logger->info("ECARD found possible patron match but skipping ".
+#            "secondary street name check -- no street name was provided");
+#    }
+#
+#    return 1 if @$ids == 0;
+
+    $ctx->{response}->{status} = 'DUPLICATE';
+    $ctx->{response}->{messages} = ['first_given_name', 
+        'family_name', 'dob'];
+    return undef;
+}
+
+
+sub save_user {
+    my $self = shift;
+    my $ctx = $self->ctx;
+    my $cgi = $self->cgi;
+    my $user = $ctx->{user};
+
+    my $resp = $U->simplereq(
+        'open-ils.actor',
+        'open-ils.actor.patron.update',
+        $self->ctx->{authtoken}, $user
+    );
+
+    $resp = {textcode => 'UNKNOWN_ERROR'} unless $resp;
+
+    if ($U->is_event($resp)) {
+
+        my $msg = "Error creating user account: " . $resp->{textcode};
+        $logger->error("ECARD: $msg");
+
+        $ctx->{response}->{status} = 'CREATE_ERR';
+        $ctx->{response}->{messages} = [{msg => $msg, pid => $$}];
+
+        return 0;
+    }
+
+    $ctx->{user} = $resp;
+    return 1;
+}
+
+1;
+
index 8c8328f..32971a6 100644 (file)
@@ -208,6 +208,27 @@ $$;
 
 CREATE INDEX actor_usr_setting_usr_idx ON actor.usr_setting (usr);
 
+-- Start at 100 to avoid barcodes with long stretches of zeros early on.
+-- eCard barcodes have 7 auto-generated digits.
+CREATE SEQUENCE actor.auto_barcode_ecard_seq START 100 MAXVALUE 9999999;
+
+CREATE OR REPLACE FUNCTION actor.generate_barcode
+    (prefix TEXT, numchars INTEGER, seqname TEXT) RETURNS TEXT AS
+$$
+/*
+Generate a barcode starting with 'prefix' and followed by 'numchars'
+numbers.  The auto portion numbers are generated from the provided
+sequence, guaranteeing uniquness across all barcodes generated with
+the same sequence.  The number is left-padded with zeros to meet the
+numchars size requirement.  Returns NULL if the sequnce value is
+higher than numchars can accommodate .*/
+       SELECT NEXTVAL($3); -- bump the sequence up 1
+       SELECT CASE
+               WHEN LENGTH(CURRVAL($3)::TEXT) > $2 THEN NULL
+               ELSE $1 || LPAD(CURRVAL($3)::TEXT, $2, '0')
+               END;
+$$ LANGUAGE SQL;
+
 CREATE TABLE actor.stat_cat_sip_fields (
     field   CHAR(2) PRIMARY KEY,
     name    TEXT    NOT NULL,
index 1487447..828d560 100644 (file)
@@ -2900,8 +2900,9 @@ INSERT INTO permission.grp_perm_map (grp, perm, depth, grantable)
 
 -- Admin user account
 INSERT INTO actor.passwd_type 
-    (code, name, login, crypt_algo, iter_count) 
-    VALUES ('main', 'Main Login Password', TRUE, 'bf', 10);
+    (code, name, login, crypt_algo, iter_count) VALUES
+    ('main', 'Main Login Password', TRUE, 'bf', 10)
+    ,('ecard_vendor', 'eCard Vendor Password', TRUE, 'bf', 10);
 
 INSERT INTO actor.usr ( profile, card, usrname, passwd, first_given_name, family_name, dob, master_account, super_user, ident_type, ident_value, home_ou ) VALUES ( 1, 1, md5(random()::text), md5(random()::text), 'Administrator', 'System Account', '1979-01-22', TRUE, TRUE, 1, 'identification', 1 );
 
@@ -4562,6 +4563,24 @@ INSERT into config.org_unit_setting_type
         'coust', 'description'),
     'string', null)
 
+,( 'lib.ecard_barcode_prefix', 'lib',
+    oils_i18n_gettext('lib.ecard_barcode_prefix',
+        'Barcode prefix for Quipu eCard feature',
+        'coust', 'label'),
+    oils_i18n_gettext('lib.ecard_barcode_prefix',
+        'Set the barcode prefix for new Quipu eCard users',
+        'coust', 'description'),
+    'string', null)
+
+,( 'lib.ecard_patron_profile', 'lib',
+    oils_i18n_gettext('lib.ecard_patron_profile',
+        'Patron permission profile for Quipu eCard feature',
+        'coust', 'label'),
+    oils_i18n_gettext('lib.ecard_barcode_prefix',
+        'Patron permission profile for Quipu eCard feature',
+        'coust', 'description'),
+    'link', 'pgt')
+
 ,( 'lib.info_url', 'lib',
     oils_i18n_gettext('lib.info_url',
         'Library information URL (such as "http://example.com/about.html")',
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX-quipu-ecard-integration.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX-quipu-ecard-integration.sql
new file mode 100644 (file)
index 0000000..378856c
--- /dev/null
@@ -0,0 +1,51 @@
+BEGIN;
+
+-- Thank you, berick :-)
+-- Start at 100 to avoid barcodes with long stretches of zeros early on.
+-- eCard barcodes have 7 auto-generated digits.
+CREATE SEQUENCE actor.auto_barcode_ecard_seq START 100 MAXVALUE 9999999;
+                                                                               
+CREATE OR REPLACE FUNCTION actor.generate_barcode
+    (prefix TEXT, numchars INTEGER, seqname TEXT) RETURNS TEXT AS
+$$
+/*
+Generate a barcode starting with 'prefix' and followed by 'numchars'
+numbers.  The auto portion numbers are generated from the provided
+sequence, guaranteeing uniquness across all barcodes generated with
+the same sequence.  The number is left-padded with zeros to meet the
+numchars size requirement.  Returns NULL if the sequnce value is
+higher than numchars can accommodate .*/
+    SELECT NEXTVAL($3); -- bump the sequence up 1
+    SELECT CASE
+        WHEN LENGTH(CURRVAL($3)::TEXT) > $2 THEN NULL
+        ELSE $1 || LPAD(CURRVAL($3)::TEXT, $2, '0')
+    END;
+$$ LANGUAGE SQL;
+
+INSERT INTO actor.passwd_type
+    (code, name, login, crypt_algo, iter_count)
+    VALUES ('ecard_vendor', 'eCard Vendor Password', TRUE, 'bf', 10);
+
+INSERT into config.org_unit_setting_type
+( name, grp, label, description, datatype, fm_class ) VALUES
+
+( 'lib.ecard_barcode_prefix', 'lib',
+    oils_i18n_gettext('lib.ecard_barcode_prefix',
+        'Barcode prefix for Quipu eCard feature',
+        'coust', 'label'),
+    oils_i18n_gettext('lib.ecard_barcode_prefix',
+        'Set the barcode prefix for new Quipu eCard users',
+        'coust', 'description'),
+    'string', null)
+
+,( 'lib.ecard_patron_profile', 'lib',
+    oils_i18n_gettext('lib.ecard_patron_profile',
+        'Patron permission profile for Quipu eCard feature',
+        'coust', 'label'),
+    oils_i18n_gettext('lib.ecard_barcode_prefix',
+        'Patron permission profile for Quipu eCard feature',
+        'coust', 'description'),
+    'link', 'pgt')
+;
+
+COMMIT;
index 87ba483..9cbb7e3 100755 (executable)
@@ -4143,6 +4143,24 @@ padding: 15px;
 
 #course_material_table td, #course_material_table th {
     padding: 4px;
+
+/* QUIPU CUSTOMIZATIONS */
+.radioLabel {
+    text-decoration: none;
+    color: #000;
+    padding-right: 10px;
+}
+
+.eCARDPreferredNameDivClass {
+    padding: 10px;
+    font-size: .9em;
+}
+
+.eCARDPatronNumber {
+    border:3px solid forestgreen;
+    padding:20px;max-width:700px;
+    font-weight:bold;
+    text-align:center;
 }
 
 .form-control {
diff --git a/Open-ILS/src/templates-bootstrap/opac/register-sp.tt2 b/Open-ILS/src/templates-bootstrap/opac/register-sp.tt2
new file mode 100644 (file)
index 0000000..d29bf5e
--- /dev/null
@@ -0,0 +1,28 @@
+[%- PROCESS "opac/parts/header.tt2";
+    PROCESS "opac/parts/org_selector.tt2";
+    WRAPPER "opac/parts/base.tt2";
+    INCLUDE "opac/parts/topnav.tt2";
+    ctx.page_title = l("Apply for a PINES Library Card");
+%]
+
+
+
+<h2 class="sr-only">[% l('Apply for a PINES Library Card') %]</h2>
+<div id="content-wrapper">
+    <div id="main-content-register">
+        <div class="common-full-pad"></div>
+            <p style="font-size:.8em;">(<a href="/eg/opac/register">English</a> | Español)</p>
+            <iframe id="eCARDFrame" style="border:none;" src="https://ecard.quipugroup.net/Libraries/48/eCARD.php?language=es" allowfullscreen="" width="100%" height="1900px;"></iframe>
+            <!-- eCARD requires JavaScript in order to display the registration form -->
+            <!-- The following will detect if JavaScript is enabled on the patron's browser -->
+            <noscript>
+            <h2 style="color:red;">Warning - JavaScript Required</h2>
+            <p>For full functionality of this web page it is necessary to enable JavaScript in your browser. For more information on most browsers, try <a href="http://www.enable-javascript.com/" target="_blank">How to enable JavaScript</a> OR <a href="http://activatejavascript.org/en/instructions" target="_blank">activatejavascript.org</a><
+            </p>
+            </noscript>
+            </div>
+        
+        <div class="common-full-pad"></div>    
+    </div>
+</div>
+[%- END %]
index c6dbec3..bee05fa 100755 (executable)
     WRAPPER "opac/parts/base.tt2";
     INCLUDE "opac/parts/topnav.tt2";
     ctx.page_title = l("Request Library Card");
-
-# for privacy, reload the page after (default) 5 minutes
-refresh_time = ctx.register.settings.refresh_timeout || 300;
-ctx.refresh = refresh_time _ '; ' _ ctx.opac_root _ '/home';
-
-# some useful variables and MACROs for display,
-# field validation, and added info display
-
-ctx_org = ctx.physical_loc || ctx.search_ou || ctx.aou_tree.id;
-
-# list of the registration fields to (potentially)
-# display in the order they should be shown
-
-# post_code is the only field below that is required in the database and
-# post_code is only required if an address is created.
-# To prevent any of these fields from showing locally, regardless org unit
-# settings, simply remove the fields from this list.  In the case of
-# addresses, if all address fields are removed, no attempt at creating
-# an address will be made (and post_code will no longer be required).
-
-register_fields = [
-    {class => 'stgu',  name = 'first_given_name', label => l('First Name')},
-    {class => 'stgu',  name = 'second_given_name', label => l('Middle Name')},
-    {class => 'stgu',  name = 'family_name', label => l('Last Name')},
-    {class => 'stgu',  name = 'pref_first_given_name', label => l('Preferred First Name')},
-    {class => 'stgu',  name = 'pref_second_given_name', label => l('Preferred Middle Name')},
-    {class => 'stgu',  name = 'pref_family_name', label => l('Preferred Last Name')},
-    {class => 'stgma', name = 'street1', label => l('Street Address')},
-    {class => 'stgma', name = 'street2', label => l('Street Address (2)')},
-    {class => 'stgma', name = 'city', label => l('City')},
-    {class => 'stgma', name = 'county', label => l('County')},
-    {class => 'stgma', name = 'state', label => l('State')},
-    {class => 'stgma', name = 'post_code', label => l('Zip Code')},
-    {class => 'stgu',  name = 'dob', label => l('Date of Birth')},
-    {class => 'stgu',  name = 'day_phone', label => l('Phone Number')},
-    {class => 'stgu',  name = 'email', label => l('Email Address')}
-    {class => 'stgu',  name = 'usrname', label => l('Requested Username')}
-];
+%]
 
 
 
-%]
-
 <h2 class="sr-only">[% l('Account Registration') %]</h2>
-<div class="container">
+<div id="content-wrapper">
     <div id="main-content-register">
-        <h1>[% l('Request a Library Card')%]</h1>
-        <span class="validate">&bigstar; = Required Field</span>
-        <hr/>
-
-        [% IF ctx.register.success %]
-            <h3>[% l('Registration successful!') %]<h3>
-            <h4>[% l('Please see library staff to complete your registration.') %]</h4>
-
-            [% IF ctx.register.username_taken %]
-            <p>
-                [% |l %]
-                Note: The selected username may be in use by another patron.
-                You may select another username when finalizing your
-                registration or in the online catalog.
-                [% END %]
-            </p>
-            [% END %]
-
-            <br/>
-            <p>
-                <a href="[% ctx.opac_root %]/home"
-                    class="btn btn-confirm">[% l('Return to the Catalog') %]</a>
+        <div class="common-full-pad"></div>
+            <p style="font-size:.8em;">(English | <a href="/eg/opac/register-sp">Español</a>)</p>
+            <iframe id="eCARDFrame" height="1900px;" width="100%" style="border:none;" src="https://ecard.quipugroup.net/Libraries/48/eCARD.php" allowfullscreen=""></iframe>
+            <!-- eCARD requires JavaScript in order to display the registration form -->
+            <!-- The following will detect if JavaScript is enabled on the patron's browser -->
+            <noscript>
+            <h2 style="color:red;">Warning - JavaScript Required</h2>
+            <p>For full functionality of this web page it is necessary to enable JavaScript in your browser. For more information on most browsers, try <a href="http://www.enable-javascript.com/" target="_blank">How to enable JavaScript</a> OR <a href="http://activatejavascript.org/en/instructions" target="_blank">activatejavascript.org</a><
             </p>
-
-        [% ELSIF ctx.register.error %]
-            <h3>[% l('A registration error has occurred') %]</h3>
-            <h4>[% l('Please see library staff to complete your registration.') %]</h4>
-
-            <br/>
-            <p>
-                <a href="[% ctx.opac_root %]/home"
-                    class="btn btn-confirm">[% l('Return to the Catalog') %]</a>
-            </p>
-
-        [% ELSE %]
-
-        [% IF ctx.user %]
-            <!-- if the user is logged in, make it
-                clear we are tracking the requestor -->
-            <h4>[% l('New account requested by [_1] [_2] [_3] [_4] [_5]',
-                    ctx.user.prefix, ctx.user.first_given_name,
-                    ctx.user.second_given_name, ctx.user.family_name,
-                    ctx.user.suffix
-                ) | html %]</h4>
-        [% END %]
-
-        <form method='POST' class="needs-validation" novalidate>
-            <div class="form-group row">
-                <label class="control-label col-md-2" for='stgu.home_ou'>[% l('Home Library') %]</label>
-                <div class="col-md-6">
-                    [% INCLUDE build_org_selector
-                            name='stgu.home_ou'
-                            value=value || ctx_org
-                            can_have_users_only=1
-                            valid_org_list=ctx.register.valid_orgs
-                    %]
-                </div>    
-                <div class="col-md-4">
-                    [% IF ctx.register.invalid.bad_home_ou %]
-                    <span class='patron-reg-invalid'>
-                        [% l('Please select a valid library') %]
-                    </span>
-                    [% END %]
-                </div>
+            </noscript>
             </div>
-
-[%
-# <=== shifting code left for readability
-
-# render a row for each of the register fields
-FOR field_def IN register_fields;
-    fclass = field_def.class;
-    fname = field_def.name;
-    orig_name = fname;
-
-    field_path = fclass _ "." _ fname;
-
-    IF fname.match('^pref_');
-        # Preferred name fields adopt most visibility, etc.
-        # settings from the primary name counterparts.
-        fname = fname.remove('^pref_');
-    END;
-
-    show = ctx.register.settings.$fclass.$fname.show;
-    require = ctx.register.settings.$fclass.$fname.require;
-    example = ctx.register.settings.$fclass.$fname.example;
-    value = ctx.register.values.$fclass.$fname;
-
-    invalid_require = ctx.register.invalid.$fclass.$fname.require;
-    invalid_regex = ctx.register.invalid.$fclass.$fname.regex;
-
-    IF orig_name.match('^pref_');
-        show = show || require;
-        require = 0; # pref name values never required
-    END;
-
-    NEXT UNLESS require OR show;
-%]
-
-<div class="form-group row">
-        <label class="control-label col-md-2" for='[% field_path %]'>[% field_def.label | html %]
-        [% IF require %]
-        <span class="validate">&bigstar;</span>
-        [% END %]
-        </label>
-        <div class="col-md-6">
-            [% IF fname == "dob"; %]
-            <div class="input-group date" data-provide="datepicker-inline">
-                <input type="text" class="form-control datepicker" id='[% field_path %]'
-                    name='[% field_path %]' value='[% value || CGI.param(field_path) | html %]' [% IF require %]required[% END %] data-date-format="yyyy-mm-dd" />
-                <div class="input-group-addon">
-                    <span class="glyphicon glyphicon-th"></span>
-                </div>
-            </div>
-           [% ELSE; %]
-        <input
-            class='form-control'
-            type='text'
-            id='[% field_path %]'
-            name='[% field_path %]'
-            value='[% value || CGI.param(field_path) | html %]' [% IF require %]required[% END %]/>
-     [% END %]
-        <div class="invalid-feedback">
-          Please enter a [% field_def.label | html %]
-        </div>
-         [% IF example %]
-        <span class='patron-reg-extra'>
-            [% l('(Example: [_1])', example) %]
-        </span>
-    [% END %]
-
-        </div>
-
-    <div class="col-md-4">
-    <!-- display errors and example text -->
-
-    [% IF invalid_require %]
-        <span class='patron-reg-invalid'>
-            [% l('This field is required') %]
-        </span>
-    [% ELSIF invalid_regex %]
-        <span class='patron-reg-invalid'>
-            [% l('The value entered does not have the correct format') %]
-        </span>
-    [% END %]
-    [% IF example %]
-        <span class='patron-reg-extra'>
-            [% l('(Example: [_1])', example) %]
-        </span>
-    [% END %]
+        
+        <div class="common-full-pad"></div>    
     </div>
 </div>
-[% END %]
-
-
-<!-- ====> shifting the code back to the right for context -->
-                    [% IF ctx.register.opt_in_settings.size > 0 %]
-                        [% FOR optin IN ctx.register.opt_in_settings %]
-                        <div class="form-group row">
-                            <label class="control-label col-md-2" for="stgs.[% optin.name | uri %]'">[% optin.label | html %]</label>
-                            <div class="col-md-6">
-                                <input type='checkbox'
-                                    name='stgs.[% optin.name | uri %]'
-                                    id='stgs.[% optin.name | uri %]'
-                                    title="[% optin.label | html %]"
-                                ></input>
-                            </div>
-                            <div class="col-md-4">
-                            <!-- display errors and example text -->
-                            </div>
-                        </div>
-                        [% END %]
-                    [% END %]
-
-                    <div class="form-group row">
-                       <div class="col-md-6 offset-md-2">
-                            <a href="[% ctx.opac_root %]/home"
-                                class="btn btn-confirm">[% l('Go Back') %]</a>
-                            <input type="submit"
-                                value="[% l('Submit Registration') %]"
-                                class="btn btn-confirm" />
-                       </div>
-                    </div>
-            </form>
-            [% END %]
-        </div>
-    </div>
 [%- END %]
-<script>
-(function() {
-  'use strict';
-  window.addEventListener('load', function() {
-    // Fetch all the forms we want to apply custom Bootstrap validation styles to
-    var forms = document.getElementsByClassName('needs-validation');
-    // Loop over them and prevent submission
-    var validation = Array.prototype.filter.call(forms, function(form) {
-      form.addEventListener('submit', function(event) {
-        if (form.checkValidity() === false) {
-          event.preventDefault();
-          event.stopPropagation();
-        }
-        form.classList.add('was-validated');
-      }, false);
-    });
-  }, false);
-})();
-
-$(document).ready(function(){
-   $('.datepicker').datepicker({
-        weekStart: 1,
-        autoclose: true,
-        todayHighlight: true,
-    });
-    $('.datepicker').datepicker("setDate", "");
-});
-</script>
index 59577f6..292b44a 100644 (file)
@@ -3552,6 +3552,55 @@ label[for*=expert_]
     color: #00593d;
 }
 
+
+/*
+  Fake tables for form-rows
+*/
+
+div.egtable { display:table; }
+form.egtr, div.egtr { display:table-row; }
+span.egth { display:table-cell; font-weight: bold; }
+span.egtd { display:table-cell; }
+
+/* Example:
+
+<div class="egtable">
+    <form class="egtr" method="post" action="blah.html">
+        <span class="egtd"><input type="text"/></span>
+        <span class="egtd"><input type="text"/></span>
+    </form>
+    <div class="egtr">
+        <span class="egtd">(cell data)</span>
+        <span class="egtd">(cell data)</span>
+    </div>
+    ...
+</div>
+
+*/
+
+
+/* QUIPU CUSTOMIZATIONS */
+.radioLabel {
+    text-decoration: none;
+    color: #000;
+    padding-right: 10px;
+}
+
+.eCARDPreferredNameDivClass {
+    padding: 10px;
+    font-size: .9em;
+}
+
+.eCARDPatronNumber {
+    border:3px solid forestgreen;
+    padding:20px;max-width:700px;
+    font-weight:bold;
+    text-align:center;
+}
+
+
+
+
 @media only screen and (max-width: 1200px) {
     .carousel {
         margin-left:430px;
diff --git a/Open-ILS/src/templates/opac/ecard.tt2 b/Open-ILS/src/templates/opac/ecard.tt2
new file mode 100644 (file)
index 0000000..ef73140
--- /dev/null
@@ -0,0 +1,63 @@
+[%- PROCESS "opac/parts/header.tt2";
+    PROCESS "opac/parts/org_selector.tt2";
+    WRAPPER "opac/parts/base.tt2";
+    INCLUDE "opac/parts/topnav.tt2";
+    ctx.page_title = l("Request Library Card");
+%]
+
+<h2 class="sr-only">[% l('Account Registration') %]</h2>
+<div id="content-wrapper">
+    <div id="main-content-register">
+        <div class="common-full-pad"></div>
+            <div id="eCARDFiles">
+
+            <link href="https://ecard.quipugroup.net/css/eCARD.css" rel="stylesheet">
+
+            <link href="https://ecard.quipugroup.net/js/jqueryUI/css/ui-lightness/jquery-ui-1.10.4.custom.min.css" rel="stylesheet">
+
+            <script type="text/javascript" src="https://ecard.quipugroup.net/js/jquery-1.11.1.min.js"></script>
+
+            <script type="text/javascript" src="https://ecard.quipugroup.net/js/jqueryUI/js/jquery-ui-1.10.4.custom.min.js"></script>
+
+            <script type="text/javascript" src="https://ecard.quipugroup.net/js/jquery.xdomainrequest.min.js"></script>
+
+            <script type="text/javascript" src="https://ecard.quipugroup.net/js/jquery.PrintArea.js"></script>
+
+            <script type="text/javascript" src="https://ecard.quipugroup.net/js/jQuery-Mask-Plugin-master/dist/jquery.mask.min.js"></script>
+
+            <script type="text/javascript" src="https://ecard.quipugroup.net/js/eCARDMain2.js"></script>
+
+            <script type="text/javascript" src="https://ecard.quipugroup.net/Libraries/48/eCARDLibrary.js"></script>
+
+            </div>
+
+            <div id="pines_intro_inhouse" style="display:none;">
+            <h1>Welcome to PINES!</h1>
+                <p>Please fill out the form below to register for a PINES e-card. An e-card provides immediate access to your library's online resources.</p>
+
+                <p>If you'd like to upgrade to a full PINES card in order to check out library books and other materials, please bring your e-card account number and your photo ID to the library's circulation desk to complete the registration process.</p>
+            </div>
+
+            <div id="pines_intro_remote" style="display:none;">
+            <h1>Welcome to PINES!</h1>
+                <p>Please fill out the form below to register for a PINES e-card. An e-card provides immediate access to your library's online resources.</p>
+
+                <p>If you'd like to upgrade to a full PINES card in order to check out library books and other materials, please bring your e-card account number and your photo ID to any PINES library to complete the registration process. If you have any questions, please call your local library for assistance.</p>
+            </div>
+
+            <div id="eCARD" data-language="en" data-branchid="">
+
+
+            <!-- eCARD requires JavaScript in order to display the registration form -->
+            <!-- The following will detect if JavaScript is enabled on the patron's browser -->
+            <noscript>
+            <h2 style="color:red;">Warning - JavaScript Required</h2>
+            <p>For full functionality of this web page it is necessary to enable JavaScript in your browser. For more information on most browsers, try <a href="http://www.enable-javascript.com/" target="_blank">How to enable JavaScript</a> OR <a href="http://activatejavascript.org/en/instructions" target="_blank">activatejavascript.org</a><
+            </p>
+            </noscript>
+            </div>
+        
+        <div class="common-full-pad"></div>    
+    </div>
+</div>
+[%- END %]
diff --git a/Open-ILS/src/templates/opac/ecard/form.tt2 b/Open-ILS/src/templates/opac/ecard/form.tt2
new file mode 100644 (file)
index 0000000..909cb7a
--- /dev/null
@@ -0,0 +1,131 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>[% l('Get an eCard') %]</title>
+    [% INCLUDE 'opac/parts/googalytics_new.tt2' %]
+    [% INCLUDE 'opac/parts/goog_tag_manager.tt2' %]
+
+    <!-- NOTE: BootstrapCSS v4 does not play nicely with BC headers -->
+    <link rel="stylesheet" href="/js/ui/default/staff/build/css/bootstrap.min.css" />
+
+    <!-- QUIPU CSS -->
+    <link rel="stylesheet" href="https://ecard.quipugroup.net/css/eCARD.css">
+    <link rel="stylesheet"
+      href="https://ecard.quipugroup.net/js/jqueryUI/css/ui-lightness/jquery-ui-1.10.4.custom.min.css">
+    <!-- END QUIPU CSS -->
+
+    <!-- local CSS -->
+    <style>
+      /* BC screen reader links are not correctly hidden via their API.
+         Add some additional CSS to hide them */
+      .screen_reader_nav {
+        position: absolute;
+        top: -1000px;
+        left: -1000px;
+        z-index: 0;
+      }
+      #ecard-container-wrapper {
+        width: 98%;
+      }
+      #ecard-container {
+        margin-bottom: 20px;
+        color: #585d5e;
+        font-family: 'Open Sans', sans-serif;
+        letter-spacing: .5pt;
+        font-size: 15px;
+        width: 900px; /* to match bibliocms */
+        margin-left: auto;
+        margin-right: auto;
+      }
+    </style>
+
+    <!-- BC CSS -->
+    [% ctx.bc_css %]
+    <!-- BC END CSS -->
+
+  </head>
+  <body>
+
+    [% INCLUDE 'opac/parts/goog_tag_manager_noscript.tt2' %]
+
+    <!-- BC SCREEN READER NAVIGATION -->
+    [% ctx.bc_screen_reader_navigation %]
+    <!-- BC END SCREEN READER NAVIGATION -->
+
+    <!-- BC HEADER -->
+    [% ctx.bc_header %]
+    <!-- BC END HEADER -->
+
+    <div id='ecard-container-wrapper'>
+      <div id='ecard-container'>
+
+        <div id='ecard-preamble'>
+
+          <h1>Get a KCLS eCard</h1>
+
+          <p>
+            Please fill out the application below to get immediate 24/7
+            access to King County Library System’s online services
+            including e-books and audiobooks, movies and music, online
+            classes, exam prep and research databases, and magazines.
+          </p>
+          <!--
+          <p>
+            Please apply <a title="Get A Library Card"
+              href="https://w3.kcls.org/get-a-library-card">here</a>
+            if you would prefer a card with full library privileges 
+            including check out, computer use and printing.
+          </p>
+          -->
+          <p>
+            If your eCard application is successful we will mail
+            a confirmation letter to you in order to verify your
+            address. You must follow the instructions in the letter so
+            that the account remains open.
+          </p>
+          <p>
+            Want more information about the eCard and who qualifies to
+            use it? Read the <a href="https://kcls.org/faq/ecards/#ecards">FAQ</a>.
+          </p>
+          <p><b>KCLS eCard is not available to City of Seattle residents.</b></p>
+        </div>
+
+        <div id="eCARD" data-language="en" data-branchid="">
+          <!-- eCARD requires JavaScript in order to display the registration form -->
+          <!-- The following will detect if JavaScript is enabled on the patron's browser -->
+          <noscript>
+            <h2 style="color:red;">Warning - JavaScript Required</h2>
+            <p>
+             For full functionality of this web page it is necessary to enable 
+             JavaScript in your browser. For more information on most browsers, try 
+             <a href="http://www.enable-javascript.com/" target="_blank">How to enable JavaScript</a> 
+             OR <a href="http://activatejavascript.org/en/instructions" target="_blank">activatejavascript.org</a>
+            </p>
+          </noscript>
+        </div>
+      </div>
+    </div>
+
+    <!-- BC FOOTER -->
+    [% ctx.bc_footer %]
+    <!-- BC END FOOTER -->
+
+
+    <!-- QUIPU JS -->
+    <script type="text/javascript" src="https://ecard.quipugroup.net/js/jquery-1.11.1.min.js"></script>
+    <script type="text/javascript" src="https://ecard.quipugroup.net/js/jqueryUI/js/jquery-ui-1.10.4.custom.min.js"></script>
+    <script type="text/javascript" src="https://ecard.quipugroup.net/js/jquery.xdomainrequest.min.js"></script>
+    <script type="text/javascript" src="https://ecard.quipugroup.net/js/jquery.PrintArea.js"></script>
+    <script type="text/javascript" src="https://ecard.quipugroup.net/js/eCARDMain.js"></script>
+    <script type="text/javascript" src="https://ecard.quipugroup.net/Libraries/22/eCARDLibrary.js"></script>
+    <!-- END QUIPU JS -->
+
+    <!-- BC requires jquery, loaded from quipu (above) in this form -->
+    <!-- BC JS -->
+    [% ctx.bc_js %]
+    <!-- BC END JS -->
+
+  </body>
+</html>
+
diff --git a/Open-ILS/src/templates/opac/ecard/submit.tt2 b/Open-ILS/src/templates/opac/ecard/submit.tt2
new file mode 100644 (file)
index 0000000..ed3e58d
--- /dev/null
@@ -0,0 +1 @@
+[% ctx.response %]
diff --git a/Open-ILS/src/templates/opac/ecard/verify.tt2 b/Open-ILS/src/templates/opac/ecard/verify.tt2
new file mode 100644 (file)
index 0000000..08180ac
--- /dev/null
@@ -0,0 +1,153 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <title>[% l('Confirm an eCard Account') %]</title>
+    [% INCLUDE 'opac/parts/googalytics_new.tt2' %]
+
+    <link rel="stylesheet" href="/js/ui/default/staff/build/css/bootstrap.min.css" />
+
+    <!-- local CSS -->
+    <style>
+      /* BC screen reader links are not correctly hidden via their API.
+         Add some additional CSS to hide them */
+      .screen_reader_nav {
+        position: absolute;
+        top: -1000px;
+        left: -1000px;
+        z-index: 0;
+      }
+      #ecard-container-wrapper {
+        width: 98%;
+      }
+      #ecard-container {
+        margin-bottom: 20px;
+        color: #585d5e;
+        font-family: 'Open Sans', sans-serif;
+        letter-spacing: .5pt;
+        font-size: 15px;
+        width: 900px; /* to match bibliocms */
+        margin-left: auto;
+        margin-right: auto;
+      }
+    </style>
+
+    <script>
+      function handleSubmit() {
+        if (typeof ga === 'function') {
+          ga('send', 'event', 'Ecard Verify', 'submit', 'Forms');
+        }
+        return true;
+      }
+
+      function handleCancel() {
+        // unused at time of writing, keep around just in case.
+        if (typeof ga === 'function') {
+          ga('send', 'event', 'Ecard Verify', 'cancel', 'Forms');
+        }
+        return false; // avoid submit
+      }
+    </script>
+
+    <!-- BC CSS -->
+    [% ctx.bc_css %]
+    <!-- BC END CSS -->
+
+  </head>
+  <body>
+
+    <!-- BC SCREEN READER NAVIGATION -->
+    [% ctx.bc_screen_reader_navigation %]
+    <!-- BC END SCREEN READER NAVIGATION -->
+
+    <!-- BC HEADER -->
+    [% ctx.bc_header %]
+    <!-- BC END HEADER -->
+
+    <div id='ecard-container-wrapper' role="main">
+      <div id='ecard-container'>
+
+        <div id='ecard-preamble'>
+          <h1>Confirm Your KCLS eCard</h1>
+          <p>
+            Please fill out the form below to confirm your eCard account.
+          </p>
+          [% IF ctx.verify_failed %]
+          <div id='ecard-verify-failed'>
+            <div class="alert alert-warning" role="alert">
+              <p>
+                It appears that your confirmation did not go through.
+                This could happen for a variety of reasons:
+              </p>
+              <br/>
+              <ul>
+                <li>You mistyped the confirmation code</li>
+                <li>
+                  You typed in the code, but you provided it more than 30
+                  days after your application. If so, please feel free to reapply.
+                </li>
+                <li>You already confirmed, so your eCard is ready to use!</li>
+              </ul>
+              <br/>
+              <p>
+                If you have any questions about how to confirm your eCard
+                please contact <a href="https://kcls.org/ask/">Ask KCLS</a>
+                or staff at <a href="https://kcls.bibliocommons.com/locations">
+                your neighborhood library</a>.
+              </p>
+            </div>
+          </div>
+          [% END %]
+        </div>
+
+        [% IF ctx.verify_success %]
+        <div id='ecard-verify-success'>
+          <div class="alert alert-success" role="alert">
+            <p>
+            Congratulations! You have successfully confirmed your KCLS eCard!
+            </p>
+            <p>
+            <b>If you have not yet had a chance to find out what you can do with
+            your eCard, go to <a href="https://kcls.org/onlinelibrary">KCLS Online Resources</a>.
+            Read, stream, listen, find information, advance your studies, and enjoy!</b>
+            </p>
+          </div>
+        </div>
+        [% ELSE %]
+        <div id='ecard-verify-form' class='col-md-6'>
+          <form method='POST' onsubmit="return handleSubmit()">
+            <div class="form-group">
+              <label for="barcode">eCard Number</label>
+              <input type="text" class="form-control" id="barcode"
+                name="barcode" placeholder="eCard Number"
+                value="[% ctx.barcode | html %]"/>
+            </div>
+            <div class="form-group">
+              <label for="verification_code">6-Character Confirmation Code</label>
+              <input type="text" class="form-control" id="verification_code"
+                name="verification_code" placeholder="Confirmation Code"
+                value="[% ctx.verify_code | html %]"/>
+            </div>
+            <button type="submit" class="btn btn-default">Submit</button>
+          </form>
+        </div>
+        <div style="clear:both"></div>
+        [% END %]
+
+      </div>
+    </div>
+
+    <!-- BC FOOTER -->
+    [% ctx.bc_footer %]
+    <!-- BC END FOOTER -->
+
+    <!-- unlike the quipu form page, we have to manaully load jquery here -->
+    <script src="[% ctx.media_prefix %]/js/ui/default/common/build/js/jquery.min.js"></script>
+
+    <!-- BC JS -->
+    [% ctx.bc_js %]
+    <!-- BC END JS -->
+
+  </body>
+</html>
+
index 99c4b8f..ceae997 100644 (file)
@@ -1,38 +1,25 @@
 [% IF !ctx.is_staff %]
 <div id="footer-wrap">
 <div id="footer">
-    [% IF ctx.get_org_setting(
-        ctx.physical_loc || ctx.aou_tree.id, 'opac.allow_pending_user') %]
-    <a href="[% mkurl(ctx.opac_root _ '/register') %]">
-           <img alt="[% l('Request Library Card') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
-               [% l('Request Library Card') %]</a> &nbsp; &nbsp; &nbsp; &nbsp;
-    [% END %]
-    <!-- <a href="/eg/kpac/home">[% l("Kids Catalog") %]</a> &nbsp;|&nbsp; -->
-    <!-- <a href="http://pines.georgialibraries.org/pinesLocator/locator.html">[% l('Library Locations') %]</a> &nbsp;|&nbsp;-->
-    <!-- <a href="http://pines.georgialibraries.org/catalog-help">[% l('Help') %]</a> &nbsp;|&nbsp; -->
+
+<div id="footer-menu-wrapper">
     <a href="http://pines.georgialibraries.org/about">
-           <img alt="[% l('About PINES') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" /> [%- l('Learn More About PINES') %]</a> <!-- &nbsp;|&nbsp; -->
-        &nbsp; &nbsp; &nbsp; &nbsp;        
+        <img alt="[% l('About PINES') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" /> [%- l('Learn More About PINES') %]</a>
+        &nbsp; &nbsp; &nbsp; &nbsp;
     <a href="http://pines.georgialibraries.org/catalog-help">
         <img alt="[% l('Help') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
         [% l('Help') %]</a>
-        &nbsp; &nbsp; &nbsp; &nbsp;
-        
-    <!-- &nbsp;|&nbsp; -->
-    <!-- <a href="/">[% l('Dynamic catalog') -%]</a> &nbsp;|&nbsp; -->
-    <!-- [% gurl = mkurl(ctx.opac_root _ '/galileo', {}, 1) %]
-    <a href="[% gurl %]"> [% l('GALILEO') %] </a> -->
 </div>
 <div id="footer-menu-slim">
     <a href="/eg/opac/home">[% l("Home") %]</a><br/>
-       <a href="http://www.georgialibraries.org/lib/directories/pineslibdir.html">
-           [% l('Library Locations') %]</a><br/>
+    <a href="http://pines.georgialibraries.org/pinesLocator/locator.html">
+        [% l('Library Locations') %]</a><br/>
     <a href="/eg/kpac/home">
-           [% l("Kids' Catalog") %]</a><br/>
+        [% l("Kids' Catalog") %]</a><br/>
     [% IF ctx.get_org_setting(
         ctx.physical_loc || ctx.aou_tree.id, 'opac.allow_pending_user') %]
-    <a href="[% mkurl(ctx.opac_root _ '/register') %]">
-           [% l('Request Library Card') %]</a><br/>
+        <a href="[% mkurl(ctx.opac_root _ '/register') %]">
+        [% l('Request Library Card') %]</a><br/>
     [% END %]   
     [% IF ctx.physical_loc;
         # patron is at the branch, no redirect needed
         # send patron to galileo auth redirector
         gurl = mkurl(ctx.opac_root _ '/galileo', {}, 1);
     END %]
-   <a href="[% gurl %]">
-               [% l('GALILEO Research Databases') %]</a><br/>
-       <a href="http://pines.georgialibraries.org/about">
-           [%- l('Learn More About PINES') %]</a><br/>
+    <a href="[% gurl %]">
+        [% l('GALILEO Research Databases') %]</a><br/>
+    <a href="http://pines.georgialibraries.org/about">
+        [%- l('Learn More About PINES') %]</a><br/>
+    <a href="https://play.google.com/store/apps/details?id=net.kenstir.apps.pines">
+        PINES Android App</a><br/>
     <a href="http://pines.georgialibraries.org/catalog-help">
-               [% l('Help') %]</a>     
-               
-       <hr style="margin-top:20px;">
-</div> 
-       
+        [% l('Help') %]</a>
+
+    <hr style="margin-top:20px;">
+</div>
+
     [% IF ctx.timing %]
     <div id="timing">
         [% FOR event IN ctx.timing %]
                 alt="[% l('Evergreen') %]"
             />
         </a>
+
         <br/> <br/>
         <div style="float:left; margin:10px 10px 0px 0px;"><a href="http://www.imls.gov">
             <img src="[% ctx.media_prefix %]/images/IMLS-logo.jpg" style="border:none; width: 150px;" alt="IMLS"></a>
         </div>
-               <p style="font-weight:normal;font-style:italic;">
-        [% l('Funding Note') %]</p>            
+        <p style="font-weight:normal;font-style:italic;">
+        [% l('Funding Note') %]</p>
+
     </div>
 </div>
 </div>
index 2db429d..f931838 100644 (file)
@@ -1,35 +1,37 @@
 <div id="gold-links-holder">
     <div id="gold-links">
-    <div id="header-links">
-        <a href="/eg/opac/home">
-                   <img alt="[% l('PINES Home Page') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
-                   [% l("Home") %]</a>
-       <!--
-       [% IF ctx.get_org_setting(
-               ctx.physical_loc || ctx.aou_tree.id, 'opac.allow_pending_user') %]
-       <a href="[% mkurl(ctx.opac_root _ '/register') %]">[%
-               l('Apply for a PINES Library Card') %]</a> 
-       [% END %]
-       -->
-       <a href="http://pines.georgialibraries.org/pinesLocator/locator.html">
-           <img alt="[% l('Library Locations') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
-               [% l('Library Locations') %]</a>
-       <a href="/eg/kpac/home">
-           <img alt="[% l('Kids Catalog') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
-               [% l("Kids Catalog") %]</a> 
-    <a href="https://pines.georgialibraries.org/app">
-        <img alt="[% l('PINES App') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
-        [% l("Download the PINES App") %]</a>
-   [% IF ctx.physical_loc;
-        # patron is at the branch, no redirect needed
-        gurl = 'http://www.galileo.usg.edu/express';
-    ELSE;
-        # send patron to galileo auth redirector
-        gurl = mkurl(ctx.opac_root _ '/galileo', {}, 1);
-    END %]
-    <a href="[% gurl %]">
-        <img alt="[% l('GALILEO') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
-        [% l('GALILEO Virtual Library') %]</a>
-    </div>
+        <div id="header-links">
+            <a href="/eg/opac/home">
+                <img alt="[% l('PINES Home Page') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
+                [% l("Home") %]</a>
+            <a href="http://pines.georgialibraries.org/pinesLocator/locator.html">
+                <img alt="[% l('Library Locations') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
+                [% l('Library Locations') %]</a>
+            <a href="/eg/kpac/home">
+                <img alt="[% l('Kids Catalog') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
+                [% l("Kids Catalog") %]</a> 
+            <a href="https://pines.georgialibraries.org/app">
+                <img alt="[% l('PINES App') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
+                [% l("Download the PINES App") %]</a>
+            [% IF ctx.physical_loc;
+                # patron is at the branch, no redirect needed
+                gurl = 'http://www.galileo.usg.edu/express';
+            ELSE;
+                # send patron to galileo auth redirector
+                gurl = mkurl(ctx.opac_root _ '/galileo', {}, 1);
+            END %]
+            <a href="[% gurl %]">
+                <img alt="[% l('GALILEO') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
+                [% l('GALILEO Virtual Library') %]</a>
+            [% IF ctx.get_org_setting(
+                ctx.physical_loc || ctx.aou_tree.id, 'opac.allow_pending_user') %]
+                <a href="[% mkurl(ctx.opac_root _ '/register') %]">
+                    <img alt="[% l('Apply for a PINES Library Card') %]" src="[% ctx.media_prefix %]/images/pines-dot.png" />
+                    [% l('Apply for a PINES Library Card') %]</a>
+            [% END %]
+
+        </div>
     </div>
 </div>
+
+<div style="clear:both;" />
index 0f2ce52..f0acbcf 100644 (file)
     WRAPPER "opac/parts/base.tt2";
     INCLUDE "opac/parts/topnav.tt2";
     ctx.page_title = l("Request Library Card");
-
-# for privacy, reload the page after (default) 5 minutes
-refresh_time = ctx.register.settings.refresh_timeout || 300; 
-ctx.refresh = refresh_time _ '; ' _ ctx.opac_root _ '/home';
-
-# some useful variables and MACROs for display, 
-# field validation, and added info display
-
-ctx_org = ctx.physical_loc || ctx.search_ou || ctx.aou_tree.id;
-
-# list of the registration fields to (potentially) 
-# display in the order they should be shown
-
-# post_code is the only field below that is required in the database and
-# post_code is only required if an address is created.
-# To prevent any of these fields from showing locally, regardless org unit
-# settings, simply remove the fields from this list.  In the case of 
-# addresses, if all address fields are removed, no attempt at creating
-# an address will be made (and post_code will no longer be required).
-
-register_fields = [
-    {class => 'stgu',  name = 'first_given_name', label => l('First Name')},
-    {class => 'stgu',  name = 'second_given_name', label => l('Middle Name')},
-    {class => 'stgu',  name = 'family_name', label => l('Last Name')},
-    {class => 'stgu',  name = 'pref_first_given_name', label => l('Preferred First Name')},
-    {class => 'stgu',  name = 'pref_second_given_name', label => l('Preferred Middle Name')},
-    {class => 'stgu',  name = 'pref_family_name', label => l('Preferred Last Name')},
-    {class => 'stgma', name = 'street1', label => l('Street Address')},
-    {class => 'stgma', name = 'street2', label => l('Street Address (2)')},
-    {class => 'stgma', name = 'city', label => l('City')},
-    {class => 'stgma', name = 'county', label => l('County')},
-    {class => 'stgma', name = 'state', label => l('State')},
-    {class => 'stgma', name = 'post_code', label => l('Zip Code')},
-    {class => 'stgu',  name = 'dob', label => l('Date of Birth')},
-    {class => 'stgu',  name = 'day_phone', label => l('Phone Number')},
-    {class => 'stgu',  name = 'email', label => l('Email Address')}
-    {class => 'stgu',  name = 'usrname', label => l('Requested Username')}
-];
-
-# The dojo date widget in the patron edit UI only accepts default 
-# values in ISO8601 format.  It will not accept locale-shaped dates.
-IF !ctx.register.settings.stgu.dob.example;
-    ctx.register.settings.stgu.dob.example = l('YYYY-MM-DD or YYYY/MM/DD');
-END;
-
 %]
 
 <h2 class="sr-only">[% l('Account Registration') %]</h2>
 <div id="content-wrapper">
     <div id="main-content-register">
         <div class="common-full-pad"></div>
-        <h1>[% l('Request a Library Card')%]</h1>
-        <hr/>
-
-        [% IF ctx.register.success %]
-            <h3>[% l('Registration successful!') %]<h3>
-            <h4>[% l('Please see library staff to complete your registration.') %]</h4>
-
-            [% IF ctx.register.username_taken %]
-            <p>
-                [% |l %]
-                Note: The selected username may be in use by another patron.  
-                You may select another username when finalizing your 
-                registration or in the online catalog.
-                [% END %]
-            </p>
-            [% END %]
+            <div id="eCARDFiles">
 
-            <br/>
-            <p>
-                <a href="[% ctx.opac_root %]/home" 
-                    class="opac-button">[% l('Return to the Catalog') %]</a>
-            </p>
+            <link href="https://ecard.quipugroup.net/css/eCARD.css" rel="stylesheet">
+
+            <link href="https://ecard.quipugroup.net/js/jqueryUI/css/ui-lightness/jquery-ui-1.10.4.custom.min.css" rel="stylesheet">
+
+            <script type="text/javascript" src="https://ecard.quipugroup.net/js/jquery-1.11.1.min.js"></script>
+
+            <script type="text/javascript" src="https://ecard.quipugroup.net/js/jqueryUI/js/jquery-ui-1.10.4.custom.min.js"></script>
+
+            <script type="text/javascript" src="https://ecard.quipugroup.net/js/jquery.xdomainrequest.min.js"></script>
+
+            <script type="text/javascript" src="https://ecard.quipugroup.net/js/jquery.PrintArea.js"></script>
+
+            <script type="text/javascript" src="https://ecard.quipugroup.net/js/jQuery-Mask-Plugin-master/dist/jquery.mask.min.js"></script>
 
-        [% ELSIF ctx.register.error %]
-            <h3>[% l('A registration error has occurred') %]</h3>
-            <h4>[% l('Please see library staff to complete your registration.') %]</h4>
+            <script type="text/javascript" src="https://ecard.quipugroup.net/js/eCARDMain2.js"></script>
 
-            <br/>
-            <p>
-                <a href="[% ctx.opac_root %]/home" 
-                    class="opac-button">[% l('Return to the Catalog') %]</a>
+            <script type="text/javascript" src="https://ecard.quipugroup.net/Libraries/48/eCARDLibrary.js"></script>
+
+            </div>
+
+            <div id="pines_intro_inhouse" style="display:none;">
+            <h1>Welcome to PINES!</h1>
+                <p>Please fill out the form below to register for a PINES e-card. An e-card provides immediate access to your library's online resources.</p>
+
+                <p>If you'd like to upgrade to a full PINES card in order to check out library books and other materials, please bring your e-card account number and your photo ID to the library's circulation desk to complete the registration process.</p>
+            </div>
+
+            <div id="pines_intro_remote" style="display:none;">
+            <h1>Welcome to PINES!</h1>
+                <p>Please fill out the form below to register for a PINES e-card. An e-card provides immediate access to your library's online resources.</p>
+
+                <p>If you'd like to upgrade to a full PINES card in order to check out library books and other materials, please bring your e-card account number and your photo ID to any PINES library to complete the registration process. If you have any questions, please call your local library for assistance.</p>
+            </div>
+
+            <div id="eCARD" data-language="en" data-branchid="">
+
+
+            <!-- eCARD requires JavaScript in order to display the registration form -->
+            <!-- The following will detect if JavaScript is enabled on the patron's browser -->
+            <noscript>
+            <h2 style="color:red;">Warning - JavaScript Required</h2>
+            <p>For full functionality of this web page it is necessary to enable JavaScript in your browser. For more information on most browsers, try <a href="http://www.enable-javascript.com/" target="_blank">How to enable JavaScript</a> OR <a href="http://activatejavascript.org/en/instructions" target="_blank">activatejavascript.org</a><
             </p>
+            </noscript>
+            </div>
+        
+        <div class="common-full-pad"></div>    
 
-        [% ELSE %]
-
-        [% IF ctx.user %]
-            <!-- if the user is logged in, make it 
-                clear we are tracking the requestor -->
-            <h4>[% l('New account requested by [_1] [_2] [_3] [_4] [_5]',
-                    ctx.user.prefix, ctx.user.first_given_name,
-                    ctx.user.second_given_name, ctx.user.family_name,
-                    ctx.user.suffix
-                ) | html %]</h4>
-        [% END %]
-
-        [%
-            #prepopulate org selector on refresh or error
-            cgi_org = CGI.param('stgu.home_ou') | html;
-            IF cgi_org && ctx.register.valid_orgs.grep("^$cgi_org$").size;
-                prepopulate_org = cgi_org;
-            END
-        %]
-
-        <form method='POST' onSubmit="return dobValidate(document.getElementById('stgu.dob'))">
-            <table>
-                <tr>
-                    <td>
-                        <label for='stgu.home_ou'>[% l('Home Library') %]</label>
-                    </td>
-                    <td>[% INCLUDE build_org_selector 
-                            name='stgu.home_ou' 
-                            value=value || prepopulate_org || ctx_org
-                            can_have_users_only=1
-                            valid_org_list=ctx.register.valid_orgs
-                        %]<br/>
-                                               <div style="font-size:small;font-style:italic;">
-                            [% l("PINES Location Tip") %]
-                                           </div>
-                    </td>
-                    <td>
-                        [% IF ctx.register.invalid.bad_home_ou %]
-                        <span class='patron-reg-invalid'>
-                            [% l('Please select a valid library') %]
-                        </span>
-                        [% END %]
-                </tr>
-[%
-# <=== shifting code left for readability
-
-# render the table row for each of the register fields
-FOR field_def IN register_fields;
-    fclass = field_def.class;
-    fname = field_def.name;
-    orig_name = fname;
-
-    field_path = fclass _ "." _ fname;
-
-    IF fname.match('^pref_');
-        # Preferred name fields adopt most visibility, etc.
-        # settings from the primary name counterparts.
-        fname = fname.remove('^pref_');
-    END;
-
-    show = ctx.register.settings.$fclass.$fname.show;
-    require = ctx.register.settings.$fclass.$fname.require;
-    example = ctx.register.settings.$fclass.$fname.example;
-    value = ctx.register.values.$fclass.$fname;
-
-    invalid_require = ctx.register.invalid.$fclass.$fname.require;
-    invalid_regex = ctx.register.invalid.$fclass.$fname.regex;
-
-    IF orig_name.match('^pref_');
-        show = show || require;
-        require = 0; # pref name values never required
-    END;
-
-    NEXT UNLESS require OR show;
-%]
-<tr>
-    <td>
-        <label for='[% field_path %]'>[% field_def.label | html %]</label>
-    </td>
-    <td>
-        <input 
-            type='text'
-            id='[% field_path %]'
-            name='[% field_path %]'
-            value='[% value || CGI.param(field_path) | html %]'/>
-        [% IF require %]
-        <span class='patron-reg-invalid'>*</span>
-        [% END %]
-    </td>
-    <td>
-
-    <!-- display errors and example text -->
-
-    [% IF invalid_require %]
-        <span class='patron-reg-invalid'>
-            [% l('This field is required') %]
-        </span>
-    [% ELSIF invalid_regex %]
-        <span class='patron-reg-invalid'>
-            [% l('The value entered does not have the correct format') %]
-        </span>
-    [% END %]
-    [% IF example %]
-        <span class='patron-reg-extra'>
-            [% l('(Example: [_1])', example) %]
-        </span>
-    [% END %]
-
-    </td>
-</tr>
-[% END %]
-<!-- ====> shifting the code back to the right for context -->
-                    [% IF ctx.register.opt_in_settings.size > 0 %]
-                        [% FOR optin IN ctx.register.opt_in_settings %]
-                        <tr>
-                            <td><label for="stgs.[% optin.name | uri %]'">[% optin.label | html %]</label></td>
-                            <td>
-                                <input type='checkbox'
-                                    name='stgs.[% optin.name | uri %]'
-                                    id='stgs.[% optin.name | uri %]'
-                                    title="[% optin.label | html %]"
-                                ></input>
-                            </td>
-                            <td><!-- display errors and example text --></td>
-                        </tr>
-                        [% END %]
-                    [% END %]
-                    <tr>
-                        <td colspan='3'>
-                            <a href="[% ctx.opac_root %]/home" 
-                                class="opac-button">[% l('Go Back') %]</a>
-                            <input type="submit" 
-                                value="[% l('Submit Registration') %]" 
-                                class="opac-button" />
-                        </td>
-                    </tr>
-                </table>
-            </form>
-            [% END %]
-            <div class="common-full-pad"></div>        
-        </div>
     </div>
+</div>
 [%- END %]