From 63b133d3b72580e5b8dbf57558d4cb5439bf6e7d Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Fri, 2 Aug 2013 17:20:07 -0400 Subject: [PATCH] LP1207396 Patron self-registration web form Signed-off-by: Bill Erickson --- .../lib/OpenILS/WWW/EGCatLoader/Register.pm | 108 ++++++++- Open-ILS/src/templates/opac/register.tt2 | 245 +++++++++------------ 2 files changed, 213 insertions(+), 140 deletions(-) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Register.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Register.pm index b2265b1bc9..9d8d48d3c6 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Register.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Register.pm @@ -4,6 +4,7 @@ use Apache2::Const -compile => qw(OK FORBIDDEN HTTP_INTERNAL_SERVER_ERROR); use OpenSRF::Utils::Logger qw/$logger/; use OpenILS::Utils::Fieldmapper; use OpenILS::Application::AppUtils; +use OpenILS::Utils::CStoreEditor qw/:funcs/; use OpenILS::Event; use Data::Dumper; $Data::Dumper::Indent = 0; @@ -14,6 +15,7 @@ sub load_patron_reg { my $ctx = $self->ctx; my $cgi = $self->cgi; $ctx->{register} = {}; + $self->collect_register_validation_settings; # just loading the form return Apache2::Const::OK @@ -25,7 +27,7 @@ sub load_patron_reg { # user foreach (grep /^stgu\./, $cgi->param) { my $val = $cgi->param($_); - # TODO validate + $self->inspect_register_value($_, $val); s/^stgu\.//g; $user->$_($val); } @@ -33,11 +35,14 @@ sub load_patron_reg { # address foreach (grep /^stgma\./, $cgi->param) { my $val = $cgi->param($_); - # TODO validate + $self->inspect_register_value($_, $val); s/^stgma\.//g; $addr->$_($val); } + # At least one value was invalid. Exit early and re-render. + return Apache2::Const::OK if $ctx->{register}{invalid}; + # user.stage.create will generate a temporary usrname and # link the user and address objects via this username in the DB. my $resp = $U->simplereq( @@ -59,3 +64,102 @@ sub load_patron_reg { return Apache2::Const::OK; } + +sub collect_register_validation_settings { + my $self = shift; + my $ctx = $self->ctx; + my $e = new_editor(); + my $ctx_org = $ctx->{physical_loc} || $self->_get_search_lib; + my $shash = $self->{register}{settings} = {}; + + # retrieve the org unit setting types and values + # that are relevant to our validation tasks. + + my $settings = $e->json_query({ + select => {coust => ['name']}, + from => 'coust', + where => {name => {like => 'ui.patron.edit.%.%.%'}} + }); + + # load org setting values for all of the regex, + # example, show, and require settings + for my $set (@$settings) { + $set = $set->{name}; + next unless $set =~ /regex$|show$|require$|example$/; + + my $val = $ctx->{get_org_setting}->($ctx_org, $set); + next unless $val; # no configured org setting + + # extract the field class, name, and + # setting type from the setting name + my (undef, undef, undef, $cls, $field, $type) = split(/\./, $set); + + # translate classes into stage classes + my $scls = ($cls eq 'au') ? 'stgu' : 'stgma'; + + $shash->{$scls}{$field}{$type} = $val; + } + + # use the generic phone settings where none are provided for day_phone. + + $shash->{stgu}{day_phone}{example} = + $ctx->{get_org_setting}->($ctx_org, 'ui.patron.edit.phone.example') + unless $shash->{stgu}{day_phone}{example}; + + $shash->{stgu}{day_phone}{regex} = + $ctx->{get_org_setting}->($ctx_org, 'ui.patron.edit.phone.regex') + unless $shash->{stgu}{day_phone}{regex}; + + # some fields are assumed to be visible / required even without the + # presence of org unit settings. E.g. we obviously want the user to + # enter a name, since a name is required for ultimately creating a user + # account. We can mimic that by forcing some org unit setting values + + $shash->{stgu}{first_given_name}{require} = 1 + unless defined $shash->{stgu}{first_given_name}{require}; + $shash->{stgu}{second_given_name}{show} = 1 + unless defined $shash->{stgu}{second_given_name}{show}; + $shash->{stgu}{family_name}{require} = 1 + unless defined $shash->{stgu}{family_name}{require}; + $shash->{stgma}{street1}{require} = 1 + unless defined $shash->{stgma}{street1}{require}; + $shash->{stgma}{city}{require} = 1 + unless defined $shash->{stgma}{city}{require}; + $shash->{stgma}{post_code}{require} = 1 + unless defined $shash->{stgma}{post_code}{require}; + + $ctx->{register}{settings} = $shash; +} + +# inspects each value and determines, based on org unit settings, +# if the value is invalid. Invalid is defined as not providing +# a value when one is required or not matching the configured regex. +sub inspect_register_value { + my ($self, $field_path, $value) = @_; + my $ctx = $self->ctx; + my ($scls, $field) = split(/\./, $field_path); + + if (!$value) { + + if ($self->{register}{settings}{$scls}{$field}{require}) { + $ctx->{register}{invalid}{$scls}{$field}{require} = 1; + + $logger->info("patron register field $field ". + "requires a value, but none was entered"); + } + return; + } + + my $regex = $self->{register}{settings}{$scls}{$field}{regex}; + return if !$regex or $value =~ /$regex/; # field is valid + + $logger->info("invalid value was provided for patron ". + "register field=$field; pattern=$regex; value=$value"); + + $ctx->{register}{invalid}{$scls}{$field}{regex} = 1; + + return; +} + + + diff --git a/Open-ILS/src/templates/opac/register.tt2 b/Open-ILS/src/templates/opac/register.tt2 index 6ebfe477c7..4ecc65592f 100644 --- a/Open-ILS/src/templates/opac/register.tt2 +++ b/Open-ILS/src/templates/opac/register.tt2 @@ -2,154 +2,124 @@ PROCESS "opac/parts/org_selector.tt2"; WRAPPER "opac/parts/base.tt2"; INCLUDE "opac/parts/topnav.tt2"; - ctx.page_title = l("Request Library Card") %] -
-
-
-

[% l('Request a Library Card')%]

-
+ ctx.page_title = l("Request Library Card"); - [% IF ctx.register.success %] -

[% |l %] - Registration successful! Please see library staff to - complete your registration. - [% END %]

- [% ELSIF ctx.register.error %] -

[% |l %] - An registration error has occurred. Please see library staff. - [% END %]

+# some useful variables and MACROs for display, +# field validation, and added info display - [% ELSE; - ctx_org = ctx.physical_loc || ctx.search_ou || ctx.aou_tree.id ; +ctx_org = ctx.physical_loc || ctx.search_ou || ctx.aou_tree.id; - addr_required = ctx.get_org_setting(ctx_org, - 'ui.patron.registration.require_address'); +# list of the registration fields to (potentially) +# display in the order they should be shown - # true if the selected field is required - MACRO require_field(cls, field_name) BLOCK; - sname = "ui.patron.edit.${cls}.${field_name}.require"; - IF ctx.get_org_setting(ctx_org, sname); 1; ELSE; 0; END; - END; +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 = 'family_name', label => l('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')} +]; +%] - # true if the selected field should be shown - MACRO show_field(cls, field_name) BLOCK; - sname = "ui.patron.edit.${cls}.${field_name}.show"; - IF require_field(cls, field_name) || - ctx.get_org_setting(ctx_org, sname); 1; ELSE; 0; END; - END; +
+
+
+

[% l('Request a Library Card')%]

+
- # indicate whether a field is optional; display example text - MACRO show_field_extras(cls, field_name, test_req, test_ex) BLOCK; - required = 0; - example = ''; + [% IF ctx.register.success %] +

[% |l %] + Registration successful! Please see library staff to + complete your registration. + [% END %]

- sname = "ui.patron.edit.${cls}.${field_name}.example"; - IF test_ex; - example = ctx.get_org_setting(ctx_org, sname); + [% ELSIF ctx.register.error %] +

[% |l %] + An registration error has occurred. Please see library staff. + [% END %]

- # day_phone is a special case, since there is a both - # a day_phone example and generic phone example - IF field_name == 'day_phone' AND !example; - sname = 'ui.patron.edit.phone.example'; - example = ctx.get_org_setting(ctx_org, sname); - END; - END; - - SET required = require_field(cls, field_name) IF test_req; - IF example; - IF required; - l('(Example: [_1])', example); - ELSE; - l('(Optional, Example: [_1])', example); - END; - ELSIF !required; - l('(Optional)'); - END; - END; - %] + [% ELSE %] -
- - - - - - - - - - - - - - - - - - + +
[% l('Home Library') %][% INCLUDE build_org_selector - # TODO: limit to orgs where pending-allowed - name='stgu.home_ou' - value=ctx_org - can_have_users_only=1 - %] -
[% l('First Name') %]
[% l('Middle Name') %]
[% l('Last Name') %]
+ + + + + +[% +# <=== shifting code left for readability - [% IF addr_required # --------------------------------- %] - - - - - - - - - - - - - - [% IF show_field('aua', 'state') %] - - - - - - [% END %] - - - - - - [% IF show_field('aua', 'county') %] - - - - - - [% END %] - [% END # addr_required -------------------------------- %] +# render the table row for each of the register fields +FOR field_def IN register_fields; + fclass = field_def.class; + fname = field_def.name; + field_path = fclass _ "." _ fname; - [% IF show_field('au', 'dob') %] - - - - - - [% END %] - [% IF show_field('au', 'day_phone') %] - - - - - - [% END %] - [% IF show_field('au', 'email') %] - - - - - - [% END %] + show = ctx.register.settings.$fclass.$fname.show; + require = ctx.register.settings.$fclass.$fname.require; + example = ctx.register.settings.$fclass.$fname.example; + + invalid_require = ctx.register.invalid.$fclass.$fname.require; + invalid_regex = ctx.register.invalid.$fclass.$fname.regex; + + NEXT UNLESS require OR show; +%] + + + + + + +[% END; +# ====> shifting the code back to the right for context %]
+ + [% INCLUDE build_org_selector + # TODO: limit to orgs where pending-allowed + name='stgu.home_ou' + value=ctx_org + can_have_users_only=1 + %] +
[% l('Street Address') %]
[% l('Street Address (2)') %][% l('(Optional)') %]
[% l('City') %]
[% l('State') %][% show_field_extras('aua', 'state', 1) %]
[% l('Post/Zip Code') %][% show_field_extras('aua', 'post_code', 0, 1) %]
[% l('County') %][% show_field_extras('aua', 'county', 1) %]
[% l('Date of Birth') %][% show_field_extras('au', 'dob', 1) %]
[% l('Phone Number') %][% show_field_extras('au', 'day_phone', 1, 1) %]
[% l('Email Address') %][% show_field_extras('au', 'email', 1, 1) %]
+ + + + +[% + # display wether the field is optional and any example text + + IF example; + IF require; + l('(Example: [_1])', example); + ELSE; + l('(Optional, Example: [_1])', example); + END; + ELSIF !require; + l('(Optional)'); + END; +%] + + [% IF invalid_require %] + + [% l('This field is required') %] + + [% ELSIF invalid_regex %] + + [% l('The provided value does not have the correct format') %] + + [% END %] +
[% END %] -
-- 2.11.0