From 350859ce788a3d0402cee29b4b3a26561750f5a8 Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Mon, 6 May 2013 09:44:01 -0400 Subject: [PATCH] Bug 10278 - Add ability to hide items and records from search results for Independent Branches For the staff intranet, enabling IndependentBranchesRecordsAndItems will automatically add a branch limit filter to the search results thus hiding all records without one or more items owned by the logged in library. In add addition, all items whose homebranch is not that libraries will be filtered and hidden from the search results and record details. This system preference will not affect the OPAC, unless the environment variable BRANCHCODE is defined in the koha-httpd.conf file. If it is defined, the same filters are applied to the OPAC, but based on the branchcode value of the environment variable BRANCHCODE, rather than the logged in branch. Test Plan: 1) Apply patch 2) Run updatedatabase.pl 3) Perform a search that will give results for both records which have items owned by the logged in library, and records which have no items owned by the logged in library. 4) Enable the new system preference IndependentBranchesRecordesAndItems 5) Perform the same search again, any records without items owned by the currently logged in library should not appear. Signed-off-by: Joel Sasse --- C4/Auth.pm | 2 +- C4/Branch.pm | 80 ++++++++++++++++++++++++++++++++++++++--------- C4/Context.pm | 3 +- C4/Items.pm | 10 +++++- C4/Search.pm | 71 +++++++++++++++++++++++++++++++++++++++++ C4/Serials.pm | 4 ++ catalogue/search.pl | 20 +++-------- cataloguing/addbooks.pl | 3 +- cataloguing/additem.pl | 42 +++++++++++++------------ 9 files changed, 182 insertions(+), 53 deletions(-) diff --git a/C4/Auth.pm b/C4/Auth.pm index 22f1e8e..ffc4521 100644 --- a/C4/Auth.pm +++ b/C4/Auth.pm @@ -758,7 +758,7 @@ sub checkauth { $session->param('surname'), $session->param('branch'), $session->param('branchname'), $session->param('flags'), $session->param('emailaddress'), $session->param('branchprinter'), - $session->param('persona'), $session->param('shibboleth') + $session->param('persona'), $session->param('shibboleth'), $type ); C4::Context::set_shelves_userenv( 'bar', $session->param('barshelves') ); C4::Context::set_shelves_userenv( 'pub', $session->param('pubshelves') ); diff --git a/C4/Branch.pm b/C4/Branch.pm index 4a73e24..e26e953 100644 --- a/C4/Branch.pm +++ b/C4/Branch.pm @@ -42,6 +42,7 @@ BEGIN { &GetCategoryTypes &GetBranchCategories &GetBranchesInCategory + &GetCategoriesForBranch &ModBranchCategoryInfo &GetIndependentGroupModificationRights &DelBranch @@ -108,6 +109,7 @@ Create a branch selector with the following code. sub GetBranches { my ($onlymine) = @_; + $onlymine ||= onlymine(); # returns a reference to a hash of references to ALL branches... my %branches; @@ -429,6 +431,39 @@ sub GetBranchesInCategory { return( \@branches ); } +=head2 GetCategoriesForBranch + + my @categories = GetCategoriesForBranch({ + branchcode => $branchcode, + categorytype => 'independent_group' + }); + + Called in a list context, returns an array of branch category codes + that branch is part of. + + Called in a scalar context, returns an array ref. + +=cut + +sub GetCategoriesForBranch { + my ( $params ) = @_; + my $branchcode = $params->{branchcode}; + my $categorytype = $params->{categorytype} || '%'; + + carp("Missing branchcode parameter!") unless ( $branchcode ); + + my $sql = q{ + SELECT categorycode FROM branchrelations + JOIN branchcategories USING ( categorycode ) + WHERE branchcode = ? + AND categorytype = ? + }; + + my $categories = C4::Context->dbh->selectcol_arrayref( $sql, {}, ( $branchcode, $categorytype ) ); + + return wantarray() ? $categories : @$categories; +} + =head2 GetIndependentGroupModificationRights GetIndependentGroupModificationRights( @@ -463,29 +498,44 @@ sub GetBranchesInCategory { sub GetIndependentGroupModificationRights { my ($params) = @_; - my $this_branch = $params->{branch}; - my $other_branch = $params->{for}; + my $this_branch = $params->{branch} ||= q{}; + my $other_branch = $params->{for} ||= q{}; + $this_branch ||= $ENV{BRANCHCODE}; $this_branch ||= C4::Context->userenv->{branch}; - carp("No branch found!") unless ($this_branch); + unless ($this_branch) { + carp("No branch found!"); + return; + } return 1 if ( $this_branch eq $other_branch ); - my $sql = q{ - SELECT DISTINCT(branchcode) - FROM branchrelations - JOIN branchcategories USING ( categorycode ) - WHERE categorycode IN ( - SELECT categorycode - FROM branchrelations - WHERE branchcode = ? - ) - AND branchcategories.categorytype = 'independent_group' - }; + my $allow_all = 0; + $allow_all = 1 if C4::Context->IsSuperLibrarian(); + $allow_all = 1 if C4::Context->userenv->{type} eq 'opac' && !$ENV{BRANCHCODE}; + my $sql; my @params; - push( @params, $this_branch ); + + if ( $allow_all ) { + $sql = q{ + SELECT branchcode FROM branches WHERE 1 + } + } else { + $sql = q{ + SELECT DISTINCT(branchcode) + FROM branchrelations + JOIN branchcategories USING ( categorycode ) + WHERE categorycode IN ( + SELECT categorycode + FROM branchrelations + WHERE branchcode = ? + ) + AND branchcategories.categorytype = 'independent_group' + }; + push( @params, $this_branch ); + } if ($other_branch) { $sql .= q{ AND branchcode = ? }; diff --git a/C4/Context.pm b/C4/Context.pm index 274522e..5cb41ab 100644 --- a/C4/Context.pm +++ b/C4/Context.pm @@ -1100,7 +1100,7 @@ set_userenv is called in Auth.pm #' sub set_userenv { shift @_; - my ($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $branchname, $userflags, $emailaddress, $branchprinter, $persona, $shibboleth)= + my ($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $branchname, $userflags, $emailaddress, $branchprinter, $persona, $shibboleth, $type)= map { Encode::is_utf8( $_ ) ? $_ : Encode::decode('UTF-8', $_) } # CGI::Session doesn't handle utf-8, so we decode it here @_; my $var=$context->{"activeuser"} || ''; @@ -1118,6 +1118,7 @@ sub set_userenv { "branchprinter" => $branchprinter, "persona" => $persona, "shibboleth" => $shibboleth, + "type" => $type, }; $context->{userenv}->{$var} = $cell; return $cell; diff --git a/C4/Items.pm b/C4/Items.pm index 2520ded..b93f089 100644 --- a/C4/Items.pm +++ b/C4/Items.pm @@ -1281,6 +1281,11 @@ If this is set, it is set to C. sub GetItemsInfo { my ( $biblionumber ) = @_; + + my $IndependentBranchesRecordsAndItems = + C4::Context->preference('IndependentBranchesRecordsAndItems') + && !C4::Context->IsSuperLibrarian(); + my $dbh = C4::Context->dbh; # note biblioitems.* must be avoided to prevent large marc and marcxml fields from killing performance. my $query = " @@ -1326,7 +1331,10 @@ sub GetItemsInfo { LEFT JOIN serial USING (serialid) LEFT JOIN itemtypes ON itemtypes.itemtype = " . (C4::Context->preference('item-level_itypes') ? 'items.itype' : 'biblioitems.itemtype'); - $query .= " WHERE items.biblionumber = ? ORDER BY home.branchname, items.enumchron, LPAD( items.copynumber, 8, '0' ), items.dateaccessioned DESC" ; + $query .= " WHERE items.biblionumber = ? "; + $query .= " AND items.homebranch IN ( " . GetIndependentGroupModificationRights({ stringify => 1}) . " ) " if ( $IndependentBranchesRecordsAndItems ); + $query .= " ORDER BY home.branchname, items.enumchron, LPAD( items.copynumber, 8, '0' ), items.dateaccessioned DESC" ; + my $sth = $dbh->prepare($query); $sth->execute($biblionumber); my $i = 0; diff --git a/C4/Search.pm b/C4/Search.pm index f93dd15..5524e6d 100644 --- a/C4/Search.pm +++ b/C4/Search.pm @@ -36,6 +36,7 @@ use URI::Escape; use Business::ISBN; use MARC::Record; use MARC::Field; +use List::MoreUtils qw(none); use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG); # set the version for version checking @@ -303,6 +304,20 @@ sub SimpleSearch { $zoom_query->destroy(); } + if ( C4::Context->preference('IndependentBranchesRecordsAndItems') ) { + my @new_results; + my $dbh = C4::Context->dbh(); + foreach my $result ( @{$results} ) { + my $marc_record = MARC::Record->new_from_usmarc($result); + my $koha_record = TransformMarcToKoha( $dbh, $marc_record ); + my $is_allowed = $koha_record->{branchcode} ? GetIndependentGroupModificationRights( { for => $koha_record->{branchcode} } ) : 1; + + push( @new_results, $result ) if ( $is_allowed ); + } + $results = \@new_results; + $total_hits = scalar( @new_results ); + } + return ( undef, $results, $total_hits ); } @@ -1741,6 +1756,29 @@ sub buildQuery { $limit .= "($availability_limit)"; } + if ( C4::Context->preference('IndependentBranchesRecordsAndItems') ) { + my $search_context = C4::Context->userenv->{type}; + my $IndependentBranchesRecordsAndItems; + if ( $search_context eq 'opac' ) { + # For the OPAC, if IndependentBranchesRecordsAndItems is enabled, + # and BRANCHCODE has been set in the httpd conf, + # we need to filter the items + $IndependentBranchesRecordsAndItems = $ENV{BRANCHCODE}; + } + else { + # For the intranet, if IndependentBranchesRecordsAndItems is enabled, + # and the user is not a superlibrarian, + # we need to filter the items + $IndependentBranchesRecordsAndItems = !C4::Context->IsSuperLibrarian(); + } + my @allowed_branches = $IndependentBranchesRecordsAndItems ? GetIndependentGroupModificationRights() : (); + + if ( @allowed_branches ) { + $limit .= " and " if ( $query || $limit ); + $limit .= "(" . join( " or ", map { "branch:$_" } @allowed_branches ) . ")"; + } + } + # Normalize the query and limit strings # This is flawed , means we can't search anything with : in it # if user wants to do ccl or cql, start the query with that @@ -2052,14 +2090,47 @@ sub searchResults { my $maxitems = $maxitems_pref ? $maxitems_pref - 1 : 1; my @hiddenitems; # hidden itemnumbers based on OpacHiddenItems syspref + my $IndependentBranchesRecordsAndItems; + if ( $search_context eq 'opac' ) { + # For the OPAC, if IndependentBranchesRecordsAndItems is enabled, + # and BRANCHCODE has been set in the httpd conf, + # we need to filter the items + $IndependentBranchesRecordsAndItems = + C4::Context->preference('IndependentBranchesRecordsAndItems') + && $ENV{BRANCHCODE}; + } + else { + # For the intranet, if IndependentBranchesRecordsAndItems is enabled, + # and the user is not a superlibrarian, + # we need to filter the items + $IndependentBranchesRecordsAndItems = + C4::Context->preference('IndependentBranchesRecordsAndItems') + && !C4::Context->IsSuperLibrarian(); + } + my @allowed_branches = $IndependentBranchesRecordsAndItems ? GetIndependentGroupModificationRights() : undef; + # loop through every item + my $index = -1; foreach my $field (@fields) { + $index++; my $item; # populate the items hash foreach my $code ( keys %subfieldstosearch ) { $item->{$code} = $field->subfield( $subfieldstosearch{$code} ); } + + # if IndependentBranchesRecordsAndItems is enabled, and this record + # isn't allowed to be viewed, remove it from the items list and go + # right to the next item. + if ( $IndependentBranchesRecordsAndItems ) { + if ( none { $_ eq $item->{homebranch} } @allowed_branches ) { + splice(@fields, $index, 1); + $items_count--; + next; + } + } + $item->{description} = $itemtypes{ $item->{itype} }{description}; # OPAC hidden items diff --git a/C4/Serials.pm b/C4/Serials.pm index c295645..7ccb62a 100644 --- a/C4/Serials.pm +++ b/C4/Serials.pm @@ -765,6 +765,10 @@ sub SearchSubscriptions { push @where_strs, "subscription.closed = ?"; push @where_args, "$args->{closed}"; } + if( C4::Context->preference('IndependentBranchesRecordsAndItems') && !C4::Context->IsSuperlibrarian() ) { + my $branches = GetIndependentGroupModificationRights( { stringify => 1 } ); + push @where_strs, "subscription.branchcode IN ( $branches )"; + } if(@where_strs){ $query .= " WHERE " . join(" AND ", @where_strs); } diff --git a/catalogue/search.pl b/catalogue/search.pl index d25e19e..3e3688a 100755 --- a/catalogue/search.pl +++ b/catalogue/search.pl @@ -135,6 +135,8 @@ Not yet completed... use strict; # always use #use warnings; FIXME - Bug 2505 +use List::MoreUtils qw(any); + ## STEP 1. Load things that are used in both search page and # results page and decide which template to load, operations # to perform, etc. @@ -233,20 +235,10 @@ my $branches = GetBranches(); # Populate branch_loop with all branches sorted by their name. If # IndependentBranches is activated, set the default branch to the borrower # branch, except for superlibrarian who need to search all libraries. -my $user = C4::Context->userenv; -my @branch_loop = map { - { - value => $_, - branchname => $branches->{$_}->{branchname}, - selected => $user->{branch} eq $_ && C4::Branch::onlymine(), - } -} sort { - $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} -} keys %$branches; - -my $categories = GetBranchCategories('searchdomain'); - -$template->param(branchloop => \@branch_loop, searchdomainloop => $categories); +$template->param( + branchloop => GetBranchesLoop(), + searchdomainloop => GetBranchCategories( undef, 'searchdomain' ), +); # load the Type stuff my $itemtypes = GetItemTypes; diff --git a/cataloguing/addbooks.pl b/cataloguing/addbooks.pl index 54a1208..c089f6b 100755 --- a/cataloguing/addbooks.pl +++ b/cataloguing/addbooks.pl @@ -95,11 +95,12 @@ if ($query) { # SimpleSearch() give the results per page we want, so 0 offet here my $total = @{$marcresults}; my @newresults = searchResults( 'intranet', $query, $total, $results_per_page, 0, 0, $marcresults ); + my $q = $input->param('q'); $template->param( total => $total_hits, query => $query, resultsloop => \@newresults, - pagination_bar => pagination_bar( "/cgi-bin/koha/cataloguing/addbooks.pl?q=$query&", getnbpages( $total_hits, $results_per_page ), $page, 'page' ), + pagination_bar => pagination_bar( "/cgi-bin/koha/cataloguing/addbooks.pl?q=$q&", getnbpages( $total_hits, $results_per_page ), $page, 'page' ), ); } diff --git a/cataloguing/additem.pl b/cataloguing/additem.pl index 6c01bd5..9e7ec1c 100755 --- a/cataloguing/additem.pl +++ b/cataloguing/additem.pl @@ -708,6 +708,10 @@ if ( C4::Context->preference('EasyAnalyticalRecords') ) { } } +my $IndependentBranches = !C4::Context->IsSuperLibrarian() + && C4::Context->preference('IndependentBranches'); +my $IndependentBranchesRecordsAndItems = $IndependentBranches + && C4::Context->preference('IndependentBranchesRecordsAndItems'); foreach my $field (@fields) { next if ( $field->tag() < 10 ); @@ -731,15 +735,13 @@ foreach my $field (@fields) { || $subfieldvalue; } - if ( $field->tag eq $branchtagfield - && $subfieldcode eq $branchtagsubfield - && C4::Context->preference("IndependentBranches") ) + if ( $IndependentBranches + && $field->tag eq $branchtagfield + && $subfieldcode eq $branchtagsubfield ) { #verifying rights - my $userenv = C4::Context->userenv(); unless ( - C4::Context->IsSuperLibrarian() - || GetIndependentGroupModificationRights( + GetIndependentGroupModificationRights( { for => $subfieldvalue } ) ) @@ -747,24 +749,24 @@ foreach my $field (@fields) { $this_row{'nomod'} = 1; } } - $this_row{itemnumber} = $subfieldvalue if ($field->tag() eq $itemtagfield && $subfieldcode eq $itemtagsubfield); - if ( C4::Context->preference('EasyAnalyticalRecords') ) { - foreach my $hostitemnumber (@hostitemnumbers){ - if ($this_row{itemnumber} eq $hostitemnumber){ - $this_row{hostitemflag} = 1; - $this_row{hostbiblionumber}= GetBiblionumberFromItemnumber($hostitemnumber); - last; - } - } + $this_row{itemnumber} = $subfieldvalue if ($field->tag() eq $itemtagfield && $subfieldcode eq $itemtagsubfield); -# my $countanalytics=GetAnalyticsCount($this_row{itemnumber}); -# if ($countanalytics > 0){ -# $this_row{countanalytics} = $countanalytics; -# } - } + if ( C4::Context->preference('EasyAnalyticalRecords') ) { + foreach my $hostitemnumber (@hostitemnumbers) { + if ( $this_row{itemnumber} eq $hostitemnumber ) { + $this_row{hostitemflag} = 1; + $this_row{hostbiblionumber} = + GetBiblionumberFromItemnumber($hostitemnumber); + last; + } + } + } } + + next if ( $this_row{'nomod'} && $IndependentBranchesRecordsAndItems ); + if (%this_row) { push(@big_array, \%this_row); } -- 1.7.2.5