From 32458ad85b11e517eca78ebb3aead3300e31b4b2 Mon Sep 17 00:00:00 2001 From: Bill Erickson <berick@esilibrary.com> Date: Fri, 17 Feb 2012 11:57:19 -0500 Subject: [PATCH] Copy Location Search Groups : TPac org unit selector Adds support for viewing and searching on copy location groups in the tpac. Groups appear within the org unit selector, when the selector is used in a search context. Groups display below the owning org unit similar to a child org unit. Groups are displayed for all org units that meet the following criteria: search org unit, physical location, patron home org unit, plus ancestors and descendents of each. To support this, TPac gets a new "locg" CGI parameter, which contains the org unit and copy location group. It takes the form org_id:group_id. The TPac mod_perl code will extract this value and popuplate the search_ou accordingly. For consistency, we also use ctx.search_ou instead of directly checking CGI.param('loc') within the template environment. This also includes a rewrite of the org_selector.tt2 template. It changes it from a recursive routine to a depth-first while loop. I did this mainly because the recursive approach was suffering from global variable clobbering in the template environment. In theory, this new approach should be faster as well. Signed-off-by: Bill Erickson <berick@esilibrary.com> Signed-off-by: Dan Scott <dan@coffeecode.net> --- .../src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm | 7 +- .../perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm | 4 + .../perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm | 64 ++++++++++++++-- Open-ILS/src/templates/opac/advanced.tt2 | 4 +- .../src/templates/opac/myopac/prefs_notify.tt2 | 2 +- .../src/templates/opac/parts/advanced/expert.tt2 | 1 - .../src/templates/opac/parts/advanced/search.tt2 | 2 +- Open-ILS/src/templates/opac/parts/org_selector.tt2 | 87 +++++++++++++++------- Open-ILS/src/templates/opac/parts/place_hold.tt2 | 2 +- .../src/templates/opac/parts/preserve_params.tt2 | 2 +- .../templates/opac/parts/record/copy_counts.tt2 | 2 +- .../src/templates/opac/parts/record/copy_table.tt2 | 2 +- .../src/templates/opac/parts/record/refworks.tt2 | 5 +- .../src/templates/opac/parts/record/series.tt2 | 2 +- .../src/templates/opac/parts/record/subjects.tt2 | 1 - Open-ILS/src/templates/opac/parts/searchbar.tt2 | 2 +- 16 files changed, 138 insertions(+), 51 deletions(-) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm index b1ffd40587..76b3f63353 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm @@ -251,10 +251,13 @@ sub load_common { return $self->load_logout($self->apache->unparsed_uri); } } - $ctx->{search_ou} = $self->_get_search_lib(); + $self->extract_copy_location_group_info; + $ctx->{search_ou} = $self->_get_search_lib(); $self->staff_saved_searches_set_expansion_state if $ctx->{is_staff}; $self->load_eg_cache_hash; + $self->load_copy_location_groups; + $self->staff_saved_searches_set_expansion_state if $ctx->{is_staff}; return Apache2::Const::OK; } @@ -303,8 +306,6 @@ sub get_physical_loc { return $self->cgi->cookie(COOKIE_PHYSICAL_LOC); } - - # ----------------------------------------------------------------------------- # Log in and redirect to the redirect_to URL (or home) # ----------------------------------------------------------------------------- diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm index b8907a6148..ecf8ef0b04 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Search.pm @@ -112,6 +112,10 @@ sub _prepare_biblio_search { $query .= " site($site)"; } + if (my $grp = $ctx->{copy_location_group}) { + $query .= " location_groups($grp)"; + } + if(!$site) { ($site) = ($query =~ /site\(([^\)]+)\)/); $site ||= $ctx->{aou_tree}->()->shortname; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm index f10ccb796c..e672eac1f7 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm @@ -280,28 +280,35 @@ sub fetch_marc_xml_by_id { sub _get_search_lib { my $self = shift; + my $ctx = $self->ctx; + + # avoid duplicate lookups + return $ctx->{search_ou} if $ctx->{search_ou}; + + my $loc = $ctx->{copy_location_group_org}; + return $loc if $loc; # loc param takes precedence - my $loc = $self->cgi->param('loc'); + $loc = $self->cgi->param('loc'); return $loc if $loc; - if ($self->ctx->{user}) { + if ($ctx->{user}) { # See if the user has a search library preference my $lset = $self->editor->search_actor_user_setting({ - usr => $self->ctx->{user}->id, + usr => $ctx->{user}->id, name => 'opac.default_search_location' })->[0]; return OpenSRF::Utils::JSON->JSON2perl($lset->value) if $lset; # Otherwise return the user's home library - return $self->ctx->{user}->home_ou; + return $ctx->{user}->home_ou; } if ($self->cgi->param('physical_loc')) { return $self->cgi->param('physical_loc'); } - return $self->ctx->{aou_tree}->()->id; + return $ctx->{aou_tree}->()->id; } # This is defensively coded since we don't do much manual reading from the @@ -340,4 +347,51 @@ sub load_eg_cache_hash { } } +# Extracts the copy location org unit and group from the +# "logc" param, which takes the form org_id:grp_id. +sub extract_copy_location_group_info { + my $self = shift; + my $ctx = $self->ctx; + if (my $clump = $self->cgi->param('locg')) { + my ($org, $grp) = split(/:/, $clump); + $ctx->{copy_location_group_org} = $org; + $ctx->{copy_location_group} = $grp if $grp; + } +} + +sub load_copy_location_groups { + my $self = shift; + my $ctx = $self->ctx; + + # User can access to the search location groups at the current + # search lib, the physical location lib, and the patron's home ou. + my @ctx_orgs = $ctx->{search_ou}; + push(@ctx_orgs, $ctx->{physical_loc}) if $ctx->{physical_loc}; + push(@ctx_orgs, $ctx->{user}->home_ou) if $ctx->{user}; + + my $grps = $self->editor->search_asset_copy_location_group([ + { + opac_visible => 't', + owner => { + in => { + select => {aou => [{ + column => 'id', + transform => 'actor.org_unit_full_path', + result_field => 'id', + }]}, + from => 'aou', + where => {id => \@ctx_orgs} + } + } + }, + {order_by => {acplg => 'pos'}} + ]); + + my %buckets; + push(@{$buckets{$_->owner}}, $_) for @$grps; + $ctx->{copy_location_groups} = \%buckets; +} + + + 1; diff --git a/Open-ILS/src/templates/opac/advanced.tt2 b/Open-ILS/src/templates/opac/advanced.tt2 index 17cb74f334..220c56fd20 100644 --- a/Open-ILS/src/templates/opac/advanced.tt2 +++ b/Open-ILS/src/templates/opac/advanced.tt2 @@ -1,9 +1,9 @@ -[%- PROCESS "opac/parts/header.tt2"; +[%- PROCESS "opac/parts/header.tt2"; WRAPPER "opac/parts/base.tt2"; INCLUDE "opac/parts/topnav.tt2"; ctx.page_title = l("Advanced Search"); pane = CGI.param("pane") || "advanced"; - loc = CGI.param("loc"); + loc = ctx.search_ou; -%] <div id="search-wrapper"> <div id="search-box"> diff --git a/Open-ILS/src/templates/opac/myopac/prefs_notify.tt2 b/Open-ILS/src/templates/opac/myopac/prefs_notify.tt2 index 7d23021774..aeaaa4118d 100644 --- a/Open-ILS/src/templates/opac/myopac/prefs_notify.tt2 +++ b/Open-ILS/src/templates/opac/myopac/prefs_notify.tt2 @@ -51,7 +51,7 @@ [% IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]' [% END %]/> </td> </tr> - [% IF ctx.get_org_setting(CGI.param('loc') OR ctx.aou_tree.id, 'sms.enable') == 1 %] + [% IF ctx.get_org_setting(ctx.search_ou, 'sms.enable') == 1 %] <tr> <td>[% l('Notify by Text by default when a hold is ready for pickup?') %]</td> <td> diff --git a/Open-ILS/src/templates/opac/parts/advanced/expert.tt2 b/Open-ILS/src/templates/opac/parts/advanced/expert.tt2 index 24fbd1c38c..da8bba6c5b 100644 --- a/Open-ILS/src/templates/opac/parts/advanced/expert.tt2 +++ b/Open-ILS/src/templates/opac/parts/advanced/expert.tt2 @@ -1,4 +1,3 @@ -[% loc = CGI.param("loc") %] <form action="[% ctx.opac_root %]/results" method="GET"> <div class="header_middle">[% l("Expert Search") %]</div> <input type="hidden" name="_special" value="1" /> diff --git a/Open-ILS/src/templates/opac/parts/advanced/search.tt2 b/Open-ILS/src/templates/opac/parts/advanced/search.tt2 index f14aaa8246..6b622216ec 100644 --- a/Open-ILS/src/templates/opac/parts/advanced/search.tt2 +++ b/Open-ILS/src/templates/opac/parts/advanced/search.tt2 @@ -67,7 +67,7 @@ <td valign='top'> <strong>[% l("Search Library") %]</strong><br /> [% PROCESS "opac/parts/org_selector.tt2"; - PROCESS build_org_selector name='loc' value=ctx.search_ou %] + PROCESS build_org_selector show_loc_groups=1 %] <div style="position:relative;top:7px;"> <input type='checkbox' name="modifier" value="available"[% CGI.param('modifier').grep('available').size ? ' checked="checked"' : '' %] diff --git a/Open-ILS/src/templates/opac/parts/org_selector.tt2 b/Open-ILS/src/templates/opac/parts/org_selector.tt2 index 96bdcbf9ca..a2c222e40f 100644 --- a/Open-ILS/src/templates/opac/parts/org_selector.tt2 +++ b/Open-ILS/src/templates/opac/parts/org_selector.tt2 @@ -1,33 +1,66 @@ [% - BLOCK build_org_selector_options; - disabled = ''; - selected = ''; - IF can_have_vols_only AND walker.ou_type.can_have_vols != 't'; - disabled = 'disabled="disabled"'; - ELSIF walker.id == value; - selected = 'selected="selected"'; - END; - IF ctx.is_staff || walker.opac_visible == 't'; -%] - <option value='[% walker.id | uri %]' [% selected %] [% disabled %]> - [% - pad = walker.ou_type.depth * 2; - FOR idx IN [0..pad]; ' '; END; - walker.name | html; - %] - </option> - [% FOR child IN walker.children; - PROCESS build_org_selector_options walker=child value=value; - END; +# Org Unit Selector Widget : +# PROCESS build_org_selector id='selector-id' name='selector-name' +# value=org_id show_loc_groups=1/0 can_have_vols_only=1/0 + +BLOCK build_org_selector; + node_stack = [{org => org_unit || ctx.aou_tree}]; + IF !name; + name = 'loc'; + IF show_loc_groups; name = 'locg'; END; + END; + IF !value; + value = ctx.search_ou; + IF show_loc_groups; + value = CGI.param('locg') || ctx.search_ou; END; END; + %] - # XXX TODO probably put this BLOCK somewhere else so it can be used widely. - # Org Unit Selector Widget : - # PROCESS build_org_selector id='selector-id' name='selector-name' - BLOCK build_org_selector; -%] <select [% IF id %] id='[% id %]' [% END %] name='[% name %]'> - [% PROCESS build_org_selector_options walker=(org_unit || ctx.aou_tree) value=value %] + [% + WHILE node_stack.size > 0; + node = node_stack.pop(); + org_unit = node.org; + loc_grp = node.loc_grp; + ou_id = org_unit.id; + disabled = ''; + selected = ''; + + NEXT UNLESS ctx.is_staff || org_unit.opac_visible == 't'; + + IF !loc_grp; + IF show_loc_groups; + FOR grp IN ctx.copy_location_groups.$ou_id.reverse; + node_stack.push({org => org_unit, loc_grp => grp}); + END; + END; + FOR child IN org_unit.children.reverse; + node_stack.push({org => child}); + END; + END; + + node_value = ou_id; + IF loc_grp; node_value = node_value _ ':' _ loc_grp.id; END; + + IF can_have_vols_only AND org_unit.ou_type.can_have_vols != 't'; + disabled = 'disabled="disabled"'; + ELSIF node_value == value; + selected = 'selected="selected"'; + END %] + + <option value='[% node_value %]' [% selected %] [% disabled %]> + [% + # loc_grp's are displayed as children of the current org + depth = org_unit.ou_type.depth; + IF loc_grp; depth = depth + 1; END; + pad = depth * 2; + FOR idx IN [0..pad]; ' '; END; + loc_grp ? loc_grp.name : org_unit.name | html ; + %] + </option> + [% + END; + %] </select> -[% END %] +[% END %] diff --git a/Open-ILS/src/templates/opac/parts/place_hold.tt2 b/Open-ILS/src/templates/opac/parts/place_hold.tt2 index bd95814ead..97ffe967e3 100644 --- a/Open-ILS/src/templates/opac/parts/place_hold.tt2 +++ b/Open-ILS/src/templates/opac/parts/place_hold.tt2 @@ -83,7 +83,7 @@ [% l('Phone Number:') %]<input type="text" name="phone_notify" [% setting = 'opac.default_phone'; IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]' [% END %]/> </blockquote> - [% IF ctx.get_org_setting(CGI.param('loc') OR ctx.aou_tree.id, 'sms.enable') == 1 %] + [% IF ctx.get_org_setting(ctx.search_ou, 'sms.enable') == 1 %] <input type="checkbox" name="sms_notify_checkbox" [% IF ctx.default_sms_notify %]checked="checked"[% END %]/> [% l('Yes, by Text Messaging') %]<br/> diff --git a/Open-ILS/src/templates/opac/parts/preserve_params.tt2 b/Open-ILS/src/templates/opac/parts/preserve_params.tt2 index 14fe5be62a..3517f58e31 100644 --- a/Open-ILS/src/templates/opac/parts/preserve_params.tt2 +++ b/Open-ILS/src/templates/opac/parts/preserve_params.tt2 @@ -1,6 +1,6 @@ [%- UNLESS params; - params = ['loc', 'query', 'qtype', 'sort']; + params = ['locg', 'loc', 'query', 'qtype', 'sort']; END; FOR param IN params; IF CGI.param(param); %] diff --git a/Open-ILS/src/templates/opac/parts/record/copy_counts.tt2 b/Open-ILS/src/templates/opac/parts/record/copy_counts.tt2 index 9d85ae7cb8..defa0ae3ab 100644 --- a/Open-ILS/src/templates/opac/parts/record/copy_counts.tt2 +++ b/Open-ILS/src/templates/opac/parts/record/copy_counts.tt2 @@ -10,7 +10,7 @@ <li> [% l('[quant,_1,copy,copies] at [_2].', ou_avail, ctx.get_aou(ou_id).name) | html %] - [%- IF ou_avail > 0 && ou_id != CGI.param('loc'); %] + [%- IF ou_avail > 0 && ou_id != ctx.search_ou; %] <a href="[% mkurl('', {loc => ou_id}); %]" title="[% l('Show copies at [_1]', ctx.get_aou(ou_id).name); %]"> [%- l('(Show)'); %]</a> diff --git a/Open-ILS/src/templates/opac/parts/record/copy_table.tt2 b/Open-ILS/src/templates/opac/parts/record/copy_table.tt2 index 8148dd934a..240f9703cd 100644 --- a/Open-ILS/src/templates/opac/parts/record/copy_table.tt2 +++ b/Open-ILS/src/templates/opac/parts/record/copy_table.tt2 @@ -54,7 +54,7 @@ END; org_name | html -%] </td> - <td header='copy_header_callnumber'>[% callnum | html %] [% IF ctx.get_org_setting(CGI.param('loc') OR ctx.aou_tree.id, 'sms.enable') == 1 %](<a href="[% mkurl(ctx.opac_root _ '/sms_cn', {copy_id => copy_info.id}) %]">Text</a>)[% END %]</td> + <td header='copy_header_callnumber'>[% callnum | html %] [% IF ctx.get_org_setting(ctx.search_ou, 'sms.enable') == 1 %](<a href="[% mkurl(ctx.opac_root _ '/sms_cn', {copy_id => copy_info.id}) %]">Text</a>)[% END %]</td> [%- IF has_parts == 'true' %] <td header='copy_header_part'>[% copy_info.part_label | html %]</td> [%- END %] diff --git a/Open-ILS/src/templates/opac/parts/record/refworks.tt2 b/Open-ILS/src/templates/opac/parts/record/refworks.tt2 index 928ce9026e..ed02a74e2c 100644 --- a/Open-ILS/src/templates/opac/parts/record/refworks.tt2 +++ b/Open-ILS/src/templates/opac/parts/record/refworks.tt2 @@ -1,9 +1,6 @@ [% # Default to the root of the org unit tree in the absence of a specific library - loc = ctx.aou_tree.id; - IF CGI.param('loc'); - loc = CGI.param('loc'); - END; + loc = ctx.search_ou; # Get the full name of the library ou_name = ctx.get_aou(loc).name | uri; diff --git a/Open-ILS/src/templates/opac/parts/record/series.tt2 b/Open-ILS/src/templates/opac/parts/record/series.tt2 index 06def160a0..4695768a6d 100644 --- a/Open-ILS/src/templates/opac/parts/record/series.tt2 +++ b/Open-ILS/src/templates/opac/parts/record/series.tt2 @@ -1,6 +1,6 @@ [% series_tags = ['440', '490', '800', '810', '811', '830', '694']; - loc = CGI.param('loc'); + loc = ctx.search_ou; %] [% BLOCK render_series; diff --git a/Open-ILS/src/templates/opac/parts/record/subjects.tt2 b/Open-ILS/src/templates/opac/parts/record/subjects.tt2 index a78bdef731..59e26a55c6 100644 --- a/Open-ILS/src/templates/opac/parts/record/subjects.tt2 +++ b/Open-ILS/src/templates/opac/parts/record/subjects.tt2 @@ -28,7 +28,6 @@ ]; BLOCK render_subject; - loc = CGI.param('loc') | uri; xpath = xpath || '//*[starts-with(@tag,"6")]'; FOR node IN ctx.marc_xml.findnodes(xpath); all_terms = []; diff --git a/Open-ILS/src/templates/opac/parts/searchbar.tt2 b/Open-ILS/src/templates/opac/parts/searchbar.tt2 index 3c12bd9268..d0fa8ea390 100644 --- a/Open-ILS/src/templates/opac/parts/searchbar.tt2 +++ b/Open-ILS/src/templates/opac/parts/searchbar.tt2 @@ -28,7 +28,7 @@ [%- END # autosuggest enabled %] /> </span> [%- INCLUDE "opac/parts/qtype_selector.tt2" id="qtype"; - l(' in '); PROCESS build_org_selector name='loc' value=ctx.search_ou; + l(' in '); PROCESS build_org_selector show_loc_groups=1 %] <span> <input id='search-submit-go' type="submit" value="[% l('Search') %]" alt="[% l('Search') %]" class="opac-button" -- 2.11.0