Updates to INSTALL.debian documentation for 3.2.
[koha.git] / C4 / VirtualShelves.pm
index 4a81632..715cace 100644 (file)
@@ -17,18 +17,43 @@ package C4::VirtualShelves;
 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 #
 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 #
-# You should have received a copy of the GNU General Public License along with
-# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
-# Suite 330, Boston, MA  02111-1307 USA
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 use strict;
 
 use strict;
-require Exporter;
+use warnings;
+
+use Carp;
 use C4::Context;
 use C4::Circulation;
 use C4::Context;
 use C4::Circulation;
-use vars qw($VERSION @ISA @EXPORT);
+use C4::Debug;
+use C4::Members;
+require C4::Auth;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+
+BEGIN {
+       # set the version for version checking
+       $VERSION = 3.02;
+       require Exporter;
+       @ISA    = qw(Exporter);
+       @EXPORT = qw(
+            &GetShelves &GetShelfContents &GetShelf
+            &AddToShelf &AddShelf
+            &ModShelf
+            &ShelfPossibleAction
+            &DelFromShelf &DelShelf
+            &GetBibliosShelves
+       );
+        @EXPORT_OK = qw(
+            &GetShelvesSummary &GetRecentShelves
+            &RefreshShelvesSummary &SetShelvesLimit
+        );
+}
+
 
 
-# set the version for version checking
-$VERSION = 3.00;
+my $dbh = C4::Context->dbh;
 
 =head1 NAME
 
 
 =head1 NAME
 
@@ -42,41 +67,23 @@ C4::VirtualShelves - Functions for manipulating Koha virtual virtualshelves
 
 This module provides functions for manipulating virtual virtualshelves,
 including creating and deleting virtualshelves, and adding and removing
 
 This module provides functions for manipulating virtual virtualshelves,
 including creating and deleting virtualshelves, and adding and removing
-items to and from virtualshelves.
+bibs to and from virtualshelves.
 
 =head1 FUNCTIONS
 
 
 =head1 FUNCTIONS
 
-=over 2
-
-=cut
-
-@ISA    = qw(Exporter);
-@EXPORT = qw(
-        &GetShelves &GetShelfContents &GetShelf
+=head2 GetShelves
 
 
-        &AddToShelf &AddToShelfFromBiblio &AddShelf
-
-        &ModShelf
-        &ShelfPossibleAction
-        &DelFromShelf &DelShelf
-);
-
-my $dbh = C4::Context->dbh;
-
-=item GetShelves
-
-  $shelflist = &GetShelves($owner, $mincategory);
+  ($shelflist, $totshelves) = &GetShelves($mincategory, $row_count, $offset, $owner);
   ($shelfnumber, $shelfhash) = each %{$shelflist};
 
   ($shelfnumber, $shelfhash) = each %{$shelflist};
 
-Looks up the virtual virtualshelves, and returns a summary. C<$shelflist>
-is a reference-to-hash. The keys are the virtualshelves numbers
-(C<$shelfnumber>, above), and the values (C<$shelfhash>, above) are
-themselves references-to-hash, with the following keys:
-
-C<mincategory> : 2 if the list is for "look". 3 if the list is for "Select virtualshelves for adding a virtual".
-virtualshelves of the owner are always selected, whatever the category
+Returns the number of shelves specified by C<$row_count> and C<$offset> as well as the total
+number of shelves that meet the C<$owner> and C<$mincategory> criteria.  C<$mincategory>,
+C<$row_count>, and C<$offset> are required. C<$owner> must be supplied when C<$mincategory> == 1.
+When C<$mincategory> is 2 or 3, supply undef as argument for C<$owner>.
+C<$shelflist>is a reference-to-hash. The keys are the virtualshelves numbers (C<$shelfnumber>, above),
+and the values (C<$shelfhash>, above) are themselves references-to-hash, with the following keys:
 
 
-=over 4
+=over
 
 =item C<$shelfhash-E<gt>{shelfname}>
 
 
 =item C<$shelfhash-E<gt>{shelfname}>
 
@@ -90,49 +97,124 @@ The number of virtuals on that virtualshelves.
 
 =cut
 
 
 =cut
 
-#'
-# FIXME - Wouldn't it be more intuitive to return a list, rather than
-# a reference-to-hash? The shelf number can be just another key in the
-# hash.
-
-sub GetShelves {
-    my ( $owner, $mincategory ) = @_;
-
+sub GetShelves ($$$$) {
+    my ($mincategory, $row_count, $offset, $owner) = @_;
+       my @params = ($owner, $mincategory, ($offset ? $offset : 0), $row_count);
+       my @params1 = ($owner, $mincategory);
+       if ($mincategory > 1) {
+               shift @params;
+               shift @params1;
+       }
+       my $total = _shelf_count($owner, $mincategory);
+    # grab only the shelves meeting the row_count/offset spec...
     my $query = qq(
         SELECT virtualshelves.shelfnumber, virtualshelves.shelfname,owner,surname,firstname,virtualshelves.category,virtualshelves.sortfield,
                count(virtualshelfcontents.biblionumber) as count
         FROM   virtualshelves
             LEFT JOIN   virtualshelfcontents ON virtualshelves.shelfnumber = virtualshelfcontents.shelfnumber
     my $query = qq(
         SELECT virtualshelves.shelfnumber, virtualshelves.shelfname,owner,surname,firstname,virtualshelves.category,virtualshelves.sortfield,
                count(virtualshelfcontents.biblionumber) as count
         FROM   virtualshelves
             LEFT JOIN   virtualshelfcontents ON virtualshelves.shelfnumber = virtualshelfcontents.shelfnumber
-            LEFT JOIN   borrowers ON virtualshelves.owner = borrowers.borrowernumber
-        WHERE  owner=? OR category>=?
+            LEFT JOIN   borrowers ON virtualshelves.owner = borrowers.borrowernumber );
+    $query .= ($mincategory == 1) ? "WHERE  owner=? AND category=?" : "WHERE category>=?";
+       $query .= qq(
         GROUP BY virtualshelves.shelfnumber
         GROUP BY virtualshelves.shelfnumber
-        ORDER BY virtualshelves.category, virtualshelves.shelfname, borrowers.firstname, borrowers.surname
-    );
-    my $sth = $dbh->prepare($query);
-    $sth->execute( $owner, $mincategory );
+        ORDER BY virtualshelves.category
+               DESC 
+               LIMIT ?, ?);
+    my $sth2 = $dbh->prepare($query);
+    $sth2->execute(@params);
     my %shelflist;
     my %shelflist;
-    while (
-        my (
-            $shelfnumber, $shelfname, $owner, $surname,
-            $firstname,   $category,  $sortfield, $count
-        )
-        = $sth->fetchrow
-      )
-    {
+    while ( my ( $shelfnumber, $shelfname, $owner, $surname,
+               $firstname,   $category,  $sortfield, $count ) = $sth2->fetchrow ) {
         $shelflist{$shelfnumber}->{'shelfname'} = $shelfname;
         $shelflist{$shelfnumber}->{'count'}     = $count;
         $shelflist{$shelfnumber}->{'shelfname'} = $shelfname;
         $shelflist{$shelfnumber}->{'count'}     = $count;
-        $shelflist{$shelfnumber}->{'sortfield'}     = $sortfield;
+        $shelflist{$shelfnumber}->{'sortfield'} = $sortfield;
         $shelflist{$shelfnumber}->{'category'}  = $category;
         $shelflist{$shelfnumber}->{'owner'}     = $owner;
         $shelflist{$shelfnumber}->{'category'}  = $category;
         $shelflist{$shelfnumber}->{'owner'}     = $owner;
-        $shelflist{$shelfnumber}->{'surname'}     = $surname;
-        $shelflist{$shelfnumber}->{'firstname'}   = $firstname;
+        $shelflist{$shelfnumber}->{'surname'}   = $surname;
+        $shelflist{$shelfnumber}->{'firstname'} = $firstname;
     }
     }
-    return ( \%shelflist );
+    return ( \%shelflist, $total );
+}
+
+=head2 GetShelvesSummary
+
+       ($shelves, $total) = GetShelvesSummary($mincategory, $row_count, $offset, $owner)
+
+Returns the number of shelves specified by C<$row_count> and C<$offset> as well as the total
+number of shelves that meet the C<$owner> and/or C<$mincategory> criteria. C<$mincategory>,
+C<$row_count>, and C<$offset> are required. C<$owner> must be supplied when C<$mincategory> == 1.
+When C<$mincategory> is 2 or 3, supply undef as argument for C<$owner>.
+
+=cut
+
+sub GetShelvesSummary ($$$$) {
+    my ($mincategory, $row_count, $offset, $owner) = @_;
+       my @params = ($owner, $mincategory, ($offset ? $offset : 0), $row_count);
+       my @params1 = ($owner, $mincategory);
+       if ($mincategory > 1) {
+               shift @params;
+               shift @params1;
+       }
+       my $total = _shelf_count($owner, $mincategory);
+    # grab only the shelves meeting the row_count/offset spec...
+       my $query = qq(
+               SELECT
+                       virtualshelves.shelfnumber,
+                       virtualshelves.shelfname,
+                       owner,
+                       CONCAT(firstname, ' ', surname) AS name,
+                       virtualshelves.category,
+                       count(virtualshelfcontents.biblionumber) AS count
+               FROM   virtualshelves
+                       LEFT JOIN  virtualshelfcontents ON virtualshelves.shelfnumber = virtualshelfcontents.shelfnumber
+                       LEFT JOIN             borrowers ON virtualshelves.owner = borrowers.borrowernumber );
+    $query .= ($mincategory == 1) ? "WHERE  owner=? AND category=?" : "WHERE category>=?";
+       $query .= qq(
+               GROUP BY virtualshelves.shelfnumber
+               ORDER BY virtualshelves.category
+               DESC 
+               LIMIT ?, ?);
+       my $sth2 = $dbh->prepare($query);
+       $sth2->execute(@params);
+    my $shelves = $sth2->fetchall_arrayref({});
+    return ($shelves, $total);
+
+       # Probably NOT the final implementation since it is still bulky (repeated hash keys).
+       # might like an array of rows of delimited values:
+       # 1|2||0|blacklist|112
+       # 2|6|Josh Ferraro|51|en_fuego|106
 }
 
 }
 
-=item GetShelf
+=head2 GetRecentShelves
+
+       ($shelflist) = GetRecentShelves(1, $limit, $owner)
 
 
-  (shelfnumber,shelfname,owner,category) = &GetShelf($shelfnumber);
+This function returns a references to an array of hashrefs containing specified shelves sorted
+by the date the shelf was last modified in descending order limited to the number of records
+specified by C<$row_count>. If calling with C<$mincategory> other than 1, use undef as C<$owner>.
+
+This function is intended to return a dataset reflecting the most recently active shelves for
+the submitted parameters.
+
+=cut
+
+sub GetRecentShelves ($$$) {
+       my ($mincategory, $row_count, $owner) = @_;
+    my (@shelflist);
+       my $total = _shelf_count($owner, $mincategory);
+       my @params = ($owner, $mincategory, 0, $row_count);      #FIXME: offset is hardcoded here, but could be passed in for enhancements
+       shift @params if (not defined $owner);
+       my $query = "SELECT * FROM virtualshelves";
+       $query .= ((defined $owner) ? " WHERE owner = ? AND category = ?" : " WHERE category >= ? ");
+       $query .= " ORDER BY lastmodified DESC LIMIT ?, ?";
+       my $sth = $dbh->prepare($query);
+       $sth->execute(@params);
+       @shelflist = $sth->fetchall_arrayref({});
+       return ( \@shelflist, $total );
+}
+
+=head2 GetShelf
+
+  (shelfnumber,shelfname,owner,category,sortfield) = &GetShelf($shelfnumber);
 
 Looks up information about the contents of virtual virtualshelves number
 C<$shelfnumber>
 
 Looks up information about the contents of virtual virtualshelves number
 C<$shelfnumber>
@@ -141,10 +223,10 @@ Returns the database's information on 'virtualshelves' table.
 
 =cut
 
 
 =cut
 
-sub GetShelf {
+sub GetShelf ($) {
     my ($shelfnumber) = @_;
     my $query = qq(
     my ($shelfnumber) = @_;
     my $query = qq(
-        SELECT shelfnumber,shelfname,owner,category,sortfield
+        SELECT shelfnumber, shelfname, owner, category, sortfield
         FROM   virtualshelves
         WHERE  shelfnumber=?
     );
         FROM   virtualshelves
         WHERE  shelfnumber=?
     );
@@ -153,9 +235,9 @@ sub GetShelf {
     return $sth->fetchrow;
 }
 
     return $sth->fetchrow;
 }
 
-=item GetShelfContents
+=head2 GetShelfContents
 
 
-  $itemlist = &GetShelfContents($shelfnumber);
+  $biblist = &GetShelfContents($shelfnumber);
 
 Looks up information about the contents of virtual virtualshelves number
 C<$shelfnumber>.  Sorted by a field in the biblio table.  copyrightdate 
 
 Looks up information about the contents of virtual virtualshelves number
 C<$shelfnumber>.  Sorted by a field in the biblio table.  copyrightdate 
@@ -164,37 +246,54 @@ gives a desc sort.
 Returns a reference-to-array, whose elements are references-to-hash,
 as returned by C<C4::Biblio::GetBiblioFromItemNumber>.
 
 Returns a reference-to-array, whose elements are references-to-hash,
 as returned by C<C4::Biblio::GetBiblioFromItemNumber>.
 
+Note: the notforloan status comes from the itemtype, and where it equals 0
+it does not ensure that related items.notforloan status is likewise 0. The
+caller has to check any items on their own, possibly with CanBookBeIssued
+from C4::Circulation.
+
 =cut
 
 =cut
 
-#'
-sub GetShelfContents {
-    my ( $shelfnumber ,$sortfield) = @_;
+sub GetShelfContents ($;$$$) {
+    my ($shelfnumber, $row_count, $offset, $sortfield) = @_;
     my $dbh=C4::Context->dbh();
     my $dbh=C4::Context->dbh();
+       my $sth1 = $dbh->prepare("SELECT count(*) FROM virtualshelfcontents WHERE shelfnumber = ?");
+       $sth1->execute($shelfnumber);
+       my $total = $sth1->fetchrow;
        if(!$sortfield) {
        if(!$sortfield) {
-               my $sthsort = $dbh->prepare('select sortfield from virtualshelves where shelfnumber=?');
-               $sthsort->execute($shelfnumber);
-               ($sortfield) = $sthsort->fetchrow_array;
+               my $sth2 = $dbh->prepare('SELECT sortfield FROM virtualshelves WHERE shelfnumber=?');
+               $sth2->execute($shelfnumber);
+               ($sortfield) = $sth2->fetchrow_array;
        }
        }
-       my @itemlist;
     my $query =
     my $query =
-       " SELECT vc.biblionumber,vc.shelfnumber,biblio.*
-         FROM   virtualshelfcontents vc LEFT JOIN biblio on vc.biblionumber=biblio.biblionumber
+       " SELECT vc.biblionumber, vc.shelfnumber, vc.dateadded, itemtypes.*,
+                               biblio.*, biblioitems.itemtype, biblioitems.publicationyear
+         FROM   virtualshelfcontents vc
+                LEFT JOIN biblio      ON      vc.biblionumber =      biblio.biblionumber
+                LEFT JOIN biblioitems ON  biblio.biblionumber = biblioitems.biblionumber
+                LEFT JOIN itemtypes   ON biblioitems.itemtype = itemtypes.itemtype
          WHERE  vc.shelfnumber=? ";
          WHERE  vc.shelfnumber=? ";
-    my @bind = ($shelfnumber);
+       my @params = ($shelfnumber);
        if($sortfield) {
        if($sortfield) {
-               #$sortfield = $dbh->quote($sortfield);
-               $query .= " ORDER BY `$sortfield` ";
+               $query .= " ORDER BY " . $sortfield;
                $query .= " DESC " if ($sortfield eq 'copyrightdate');
        }
                $query .= " DESC " if ($sortfield eq 'copyrightdate');
        }
-    my $sth = $dbh->prepare($query);
-    $sth->execute(@bind);
-    while ( my $item = $sth->fetchrow_hashref ) {
-        push( @itemlist, $item );
+    if($row_count){
+          $query .= " LIMIT ?, ? ";
+          push (@params, ($offset ? $offset : 0));
+          push (@params, $row_count);
     }
     }
-   return ( \@itemlist );
+    my $sth3 = $dbh->prepare($query);
+       $sth3->execute(@params);
+       return ($sth3->fetchall_arrayref({}), $total);
+       # Like the perldoc says,
+       # returns reference-to-array, where each element is reference-to-hash of the row:
+       #   like [ $sth->fetchrow_hashref(), $sth->fetchrow_hashref() ... ] 
+       # Suitable for use in TMPL_LOOP.
+       # See http://search.cpan.org/~timb/DBI-1.601/DBI.pm#fetchall_arrayref
+       # or newer, for your version of DBI.
 }
 
 }
 
-=item AddShelf
+=head2 AddShelf
 
   $shelfnumber = &AddShelf( $shelfname, $owner, $category);
 
 
   $shelfnumber = &AddShelf( $shelfname, $owner, $category);
 
@@ -208,7 +307,7 @@ Returns a code to know what's happen.
 =cut
 
 sub AddShelf {
 =cut
 
 sub AddShelf {
-    my ( $shelfname, $owner, $category ) = @_;
+    my ( $shelfname, $owner, $category, $sortfield ) = @_;
     my $query = qq(
         SELECT *
         FROM   virtualshelves
     my $query = qq(
         SELECT *
         FROM   virtualshelves
@@ -219,21 +318,21 @@ sub AddShelf {
     ( $sth->rows ) and return (-1);
     $query = qq(
         INSERT INTO virtualshelves
     ( $sth->rows ) and return (-1);
     $query = qq(
         INSERT INTO virtualshelves
-            (shelfname,owner,category)
-        VALUES (?,?,?)
+            (shelfname,owner,category,sortfield)
+        VALUES (?,?,?,?)
     );
     $sth = $dbh->prepare($query);
     );
     $sth = $dbh->prepare($query);
-    $sth->execute( $shelfname, $owner, $category );
+    $sth->execute( $shelfname, $owner, $category, $sortfield );
     my $shelfnumber = $dbh->{'mysql_insertid'};
     return ($shelfnumber);
 }
 
     my $shelfnumber = $dbh->{'mysql_insertid'};
     return ($shelfnumber);
 }
 
-=item AddToShelf
+=head2 AddToShelf
 
   &AddToShelf($biblionumber, $shelfnumber);
 
 
   &AddToShelf($biblionumber, $shelfnumber);
 
-Adds item number C<$biblionumber> to virtual virtualshelves number
-C<$shelfnumber>, unless that item is already on that shelf.
+Adds bib number C<$biblionumber> to virtual virtualshelves number
+C<$shelfnumber>, unless that bib is already on that shelf.
 
 =cut
 
 
 =cut
 
@@ -249,84 +348,72 @@ sub AddToShelf {
     my $sth = $dbh->prepare($query);
 
     $sth->execute( $shelfnumber, $biblionumber );
     my $sth = $dbh->prepare($query);
 
     $sth->execute( $shelfnumber, $biblionumber );
-    unless ( $sth->rows ) {
-        # already on shelf
-        my $query = qq(
-            INSERT INTO virtualshelfcontents
-                (shelfnumber, biblionumber, flags)
-            VALUES
-                (?, ?, 0)
-        );
-        $sth = $dbh->prepare($query);
-        $sth->execute( $shelfnumber, $biblionumber );
-    }
+    ($sth->rows) and return undef;     # already on shelf
+       $query = qq(
+               INSERT INTO virtualshelfcontents
+                       (shelfnumber, biblionumber, flags)
+               VALUES
+                       (?, ?, 0)
+       );
+       $sth = $dbh->prepare($query);
+       $sth->execute( $shelfnumber, $biblionumber );
+       $query = qq(UPDATE virtualshelves
+                               SET lastmodified = CURRENT_TIMESTAMP
+                               WHERE shelfnumber = ?);
+       $sth = $dbh->prepare($query);
+       $sth->execute( $shelfnumber );
 }
 
 }
 
-=item AddToShelfFromBiblio
-    &AddToShelfFromBiblio($biblionumber, $shelfnumber)
-
-    this function allow to add a virtual into the shelf number $shelfnumber
-    from biblionumber.
-
-=cut
-
-sub AddToShelfFromBiblio {
-    my ( $biblionumber, $shelfnumber ) = @_;
-    return unless $biblionumber;
-    my $query = qq(
-        SELECT *
-        FROM   virtualshelfcontents
-        WHERE  shelfnumber=? AND biblionumber=?
-    );
-    my $sth = $dbh->prepare($query);
-    $sth->execute( $shelfnumber, $biblionumber );
-    unless ( $sth->rows ) {
-        my $query =qq(
-            INSERT INTO virtualshelfcontents
-                (shelfnumber, biblionumber, flags)
-            VALUES
-                (?, ?, 0)
-        );
-        $sth = $dbh->prepare($query);
-        $sth->execute( $shelfnumber, $biblionumber );
-    }
-}
+=head2 ModShelf
 
 
-=item ModShelf
+ModShelf($shelfnumber, $hashref)
 
 
-ModShelf($shelfnumber, $shelfname, $owner, $category )
+Where $hashref->{column} = param
 
 
-Modify the value into virtualshelves table with values given on input arg.
+Modify the value into virtualshelves table with values given 
+from hashref, which each key of the hashref should be
+the name of a column of virtualshelves.
 
 =cut
 
 sub ModShelf {
 
 =cut
 
 sub ModShelf {
-    my ( $shelfnumber, $shelfname, $owner, $category, $sortfield ) = @_;
-    my $query = qq(
-        UPDATE virtualshelves
-        SET    shelfname=?,owner=?,category=?,sortfield=?
-        WHERE  shelfnumber=?
-    );
-       my $sth = $dbh->prepare($query);
-    $sth->execute( $shelfname, $owner, $category, $sortfield, $shelfnumber );
-}
+    my $shelfnumber = shift;
+    my $shelf = shift;
 
 
-=item DelShelf
+    if (exists $shelf->{shelfnumber}) {
+        carp "Should not use ModShelf to change shelfnumber";
+        return;
+    }
+    unless (defined $shelfnumber and $shelfnumber =~ /^\d+$/) {
+        carp "Invalid shelfnumber passed to ModShelf: $shelfnumber";
+        return;
+    }
 
 
-  ($status) = &DelShelf($shelfnumber);
+       my $query = "UPDATE virtualshelves SET ";
+    my @bind_params = ();
+    my @set_clauses = ();
 
 
-Deletes virtual virtualshelves number C<$shelfnumber>. The virtualshelves must
-be empty.
+       foreach my $column (keys %$shelf) {
+        push @set_clauses, "$column = ?";
+        push @bind_params, $shelf->{$column};
+    }
 
 
-Returns a two-element array, where C<$status> is 0 if the operation
-was successful, or non-zero otherwise. C<$msg> is "Done" in case of
-success, or an error message giving the reason for failure.
+    if ($#set_clauses == -1) {
+        carp "No columns to update passed to ModShelf";
+        return;
+    }
+    $query .= join(", ", @set_clauses);
 
 
-=cut
+    $query .= " WHERE shelfnumber = ? ";
+    push @bind_params, $shelfnumber;
 
 
+    $debug and warn "ModShelf query:\n $query\n",
+                       "ModShelf query args: ", join(',', @bind_params), "\n";
+       my $sth = $dbh->prepare($query);
+       $sth->execute( @bind_params );
+}
 
 
-=item ShelfPossibleAction
+=head2 ShelfPossibleAction
 
 ShelfPossibleAction($loggedinuser, $shelfnumber, $action);
 
 
 ShelfPossibleAction($loggedinuser, $shelfnumber, $action);
 
@@ -349,17 +436,22 @@ sub ShelfPossibleAction {
     my $sth = $dbh->prepare($query);
     $sth->execute($shelfnumber);
     my ( $owner, $category ) = $sth->fetchrow;
     my $sth = $dbh->prepare($query);
     $sth->execute($shelfnumber);
     my ( $owner, $category ) = $sth->fetchrow;
-    return 1 if (($category >= 3 or $owner eq $user) && $action eq 'manage' );
-    return 1 if (($category >= 2 or $owner eq $user) && $action eq 'view' );
+       my $borrower = GetMemberDetails($user);
+       return 0 if not defined($user);
+       return 1 if ( $category >= 3);                                                  # open list
+    return 1 if (($category >= 2) and
+                               defined($action) and $action eq 'view');        # public list, anybody can view
+    return 1 if (($category >= 2) and defined($user) and ($borrower->{authflags}->{superlibrarian} || $user == 0));    # public list, superlibrarian can edit/delete
+    return 1 if (defined($user)  and $owner  eq $user );       # user owns this list.  Check last.
     return 0;
 }
 
     return 0;
 }
 
-=item DelFromShelf
+=head2 DelFromShelf
 
   &DelFromShelf( $biblionumber, $shelfnumber);
 
 
   &DelFromShelf( $biblionumber, $shelfnumber);
 
-Removes item number C<$biblionumber> from virtual virtualshelves number
-C<$shelfnumber>. If the item wasn't on that virtualshelves to begin with,
+Removes bib number C<$biblionumber> from virtual virtualshelves number
+C<$shelfnumber>. If the bib wasn't on that virtualshelves to begin with,
 nothing happens.
 
 =cut
 nothing happens.
 
 =cut
@@ -375,33 +467,132 @@ sub DelFromShelf {
     $sth->execute( $shelfnumber, $biblionumber );
 }
 
     $sth->execute( $shelfnumber, $biblionumber );
 }
 
-=head2 DelShelf
+=head2 DelShelf (old version)
+
+  ($status, $msg) = &DelShelf($shelfnumber);
+
+Deletes virtual virtualshelves number C<$shelfnumber>. The virtualshelves must
+be empty.
+
+Returns a two-element array, where C<$status> is 0 if the operation
+was successful, or non-zero otherwise. C<$msg> is "Done" in case of
+success, or an error message giving the reason for failure.
+
+=head2 DelShelf (current version)
 
   $Number = DelShelf($shelfnumber);
 
 
   $Number = DelShelf($shelfnumber);
 
-    this function delete the shelf number, and all of it's content
+This function deletes the shelf number, and all of it's content.
 
 =cut
 
 
 =cut
 
-#'
 sub DelShelf {
 sub DelShelf {
-       my ( $shelfnumber ) = @_;
+       unless (@_) {
+               carp "DelShelf called without valid argument (shelfnumber)";
+               return undef;
+       }
        my $sth = $dbh->prepare("DELETE FROM virtualshelves WHERE shelfnumber=?");
        my $sth = $dbh->prepare("DELETE FROM virtualshelves WHERE shelfnumber=?");
-       $sth->execute($shelfnumber);
-       return 0;
+       return $sth->execute(shift);
 }
 
 }
 
-END { }    # module clean-up code here (global destructor)
+=head2 GetBibShelves
+
+This finds all the public lists that this bib record is in.
+
+=cut
+
+sub GetBibliosShelves {
+    my ( $biblionumber )  = @_;
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare('
+        SELECT vs.shelfname, vs.shelfnumber 
+        FROM virtualshelves vs 
+        JOIN virtualshelfcontents vc ON (vs.shelfnumber= vc.shelfnumber) 
+        WHERE vs.category != 1 
+        AND vc.biblionumber= ?
+    ');
+    $sth->execute( $biblionumber );
+    return $sth->fetchall_arrayref({});
+}
+
+=head2 RefreshShelvesSummary
+
+       ($total, $pubshelves, $barshelves) = RefreshShelvesSummary($sessionID, $loggedinuser, $row_count);
+
+Updates the current session and userenv with the most recent shelves
+
+Returns the total number of shelves stored in the session/userenv along with two references each to an
+array of hashes, one containing the C<$loggedinuser>'s private shelves and one containing all public/open shelves.
+
+This function is used in conjunction with the 'Lists' button in masthead.inc.
+
+=cut
+
+sub RefreshShelvesSummary ($$$) {
+       
+       my ($sessionID, $loggedinuser, $row_count) = @_;
+       my $session = C4::Auth::get_session($sessionID);
+       my ($total, $totshelves, $barshelves, $pubshelves);
+
+       ($barshelves, $totshelves) = GetRecentShelves(1, $row_count, $loggedinuser);
+       $total->{'bartotal'} = $totshelves;
+       ($pubshelves, $totshelves) = GetRecentShelves(2, $row_count, undef);
+       $total->{'pubtotal'} = $totshelves;
+
+       # Update the current session with the latest shelves...
+       $session->param('barshelves', $barshelves->[0]);
+       $session->param('pubshelves', $pubshelves->[0]);
+       $session->param('totshelves', $total);
+
+       # likewise the userenv...
+       C4::Context->set_shelves_userenv('bar',$barshelves->[0]);
+       C4::Context->set_shelves_userenv('pub',$pubshelves->[0]);
+       C4::Context::set_shelves_userenv('tot',$total);
+
+       return ($total, $pubshelves, $barshelves);
+}
+
+# internal subs
+
+sub _shelf_count ($$) {
+       my (@params) = @_;
+       # Find out how many shelves total meet the submitted criteria...
+       my $query = "SELECT count(*) FROM virtualshelves";
+       $query .= ($params[1] > 1) ? " WHERE category >= ?" : " WHERE  owner=? AND category=?";
+       shift @params if $params[1] > 1;
+       my $sth = $dbh->prepare($query);
+       $sth->execute(@params);
+       my $total = $sth->fetchrow;
+       return $total;
+}
+
+sub _biblionumber_sth {
+    my ($shelf) = @_;
+    my $query = 'select biblionumber from virtualshelfcontents where shelfnumber = ?';
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare($query)
+       or die $dbh->errstr;
+    $sth->execute( $shelf )
+       or die $sth->errstr;
+    $sth;
+}
+
+sub each_biblionumbers (&$) {
+    my ($code,$shelf) = @_;
+    my $ref =  _biblionumber_sth($shelf)->fetchall_arrayref;
+    map {
+       $_=$$_[0];
+       $code->();
+    } @$ref;
+}
 
 1;
 
 __END__
 
 
 1;
 
 __END__
 
-=back
-
 =head1 AUTHOR
 
 =head1 AUTHOR
 
-Koha Developement team <info@koha.org>
+Koha Development Team <http://koha-community.org/>
 
 =head1 SEE ALSO
 
 
 =head1 SEE ALSO