1 package C4::VirtualShelves;
3 # Copyright 2000-2002 Katipo Communications
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
28 use constant SHELVES_MASTHEAD_MAX => 10; #number under Lists button in masthead
29 use constant SHELVES_COMBO_MAX => 10; #add to combo in search
30 use constant SHELVES_MGRPAGE_MAX => 20; #managing page
31 use constant SHELVES_POPUP_MAX => 40; #addbybiblio popup
33 use constant SHARE_INVITATION_EXPIRY_DAYS => 14; #two weeks to accept
35 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
38 # set the version for version checking
39 $VERSION = 3.07.00.049;
43 &GetShelves &GetShelfContents
54 C4::VirtualShelves - Functions for manipulating Koha virtual shelves
58 use C4::VirtualShelves;
62 This module provides functions for manipulating virtual shelves,
63 including creating and deleting virtual shelves, and adding and removing
64 bibs to and from virtual shelves.
70 $shelflist = &GetShelves($category, $row_count, $offset, $owner);
71 ($shelfnumber, $shelfhash) = each %{$shelflist};
73 Returns the number of shelves specified by C<$row_count> and C<$offset> as well as the total
74 number of shelves that meet the C<$owner> and C<$category> criteria. C<$category>,
75 C<$row_count>, and C<$offset> are required. C<$owner> must be supplied when C<$category> == 1.
76 When C<$category> is 2, supply undef as argument for C<$owner>.
78 This function is used by shelfpage in VirtualShelves/Page.pm when listing all shelves for lists management in opac or staff client. Order is by shelfname.
80 C<$shelflist>is a reference-to-hash. The keys are the virtualshelves numbers (C<$shelfnumber>, above),
81 and the values (C<$shelfhash>, above) are themselves references-to-hash, with the following keys:
85 =item C<$shelfhash-E<gt>{shelfname}>
87 A string. The name of the shelf.
94 my ($category, $row_count, $offset, $owner) = @_;
96 my @params = ( $offset, $row_count );
97 my $dbh = C4::Context->dbh;
99 SELECT vs.shelfnumber, vs.shelfname,vs.owner,
100 bo.surname,bo.firstname,vs.category,vs.sortfield,
101 count(vc.biblionumber) as count
102 FROM virtualshelves vs
103 LEFT JOIN borrowers bo ON vs.owner=bo.borrowernumber
104 LEFT JOIN virtualshelfcontents vc USING (shelfnumber) };
107 LEFT JOIN virtualshelfshares sh ON sh.shelfnumber=vs.shelfnumber
108 AND sh.borrowernumber=?
109 WHERE category=1 AND (vs.owner=? OR sh.borrowernumber=?) };
110 unshift @params, ($owner) x 3;
113 $query.= 'WHERE category=2 ';
116 GROUP BY vs.shelfnumber
117 ORDER BY vs.shelfname
120 my $sth2 = $dbh->prepare($query);
121 $sth2->execute(@params);
123 while( my ($shelfnumber, $shelfname, $owner, $surname, $firstname, $category, $sortfield, $count)= $sth2->fetchrow) {
124 $shelflist{$shelfnumber}->{'shelfname'} = $shelfname;
125 $shelflist{$shelfnumber}->{'count'} = $count;
126 $shelflist{$shelfnumber}->{'single'} = $count==1;
127 $shelflist{$shelfnumber}->{'sortfield'} = $sortfield;
128 $shelflist{$shelfnumber}->{'category'} = $category;
129 $shelflist{$shelfnumber}->{'owner'} = $owner;
130 $shelflist{$shelfnumber}->{'surname'} = $surname;
131 $shelflist{$shelfnumber}->{'firstname'} = $firstname;
136 =head2 GetSomeShelfNames
138 Returns shelf names and numbers for Add to combo of search results and Lists button of OPAC header.
142 sub GetSomeShelfNames {
143 my ($owner, $purpose, $adding_allowed)= @_;
144 my ($bar, $pub, @params);
145 my $dbh = C4::Context->dbh;
147 my $bquery = 'SELECT vs.shelfnumber, vs.shelfname FROM virtualshelves vs ';
148 my $limit= ShelvesMax($purpose);
150 my $qry1= $bquery."WHERE vs.category=2 ";
151 $qry1.= "AND (allow_add=1 OR owner=?) " if $adding_allowed;
152 push @params, $owner||0 if $adding_allowed;
153 $qry1.= "ORDER BY vs.lastmodified DESC LIMIT $limit";
155 unless($adding_allowed && (!defined($owner) || $owner<=0)) {
156 #if adding items, user should be known
157 $pub= $dbh->selectall_arrayref($qry1,{Slice=>{}},@params);
161 my $qry2= $bquery. qq{
162 LEFT JOIN virtualshelfshares sh ON sh.shelfnumber=vs.shelfnumber AND sh.borrowernumber=?
163 WHERE vs.category=1 AND (vs.owner=? OR sh.borrowernumber=?) };
164 @params=($owner,$owner,$owner);
165 $qry2.= "AND (allow_add=1 OR owner=?) " if $adding_allowed;
166 push @params, $owner if $adding_allowed;
167 $qry2.= "ORDER BY vs.lastmodified DESC ";
168 $qry2.= "LIMIT $limit";
169 $bar= $dbh->selectall_arrayref($qry2,{Slice=>{}},@params);
172 return ( { bartotal => $bar? scalar @$bar: 0, pubtotal => $pub? scalar @$pub: 0}, $pub, $bar);
175 =head2 GetShelfContents
177 $biblist = &GetShelfContents($shelfnumber);
179 Looks up information about the contents of virtual virtualshelves number
180 C<$shelfnumber>. Sorted by a field in the biblio table. copyrightdate
183 Returns a reference-to-array, whose elements are references-to-hash,
184 as returned by C<C4::Biblio::GetBiblioFromItemNumber>.
186 Note: the notforloan status comes from the itemtype, and where it equals 0
187 it does not ensure that related items.notforloan status is likewise 0. The
188 caller has to check any items on their own, possibly with CanBookBeIssued
189 from C4::Circulation.
193 sub GetShelfContents {
194 my ($shelfnumber, $row_count, $offset, $sortfield, $sort_direction ) = @_;
195 my $dbh=C4::Context->dbh();
196 my $sth1 = $dbh->prepare("SELECT count(*) FROM virtualshelfcontents WHERE shelfnumber = ?");
197 $sth1->execute($shelfnumber);
198 my $total = $sth1->fetchrow;
200 my $sth2 = $dbh->prepare('SELECT sortfield FROM virtualshelves WHERE shelfnumber=?');
201 $sth2->execute($shelfnumber);
202 ($sortfield) = $sth2->fetchrow_array;
205 " SELECT DISTINCT vc.biblionumber, vc.shelfnumber, vc.dateadded, itemtypes.*,
206 biblio.*, biblioitems.itemtype, biblioitems.publicationyear as year, biblioitems.publishercode, biblioitems.place, biblioitems.size, biblioitems.pages
207 FROM virtualshelfcontents vc
208 JOIN biblio ON vc.biblionumber = biblio.biblionumber
209 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
210 LEFT JOIN items ON items.biblionumber=vc.biblionumber
211 LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
212 WHERE vc.shelfnumber=? ";
213 my @params = ($shelfnumber);
215 $query .= " ORDER BY " . $dbh->quote_identifier( $sortfield );
216 $query .= " DESC " if ( $sort_direction eq 'desc' );
219 $query .= " LIMIT ?, ? ";
220 push (@params, ($offset ? $offset : 0));
221 push (@params, $row_count);
223 my $sth3 = $dbh->prepare($query);
224 $sth3->execute(@params);
225 return ($sth3->fetchall_arrayref({}), $total);
226 # Like the perldoc says,
227 # returns reference-to-array, where each element is reference-to-hash of the row:
228 # like [ $sth->fetchrow_hashref(), $sth->fetchrow_hashref() ... ]
229 # Suitable for use in TMPL_LOOP.
230 # See http://search.cpan.org/~timb/DBI-1.601/DBI.pm#fetchall_arrayref
231 # or newer, for your version of DBI.
234 =head2 ShelfPossibleAction
236 ShelfPossibleAction($loggedinuser, $shelfnumber, $action);
238 C<$loggedinuser,$shelfnumber,$action>
240 $action can be "view", "add", "delete", "manage", "new_public", "new_private".
241 New additional actions are: invite, acceptshare.
242 Note that add/delete here refers to adding/deleting entries from the list. Deleting the list itself falls under manage.
243 new_public and new_private refers to creating a new public or private list.
244 The distinction between deleting your own entries from the list or entries from
245 others is made when deleting a content from the shelf.
247 Returns 1 if the user can do the $action in the $shelfnumber shelf.
249 For the actions invite and acceptshare a second errorcode is returned if the
250 result is false. See opac-shareshelf.pl
254 sub ShelfPossibleAction {
255 my ( $user, $shelfnumber, $action ) = @_;
256 $action= 'view' unless $action;
257 $user=0 unless $user;
259 if($action =~ /^new/) { #no shelfnumber needed
260 if($action eq 'new_private') {
263 elsif($action eq 'new_public') {
264 return $user>0 && C4::Context->preference('OpacAllowPublicListCreation');
269 return 0 unless defined($shelfnumber);
271 if ( $user > 0 and $action eq 'delete_shelf' ) {
272 my $borrower = C4::Members::GetMember( borrowernumber => $user );
275 if C4::Auth::haspermission( $borrower->{userid}, { lists => 'delete_public_lists' } );
278 my $dbh = C4::Context->dbh;
280 SELECT COALESCE(owner,0) AS owner, category, allow_add, allow_delete_own, allow_delete_other, COALESCE(sh.borrowernumber,0) AS borrowernumber
281 FROM virtualshelves vs
282 LEFT JOIN virtualshelfshares sh ON sh.shelfnumber=vs.shelfnumber
283 AND sh.borrowernumber=?
284 WHERE vs.shelfnumber=?
286 my $sth = $dbh->prepare($query);
287 $sth->execute($user, $shelfnumber);
288 my $shelf= $sth->fetchrow_hashref;
290 return 0 unless $shelf && ($shelf->{category}==2 || $shelf->{owner}==$user || ($user && $shelf->{borrowernumber}==$user));
291 if($action eq 'view') {
292 #already handled in the above condition
295 elsif($action eq 'add') {
296 return 0 if $user<=0; #should be logged in
297 return 1 if $shelf->{allow_add}==1 || $shelf->{owner}==$user;
298 #owner may always add
300 elsif($action eq 'delete') {
301 #this answer is just diplomatic: it says that you may be able to delete
302 #some items from that shelf
303 #it does not answer the question about a specific biblio
304 #Koha::Virtualshelf->remove_biblios checks the situation per biblio
305 return 1 if $user>0 && ($shelf->{allow_delete_own}==1 || $shelf->{allow_delete_other}==1);
307 elsif($action eq 'invite') {
308 #for sharing you must be the owner and the list must be private
309 if( $shelf->{category}==1 ) {
310 return 1 if $shelf->{owner}==$user;
311 return (0, 4); # code 4: should be owner
314 return (0, 5); # code 5: should be private list
317 elsif($action eq 'acceptshare') {
318 #the key for accepting is checked later in Koha::Virtualshelf->share
319 #you must not be the owner, list must be private
320 if( $shelf->{category}==1 ) {
321 return (0, 8) if $shelf->{owner}==$user;
322 #code 8: should not be owner
326 return (0, 5); # code 5: should be private list
329 elsif($action eq 'manage' or $action eq 'delete_shelf') {
330 return 1 if $user && $shelf->{owner}==$user;
337 $howmany= ShelvesMax($context);
339 Tells how much shelves are shown in which context.
340 POPUP refers to addbybiblionumber popup, MGRPAGE is managing page (in opac or
341 staff), COMBO refers to the Add to-combo of search results. MASTHEAD is the
342 main Koha toolbar with Lists button.
348 return SHELVES_POPUP_MAX if $which eq 'POPUP';
349 return SHELVES_MGRPAGE_MAX if $which eq 'MGRPAGE';
350 return SHELVES_COMBO_MAX if $which eq 'COMBO';
351 return SHELVES_MASTHEAD_MAX if $which eq 'MASTHEAD';
352 return SHELVES_MASTHEAD_MAX;
355 =head2 HandleDelBorrower
357 HandleDelBorrower($borrower);
359 When a member is deleted (DelMember in Members.pm), you should call me first.
360 This routine deletes/moves lists and entries for the deleted member/borrower.
361 Lists owned by the borrower are deleted, but entries from the borrower to
362 other lists are kept.
366 sub HandleDelBorrower {
369 my $dbh = C4::Context->dbh;
371 #Delete all lists and all shares of this borrower
372 #Consistent with the approach Koha uses on deleting individual lists
373 #Note that entries in virtualshelfcontents added by this borrower to
374 #lists of others will be handled by a table constraint: the borrower
375 #is set to NULL in those entries.
376 $query="DELETE FROM virtualshelves WHERE owner=?";
377 $dbh->do($query,undef,($borrower));
380 #We could handle the above deletes via a constraint too.
381 #But a new BZ report 11889 has been opened to discuss another approach.
382 #Instead of deleting we could also disown lists (based on a pref).
383 #In that way we could save shared and public lists.
384 #The current table constraints support that idea now.
385 #This pref should then govern the results of other routines/methods such as
386 #Koha::Virtualshelf->new->delete too.
390 my ($owner, $category) = @_;
392 # Find out how many shelves total meet the submitted criteria...
394 my $dbh = C4::Context->dbh;
395 my $query = "SELECT count(*) FROM virtualshelves vs ";
398 LEFT JOIN virtualshelfshares sh ON sh.shelfnumber=vs.shelfnumber
399 AND sh.borrowernumber=?
400 WHERE category=1 AND (vs.owner=? OR sh.borrowernumber=?) };
401 @params= ($owner, $owner, $owner);
404 $query.='WHERE category=2';
407 my $sth = $dbh->prepare($query);
408 $sth->execute(@params);
409 my ($total)= $sth->fetchrow;
419 Koha Development Team <http://koha-community.org/>
423 C4::Circulation::Circ2(3)