Bug 11614: Untranslatable label_element_title in label management
[koha.git] / C4 / VirtualShelves.pm
blob70dc9657552ea8bbe8b3e5954afcf210c9d53745
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 under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 use strict;
21 use warnings;
23 use Carp;
24 use C4::Context;
25 use C4::Debug;
27 use constant SHELVES_MASTHEAD_MAX => 10; #number under Lists button in masthead
28 use constant SHELVES_COMBO_MAX => 10; #add to combo in search
29 use constant SHELVES_MGRPAGE_MAX => 20; #managing page
30 use constant SHELVES_POPUP_MAX => 40; #addbybiblio popup
32 use constant SHARE_INVITATION_EXPIRY_DAYS => 14; #two weeks to accept
34 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
36 BEGIN {
37 # set the version for version checking
38 $VERSION = 3.07.00.049;
39 require Exporter;
40 @ISA = qw(Exporter);
41 @EXPORT = qw(
42 &GetShelves &GetShelfContents &GetShelf
43 &AddToShelf &AddShelf
44 &ModShelf
45 &ShelfPossibleAction
46 &DelFromShelf &DelShelf
47 &GetBibliosShelves
48 &AddShare &AcceptShare &RemoveShare &IsSharedList
50 @EXPORT_OK = qw(
51 &GetAllShelves &ShelvesMax
56 =head1 NAME
58 C4::VirtualShelves - Functions for manipulating Koha virtual shelves
60 =head1 SYNOPSIS
62 use C4::VirtualShelves;
64 =head1 DESCRIPTION
66 This module provides functions for manipulating virtual shelves,
67 including creating and deleting virtual shelves, and adding and removing
68 bibs to and from virtual shelves.
70 =head1 FUNCTIONS
72 =head2 GetShelves
74 ($shelflist, $totshelves) = &GetShelves($category, $row_count, $offset, $owner);
75 ($shelfnumber, $shelfhash) = each %{$shelflist};
77 Returns the number of shelves specified by C<$row_count> and C<$offset> as well as the total
78 number of shelves that meet the C<$owner> and C<$category> criteria. C<$category>,
79 C<$row_count>, and C<$offset> are required. C<$owner> must be supplied when C<$category> == 1.
80 When C<$category> is 2, supply undef as argument for C<$owner>.
82 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.
84 C<$shelflist>is a reference-to-hash. The keys are the virtualshelves numbers (C<$shelfnumber>, above),
85 and the values (C<$shelfhash>, above) are themselves references-to-hash, with the following keys:
87 =over
89 =item C<$shelfhash-E<gt>{shelfname}>
91 A string. The name of the shelf.
93 =item C<$shelfhash-E<gt>{count}>
95 The number of virtuals on that virtualshelves.
97 =back
99 =cut
101 sub GetShelves {
102 my ($category, $row_count, $offset, $owner) = @_;
103 my @params;
104 my $total = _shelf_count($owner, $category);
105 my $dbh = C4::Context->dbh;
106 my $query = qq{
107 SELECT vs.shelfnumber, vs.shelfname,vs.owner,
108 bo.surname,bo.firstname,vs.category,vs.sortfield,
109 count(vc.biblionumber) as count
110 FROM virtualshelves vs
111 LEFT JOIN borrowers bo ON vs.owner=bo.borrowernumber
112 LEFT JOIN virtualshelfcontents vc USING (shelfnumber) };
113 if($category==1) {
114 $query.= qq{
115 LEFT JOIN virtualshelfshares sh ON sh.shelfnumber=vs.shelfnumber
116 AND sh.borrowernumber=?
117 WHERE category=1 AND (vs.owner=? OR sh.borrowernumber=?) };
118 @params= ($owner, $owner, $owner, $offset||0, $row_count);
120 else {
121 $query.= 'WHERE category=2 ';
122 @params= ($offset||0, $row_count);
124 $query.= qq{
125 GROUP BY vs.shelfnumber
126 ORDER BY vs.shelfname
127 LIMIT ?, ?};
129 my $sth2 = $dbh->prepare($query);
130 $sth2->execute(@params);
131 my %shelflist;
132 while( my ($shelfnumber, $shelfname, $owner, $surname, $firstname, $category, $sortfield, $count)= $sth2->fetchrow) {
133 $shelflist{$shelfnumber}->{'shelfname'} = $shelfname;
134 $shelflist{$shelfnumber}->{'count'} = $count;
135 $shelflist{$shelfnumber}->{'single'} = $count==1;
136 $shelflist{$shelfnumber}->{'sortfield'} = $sortfield;
137 $shelflist{$shelfnumber}->{'category'} = $category;
138 $shelflist{$shelfnumber}->{'owner'} = $owner;
139 $shelflist{$shelfnumber}->{'surname'} = $surname;
140 $shelflist{$shelfnumber}->{'firstname'} = $firstname;
142 return ( \%shelflist, $total );
145 =head2 GetAllShelves
147 $shelflist = GetAllShelves($category, $owner)
149 This function returns a reference to an array of hashrefs containing all shelves
150 sorted by the shelf name.
152 This function is intended to return a dataset reflecting all the shelves for
153 the submitted parameters.
155 =cut
157 sub GetAllShelves {
158 my ($category,$owner,$adding_allowed) = @_;
159 my @params;
160 my $dbh = C4::Context->dbh;
161 my $query = 'SELECT vs.* FROM virtualshelves vs ';
162 if($category==1) {
163 $query.= qq{
164 LEFT JOIN virtualshelfshares sh ON sh.shelfnumber=vs.shelfnumber
165 AND sh.borrowernumber=?
166 WHERE category=1 AND (vs.owner=? OR sh.borrowernumber=?) };
167 @params = ($owner, $owner, $owner);
169 else {
170 $query.='WHERE category=2 ';
171 @params = ();
173 $query.='AND (allow_add=1 OR owner=?) ' if $adding_allowed;
174 push @params, $owner if $adding_allowed;
175 $query.= 'ORDER BY shelfname ASC';
176 my $sth = $dbh->prepare( $query );
177 $sth->execute(@params);
178 return $sth->fetchall_arrayref({});
181 =head2 GetSomeShelfNames
183 Returns shelf names and numbers for Add to combo of search results and Lists button of OPAC header.
185 =cut
187 sub GetSomeShelfNames {
188 my ($owner, $purpose, $adding_allowed)= @_;
189 my ($bar, $pub, @params);
190 my $dbh = C4::Context->dbh;
192 my $bquery = 'SELECT vs.shelfnumber, vs.shelfname FROM virtualshelves vs ';
193 my $limit= ShelvesMax($purpose);
195 my $qry1= $bquery."WHERE vs.category=2 ";
196 $qry1.= "AND (allow_add=1 OR owner=?) " if $adding_allowed;
197 push @params, $owner||0 if $adding_allowed;
198 $qry1.= "ORDER BY vs.lastmodified DESC LIMIT $limit";
200 unless($adding_allowed && (!defined($owner) || $owner<=0)) {
201 #if adding items, user should be known
202 $pub= $dbh->selectall_arrayref($qry1,{Slice=>{}},@params);
205 if($owner) {
206 my $qry2= $bquery. qq{
207 LEFT JOIN virtualshelfshares sh ON sh.shelfnumber=vs.shelfnumber AND sh.borrowernumber=?
208 WHERE vs.category=1 AND (vs.owner=? OR sh.borrowernumber=?) };
209 @params=($owner,$owner,$owner);
210 $qry2.= "AND (allow_add=1 OR owner=?) " if $adding_allowed;
211 push @params, $owner if $adding_allowed;
212 $qry2.= "ORDER BY vs.lastmodified DESC ";
213 $qry2.= "LIMIT $limit";
214 $bar= $dbh->selectall_arrayref($qry2,{Slice=>{}},@params);
217 return ( { bartotal => $bar? scalar @$bar: 0, pubtotal => $pub? scalar @$pub: 0}, $pub, $bar);
220 =head2 GetShelf
222 (shelfnumber,shelfname,owner,category,sortfield,allow_add,allow_delete_own,allow_delete_other) = &GetShelf($shelfnumber);
224 Returns the above-mentioned fields for passed virtual shelf number.
226 =cut
228 sub GetShelf {
229 my ($shelfnumber) = @_;
230 my $dbh = C4::Context->dbh;
231 my $query = qq(
232 SELECT shelfnumber, shelfname, owner, category, sortfield,
233 allow_add, allow_delete_own, allow_delete_other
234 FROM virtualshelves
235 WHERE shelfnumber=?
237 my $sth = $dbh->prepare($query);
238 $sth->execute($shelfnumber);
239 return $sth->fetchrow;
242 =head2 GetShelfContents
244 $biblist = &GetShelfContents($shelfnumber);
246 Looks up information about the contents of virtual virtualshelves number
247 C<$shelfnumber>. Sorted by a field in the biblio table. copyrightdate
248 gives a desc sort.
250 Returns a reference-to-array, whose elements are references-to-hash,
251 as returned by C<C4::Biblio::GetBiblioFromItemNumber>.
253 Note: the notforloan status comes from the itemtype, and where it equals 0
254 it does not ensure that related items.notforloan status is likewise 0. The
255 caller has to check any items on their own, possibly with CanBookBeIssued
256 from C4::Circulation.
258 =cut
260 sub GetShelfContents {
261 my ($shelfnumber, $row_count, $offset, $sortfield, $sort_direction ) = @_;
262 my $dbh=C4::Context->dbh();
263 my $sth1 = $dbh->prepare("SELECT count(*) FROM virtualshelfcontents WHERE shelfnumber = ?");
264 $sth1->execute($shelfnumber);
265 my $total = $sth1->fetchrow;
266 if(!$sortfield) {
267 my $sth2 = $dbh->prepare('SELECT sortfield FROM virtualshelves WHERE shelfnumber=?');
268 $sth2->execute($shelfnumber);
269 ($sortfield) = $sth2->fetchrow_array;
271 my $query =
272 " SELECT DISTINCT vc.biblionumber, vc.shelfnumber, vc.dateadded, itemtypes.*,
273 biblio.*, biblioitems.itemtype, biblioitems.publicationyear as year, biblioitems.publishercode, biblioitems.place, biblioitems.size, biblioitems.pages
274 FROM virtualshelfcontents vc
275 JOIN biblio ON vc.biblionumber = biblio.biblionumber
276 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
277 LEFT JOIN items ON items.biblionumber=vc.biblionumber
278 LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
279 WHERE vc.shelfnumber=? ";
280 my @params = ($shelfnumber);
281 if($sortfield) {
282 $query .= " ORDER BY " . $dbh->quote_identifier( $sortfield );
283 $query .= " DESC " if ( $sort_direction eq 'desc' );
285 if($row_count){
286 $query .= " LIMIT ?, ? ";
287 push (@params, ($offset ? $offset : 0));
288 push (@params, $row_count);
290 my $sth3 = $dbh->prepare($query);
291 $sth3->execute(@params);
292 return ($sth3->fetchall_arrayref({}), $total);
293 # Like the perldoc says,
294 # returns reference-to-array, where each element is reference-to-hash of the row:
295 # like [ $sth->fetchrow_hashref(), $sth->fetchrow_hashref() ... ]
296 # Suitable for use in TMPL_LOOP.
297 # See http://search.cpan.org/~timb/DBI-1.601/DBI.pm#fetchall_arrayref
298 # or newer, for your version of DBI.
301 =head2 AddShelf
303 $shelfnumber = &AddShelf($hashref, $owner);
305 Creates a new virtual shelf. Params passed in a hash like ModShelf.
307 Returns a code to know what's happen.
308 * -1 : if this virtualshelves already exists.
309 * $shelfnumber : if success.
311 =cut
313 sub AddShelf {
314 my ($hashref, $owner)= @_;
315 my $dbh = C4::Context->dbh;
317 #initialize missing hash values to silence warnings
318 foreach('shelfname','category', 'sortfield', 'allow_add', 'allow_delete_own', 'allow_delete_other' ) {
319 $hashref->{$_}= undef unless exists $hashref->{$_};
322 return -1 unless _CheckShelfName($hashref->{shelfname}, $hashref->{category}, $owner, 0);
324 my $query = qq(INSERT INTO virtualshelves
325 (shelfname,owner,category,sortfield,allow_add,allow_delete_own,allow_delete_other)
326 VALUES (?,?,?,?,?,?,?));
328 my $sth = $dbh->prepare($query);
329 $sth->execute(
330 $hashref->{shelfname},
331 $owner,
332 $hashref->{category},
333 $hashref->{sortfield},
334 $hashref->{allow_add}//0,
335 $hashref->{allow_delete_own}//1,
336 $hashref->{allow_delete_other}//0 );
337 return if $sth->err;
338 my $shelfnumber = $dbh->{'mysql_insertid'};
339 return $shelfnumber;
342 =head2 AddToShelf
344 &AddToShelf($biblionumber, $shelfnumber, $borrower);
346 Adds bib number C<$biblionumber> to virtual virtualshelves number
347 C<$shelfnumber>, unless that bib is already on that shelf.
349 =cut
351 sub AddToShelf {
352 my ($biblionumber, $shelfnumber, $borrowernumber) = @_;
353 return unless $biblionumber;
354 my $dbh = C4::Context->dbh;
355 my $query = qq(
356 SELECT *
357 FROM virtualshelfcontents
358 WHERE shelfnumber=? AND biblionumber=?
360 my $sth = $dbh->prepare($query);
362 $sth->execute( $shelfnumber, $biblionumber );
363 ($sth->rows) and return; # already on shelf
364 $query = qq(
365 INSERT INTO virtualshelfcontents
366 (shelfnumber, biblionumber, flags, borrowernumber)
367 VALUES (?, ?, 0, ?));
368 $sth = $dbh->prepare($query);
369 $sth->execute( $shelfnumber, $biblionumber, $borrowernumber);
370 $query = qq(UPDATE virtualshelves
371 SET lastmodified = CURRENT_TIMESTAMP
372 WHERE shelfnumber = ?);
373 $sth = $dbh->prepare($query);
374 $sth->execute( $shelfnumber );
377 =head2 ModShelf
379 my $result= ModShelf($shelfnumber, $hashref)
381 Where $hashref->{column} = param
383 Modify the value into virtualshelves table with values given
384 from hashref, which each key of the hashref should be
385 the name of a column of virtualshelves.
386 Fields like shelfnumber or owner cannot be changed.
388 Returns 1 if the action seemed to be successful.
390 =cut
392 sub ModShelf {
393 my ($shelfnumber,$hashref) = @_;
394 my $dbh = C4::Context->dbh;
396 my $query= "SELECT * FROM virtualshelves WHERE shelfnumber=?";
397 my $sth = $dbh->prepare($query);
398 $sth->execute($shelfnumber);
399 my $oldrecord= $sth->fetchrow_hashref;
400 return 0 unless $oldrecord; #not found?
402 #initialize missing hash values to silence warnings
403 foreach('shelfname','category', 'sortfield', 'allow_add', 'allow_delete_own', 'allow_delete_other' ) {
404 $hashref->{$_}= undef unless exists $hashref->{$_};
407 #if name or category changes, the name should be tested
408 if($hashref->{shelfname} || $hashref->{category}) {
409 unless(_CheckShelfName(
410 $hashref->{shelfname}//$oldrecord->{shelfname},
411 $hashref->{category}//$oldrecord->{category},
412 $oldrecord->{owner},
413 $shelfnumber )) {
414 return 0; #name check failed
418 #only the following fields from the hash may be changed
419 $query= "UPDATE virtualshelves SET shelfname=?, category=?, sortfield=?, allow_add=?, allow_delete_own=?, allow_delete_other=? WHERE shelfnumber=?";
420 $sth = $dbh->prepare($query);
421 $sth->execute(
422 $hashref->{shelfname}//$oldrecord->{shelfname},
423 $hashref->{category}//$oldrecord->{category},
424 $hashref->{sortfield}//$oldrecord->{sortfield},
425 $hashref->{allow_add}//$oldrecord->{allow_add},
426 $hashref->{allow_delete_own}//$oldrecord->{allow_delete_own},
427 $hashref->{allow_delete_other}//$oldrecord->{allow_delete_other},
428 $shelfnumber );
429 return $@? 0: 1;
432 =head2 ShelfPossibleAction
434 ShelfPossibleAction($loggedinuser, $shelfnumber, $action);
436 C<$loggedinuser,$shelfnumber,$action>
438 $action can be "view", "add", "delete", "manage", "new_public", "new_private".
439 New additional actions are: invite, acceptshare.
440 Note that add/delete here refers to adding/deleting entries from the list. Deleting the list itself falls under manage.
441 new_public and new_private refers to creating a new public or private list.
442 The distinction between deleting your own entries from the list or entries from
443 others is made in DelFromShelf.
445 Returns 1 if the user can do the $action in the $shelfnumber shelf.
446 Returns 0 otherwise.
447 For the actions invite and acceptshare a second errorcode is returned if the
448 result is false. See opac-shareshelf.pl
450 =cut
452 sub ShelfPossibleAction {
453 my ( $user, $shelfnumber, $action ) = @_;
454 $action= 'view' unless $action;
455 $user=0 unless $user;
457 if($action =~ /^new/) { #no shelfnumber needed
458 if($action eq 'new_private') {
459 return $user>0;
461 elsif($action eq 'new_public') {
462 return $user>0 && C4::Context->preference('OpacAllowPublicListCreation');
464 return 0;
467 return 0 unless defined($shelfnumber);
469 my $dbh = C4::Context->dbh;
470 my $query = qq/
471 SELECT COALESCE(owner,0) AS owner, category, allow_add, allow_delete_own, allow_delete_other, COALESCE(sh.borrowernumber,0) AS borrowernumber
472 FROM virtualshelves vs
473 LEFT JOIN virtualshelfshares sh ON sh.shelfnumber=vs.shelfnumber
474 AND sh.borrowernumber=?
475 WHERE vs.shelfnumber=?
477 my $sth = $dbh->prepare($query);
478 $sth->execute($user, $shelfnumber);
479 my $shelf= $sth->fetchrow_hashref;
481 return 0 unless $shelf && ($shelf->{category}==2 || $shelf->{owner}==$user || ($user && $shelf->{borrowernumber}==$user));
482 if($action eq 'view') {
483 #already handled in the above condition
484 return 1;
486 elsif($action eq 'add') {
487 return 0 if $user<=0; #should be logged in
488 return 1 if $shelf->{allow_add}==1 || $shelf->{owner}==$user;
489 #owner may always add
491 elsif($action eq 'delete') {
492 #this answer is just diplomatic: it says that you may be able to delete
493 #some items from that shelf
494 #it does not answer the question about a specific biblio
495 #DelFromShelf checks the situation per biblio
496 return 1 if $user>0 && ($shelf->{allow_delete_own}==1 || $shelf->{allow_delete_other}==1);
498 elsif($action eq 'invite') {
499 #for sharing you must be the owner and the list must be private
500 if( $shelf->{category}==1 ) {
501 return 1 if $shelf->{owner}==$user;
502 return (0, 4); # code 4: should be owner
504 else {
505 return (0, 5); # code 5: should be private list
508 elsif($action eq 'acceptshare') {
509 #the key for accepting is checked later in AcceptShare
510 #you must not be the owner, list must be private
511 if( $shelf->{category}==1 ) {
512 return (0, 8) if $shelf->{owner}==$user;
513 #code 8: should not be owner
514 return 1;
516 else {
517 return (0, 5); # code 5: should be private list
520 elsif($action eq 'manage') {
521 return 1 if $user && $shelf->{owner}==$user;
523 return 0;
526 =head2 DelFromShelf
528 $result= &DelFromShelf( $bibref, $shelfnumber, $user);
530 Removes biblionumbers in passed arrayref from shelf C<$shelfnumber>.
531 If the bib wasn't on that virtualshelves to begin with, nothing happens.
533 Returns 0 if no items have been deleted.
535 =cut
537 sub DelFromShelf {
538 my ($bibref, $shelfnumber, $user) = @_;
539 my $dbh = C4::Context->dbh;
540 my $query = qq(SELECT allow_delete_own, allow_delete_other FROM virtualshelves WHERE shelfnumber=?);
541 my $sth= $dbh->prepare($query);
542 $sth->execute($shelfnumber);
543 my ($del_own, $del_oth)= $sth->fetchrow;
544 my $r; my $t=0;
546 if($del_own) {
547 $query = qq(DELETE FROM virtualshelfcontents
548 WHERE shelfnumber=? AND biblionumber=? AND borrowernumber=?);
549 $sth= $dbh->prepare($query);
550 foreach my $biblionumber (@$bibref) {
551 $sth->execute($shelfnumber, $biblionumber, $user);
552 $r= $sth->rows; #Expect -1, 0 or 1 (-1 means Don't know; count as 1)
553 $t+= ($r==-1)? 1: $r;
556 if($del_oth) {
557 #includes a check if borrowernumber is null (deleted patron)
558 $query = qq/DELETE FROM virtualshelfcontents
559 WHERE shelfnumber=? AND biblionumber=? AND
560 (borrowernumber IS NULL OR borrowernumber<>?)/;
561 $sth= $dbh->prepare($query);
562 foreach my $biblionumber (@$bibref) {
563 $sth->execute($shelfnumber, $biblionumber, $user);
564 $r= $sth->rows;
565 $t+= ($r==-1)? 1: $r;
568 return $t;
571 =head2 DelShelf
573 $Number = DelShelf($shelfnumber);
575 This function deletes the shelf number, and all of it's content.
576 Authorization to do so MUST have been checked before calling, while using
577 ShelfPossibleAction with manage parameter.
579 =cut
581 sub DelShelf {
582 my ($shelfnumber)= @_;
583 return unless $shelfnumber && $shelfnumber =~ /^\d+$/;
584 my $dbh = C4::Context->dbh;
585 my $sth = $dbh->prepare("DELETE FROM virtualshelves WHERE shelfnumber=?");
586 return $sth->execute($shelfnumber);
589 =head2 GetBibliosShelves
591 This finds all the public lists that this bib record is in.
593 =cut
595 sub GetBibliosShelves {
596 my ( $biblionumber ) = @_;
597 my $dbh = C4::Context->dbh;
598 my $sth = $dbh->prepare('
599 SELECT vs.shelfname, vs.shelfnumber
600 FROM virtualshelves vs
601 JOIN virtualshelfcontents vc ON (vs.shelfnumber= vc.shelfnumber)
602 WHERE vs.category=2
603 AND vc.biblionumber= ?
605 $sth->execute( $biblionumber );
606 return $sth->fetchall_arrayref({});
609 =head2 ShelvesMax
611 $howmany= ShelvesMax($context);
613 Tells how much shelves are shown in which context.
614 POPUP refers to addbybiblionumber popup, MGRPAGE is managing page (in opac or
615 staff), COMBO refers to the Add to-combo of search results. MASTHEAD is the
616 main Koha toolbar with Lists button.
618 =cut
620 sub ShelvesMax {
621 my $which= shift;
622 return SHELVES_POPUP_MAX if $which eq 'POPUP';
623 return SHELVES_MGRPAGE_MAX if $which eq 'MGRPAGE';
624 return SHELVES_COMBO_MAX if $which eq 'COMBO';
625 return SHELVES_MASTHEAD_MAX if $which eq 'MASTHEAD';
626 return SHELVES_MASTHEAD_MAX;
629 =head2 HandleDelBorrower
631 HandleDelBorrower($borrower);
633 When a member is deleted (DelMember in Members.pm), you should call me first.
634 This routine deletes/moves lists and entries for the deleted member/borrower.
635 Lists owned by the borrower are deleted, but entries from the borrower to
636 other lists are kept.
638 =cut
640 sub HandleDelBorrower {
641 my ($borrower)= @_;
642 my $query;
643 my $dbh = C4::Context->dbh;
645 #Delete all lists and all shares of this borrower
646 #Consistent with the approach Koha uses on deleting individual lists
647 #Note that entries in virtualshelfcontents added by this borrower to
648 #lists of others will be handled by a table constraint: the borrower
649 #is set to NULL in those entries.
650 $query="DELETE FROM virtualshelves WHERE owner=?";
651 $dbh->do($query,undef,($borrower));
653 #NOTE:
654 #We could handle the above deletes via a constraint too.
655 #But a new BZ report 11889 has been opened to discuss another approach.
656 #Instead of deleting we could also disown lists (based on a pref).
657 #In that way we could save shared and public lists.
658 #The current table constraints support that idea now.
659 #This pref should then govern the results of other routines such as
660 #DelShelf too.
663 =head2 AddShare
665 AddShare($shelfnumber, $key);
667 Adds a share request to the virtualshelves table.
668 Authorization must have been checked, and a key must be supplied. See script
669 opac-shareshelf.pl for an example.
670 This request is not yet confirmed. So it has no borrowernumber, it does have an
671 expiry date.
673 =cut
675 sub AddShare {
676 my ($shelfnumber, $key)= @_;
677 return if !$shelfnumber || !$key;
679 my $dbh = C4::Context->dbh;
680 my $sql = "INSERT INTO virtualshelfshares (shelfnumber, invitekey, sharedate) VALUES (?, ?, NOW())";
681 $dbh->do($sql, undef, ($shelfnumber, $key));
682 return !$dbh->err;
685 =head2 AcceptShare
687 my $result= AcceptShare($shelfnumber, $key, $borrowernumber);
689 Checks acceptation of a share request.
690 Key must be found for this shelf. Invitation must not have expired.
691 Returns true when accepted, false otherwise.
693 =cut
695 sub AcceptShare {
696 my ($shelfnumber, $key, $borrowernumber)= @_;
697 return if !$shelfnumber || !$key || !$borrowernumber;
699 my $sql;
700 my $dbh = C4::Context->dbh;
701 $sql="
702 UPDATE virtualshelfshares
703 SET invitekey=NULL, sharedate=NOW(), borrowernumber=?
704 WHERE shelfnumber=? AND invitekey=? AND (sharedate + INTERVAL ? DAY) >NOW()
706 my $i= $dbh->do($sql, undef, ($borrowernumber, $shelfnumber, $key, SHARE_INVITATION_EXPIRY_DAYS));
707 return if !defined($i) || !$i || $i eq '0E0'; #not found
708 return 1;
711 =head2 IsSharedList
713 my $bool= IsSharedList( $shelfnumber );
715 IsSharedList checks if a (private) list has shares.
716 Note that such a check would not be useful for public lists. A public list has
717 no shares, but is visible for anyone by nature..
718 Used to determine the list type in the display of Your lists (all private).
719 Returns boolean value.
721 =cut
723 sub IsSharedList {
724 my ($shelfnumber) = @_;
725 my $dbh = C4::Context->dbh;
726 my $sql="SELECT id FROM virtualshelfshares WHERE shelfnumber=? AND borrowernumber IS NOT NULL";
727 my $sth = $dbh->prepare($sql);
728 $sth->execute($shelfnumber);
729 my ($rv)= $sth->fetchrow_array;
730 return defined($rv);
733 =head2 RemoveShare
735 RemoveShare( $user, $shelfnumber );
737 RemoveShare removes a share for specific shelf and borrower.
738 Returns true if a record could be deleted.
740 =cut
742 sub RemoveShare {
743 my ($user, $shelfnumber)= @_;
744 my $dbh = C4::Context->dbh;
745 my $sql="
746 DELETE FROM virtualshelfshares
747 WHERE borrowernumber=? AND shelfnumber=?
749 my $n= $dbh->do($sql,undef,($user, $shelfnumber));
750 return if !defined($n) || !$n || $n eq '0E0'; #nothing removed
751 return 1;
754 # internal subs
756 sub _shelf_count {
757 my ($owner, $category) = @_;
758 my @params;
759 # Find out how many shelves total meet the submitted criteria...
761 my $dbh = C4::Context->dbh;
762 my $query = "SELECT count(*) FROM virtualshelves vs ";
763 if($category==1) {
764 $query.= qq{
765 LEFT JOIN virtualshelfshares sh ON sh.shelfnumber=vs.shelfnumber
766 AND sh.borrowernumber=?
767 WHERE category=1 AND (vs.owner=? OR sh.borrowernumber=?) };
768 @params= ($owner, $owner, $owner);
770 else {
771 $query.='WHERE category=2';
772 @params= ();
774 my $sth = $dbh->prepare($query);
775 $sth->execute(@params);
776 my ($total)= $sth->fetchrow;
777 return $total;
780 sub _CheckShelfName {
781 my ($name, $cat, $owner, $number)= @_;
783 my $dbh = C4::Context->dbh;
784 my @pars;
785 my $query = qq(
786 SELECT DISTINCT shelfnumber
787 FROM virtualshelves
788 LEFT JOIN virtualshelfshares sh USING (shelfnumber)
789 WHERE shelfname=? AND shelfnumber<>?);
790 if($cat==1 && defined($owner)) {
791 $query.= ' AND (sh.borrowernumber=? OR owner=?) AND category=1';
792 @pars=($name, $number, $owner, $owner);
794 elsif($cat==1 && !defined($owner)) { #owner is null (exceptional)
795 $query.= ' AND owner IS NULL AND category=1';
796 @pars=($name, $number);
798 else { #public list
799 $query.= ' AND category=2';
800 @pars=($name, $number);
802 my $sth = $dbh->prepare($query);
803 $sth->execute(@pars);
804 return $sth->rows>0? 0: 1;
809 __END__
811 =head1 AUTHOR
813 Koha Development Team <http://koha-community.org/>
815 =head1 SEE ALSO
817 C4::Circulation::Circ2(3)
819 =cut