Bug 28561: Remove DBIC warning in opac-shelves
[koha.git] / opac / opac-shelves.pl
1 #!/usr/bin/perl
2
3 # Copyright 2015 Koha Team
4 #
5 # This file is part of Koha.
6 #
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.
11 #
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.
16 #
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>.
19
20 use Modern::Perl;
21
22 use CGI qw ( -utf8 );
23 use C4::Auth;
24 use C4::Biblio;
25 use C4::External::BakerTaylor qw( image_url link_url );
26 use C4::Koha;
27 use C4::Items;
28 use C4::Members;
29 use C4::Output;
30 use C4::Tags qw( get_tags );
31 use C4::XSLT;
32
33 use Koha::Biblios;
34 use Koha::Biblioitems;
35 use Koha::CirculationRules;
36 use Koha::CsvProfiles;
37 use Koha::Items;
38 use Koha::ItemTypes;
39 use Koha::Patrons;
40 use Koha::Virtualshelves;
41 use Koha::RecordProcessor;
42
43 use constant ANYONE => 2;
44
45 my $query = CGI->new;
46
47 my $template_name = $query->param('rss') ? "opac-shelves-rss.tt" : "opac-shelves.tt";
48
49 # if virtualshelves is disabled, leave immediately
50 if ( ! C4::Context->preference('virtualshelves') ) {
51     print $query->redirect("/cgi-bin/koha/errors/404.pl");
52     exit;
53 }
54
55 my $op = $query->param('op') || 'list';
56 my ( $template, $loggedinuser, $cookie );
57
58 if( $op eq 'view' || $op eq 'list' ){
59     ( $template, $loggedinuser, $cookie ) = get_template_and_user({
60             template_name   => $template_name,
61             query           => $query,
62             type            => "opac",
63             authnotrequired => ( C4::Context->preference("OpacPublic") ? 1 : 0 ),
64         });
65 } else {
66     ( $template, $loggedinuser, $cookie ) = get_template_and_user({
67             template_name   => $template_name,
68             query           => $query,
69             type            => "opac",
70             authnotrequired => 0,
71         });
72 }
73
74 if (C4::Context->preference("BakerTaylorEnabled")) {
75     $template->param(
76         BakerTaylorImageURL => &image_url(),
77         BakerTaylorLinkURL  => &link_url(),
78     );
79 }
80
81 my $referer  = $query->param('referer')  || $op;
82 my $category = 1;
83 $category = 2 if $query->param('category') && $query->param('category') == 2;
84
85 my ( $shelf, $shelfnumber, @messages );
86
87 if ( $op eq 'add_form' ) {
88     # Only pass default
89     $shelf = { allow_change_from_owner => 1 };
90 } elsif ( $op eq 'edit_form' ) {
91     $shelfnumber = $query->param('shelfnumber');
92     $shelf       = Koha::Virtualshelves->find($shelfnumber);
93
94     if ( $shelf ) {
95         $category = $shelf->category;
96         my $patron = Koha::Patrons->find( $shelf->owner );
97         $template->param( owner => $patron, );
98         unless ( $shelf->can_be_managed( $loggedinuser ) ) {
99             push @messages, { type => 'error', code => 'unauthorized_on_update' };
100             $op = 'list';
101         }
102     } else {
103         push @messages, { type => 'error', code => 'does_not_exist' };
104     }
105 } elsif ( $op eq 'add' ) {
106     if ( $loggedinuser ) {
107         my $allow_changes_from = $query->param('allow_changes_from');
108         eval {
109             $shelf = Koha::Virtualshelf->new(
110                 {   shelfname          => scalar $query->param('shelfname'),
111                     sortfield          => scalar $query->param('sortfield'),
112                     category           => $category,
113                     allow_change_from_owner => $allow_changes_from > 0,
114                     allow_change_from_others => $allow_changes_from == ANYONE,
115                     owner              => scalar $loggedinuser,
116                 }
117             );
118             $shelf->store;
119             $shelfnumber = $shelf->shelfnumber;
120         };
121         if ($@) {
122             push @messages, { type => 'error', code => ref($@), msg => $@ };
123         } elsif ( not $shelf ) {
124             push @messages, { type => 'error', code => 'error_on_insert' };
125         } else {
126             push @messages, { type => 'message', code => 'success_on_insert' };
127             $op = 'view';
128         }
129     } else {
130         push @messages, { type => 'error', code => 'unauthorized_on_insert' };
131         $op = 'list';
132     }
133 } elsif ( $op eq 'edit' ) {
134     $shelfnumber = $query->param('shelfnumber');
135     $shelf       = Koha::Virtualshelves->find($shelfnumber);
136     if ( $shelf ) {
137         $op = $referer;
138         my $sortfield = $query->param('sortfield');
139         $sortfield = 'title' unless grep { $_ eq $sortfield } qw( title author copyrightdate itemcallnumber dateadded );
140         if ( $shelf->can_be_managed( $loggedinuser ) ) {
141             $shelf->shelfname( scalar $query->param('shelfname') );
142             $shelf->sortfield( $sortfield );
143             my $allow_changes_from = $query->param('allow_changes_from');
144             $shelf->allow_change_from_owner( $allow_changes_from > 0 );
145             $shelf->allow_change_from_others( $allow_changes_from == ANYONE );
146             $shelf->category( $category );
147             eval { $shelf->store };
148
149             if ($@) {
150                 push @messages, { type => 'error', code => 'error_on_update' };
151                 $op = 'edit_form';
152             } else {
153                 push @messages, { type => 'message', code => 'success_on_update' };
154             }
155         } else {
156             push @messages, { type => 'error', code => 'unauthorized_on_update' };
157         }
158     } else {
159         push @messages, { type => 'error', code => 'does_not_exist' };
160     }
161 } elsif ( $op eq 'delete' ) {
162     $shelfnumber = $query->param('shelfnumber');
163     $shelf       = Koha::Virtualshelves->find($shelfnumber);
164     if ($shelf) {
165         if ( $shelf->can_be_deleted( $loggedinuser ) ) {
166             eval { $shelf->delete; };
167             if ($@) {
168                 push @messages, { type => 'error', code => ref($@), msg => $@ };
169             } else {
170                 push @messages, { type => 'message', code => 'success_on_delete' };
171             }
172         } else {
173             push @messages, { type => 'error', code => 'unauthorized_on_delete' };
174         }
175     } else {
176         push @messages, { type => 'error', code => 'does_not_exist' };
177     }
178     $op = $referer;
179 } elsif ( $op eq 'remove_share' ) {
180     $shelfnumber = $query->param('shelfnumber');
181     $shelf = Koha::Virtualshelves->find($shelfnumber);
182     if ($shelf) {
183         my $removed = eval { $shelf->remove_share( $loggedinuser ); };
184         if ($@) {
185             push @messages, { type => 'error', code => ref($@), msg => $@ };
186         } elsif ( $removed ) {
187             push @messages, { type => 'message', code => 'success_on_remove_share' };
188         } else {
189             push @messages, { type => 'error', code => 'error_on_remove_share' };
190         }
191     } else {
192         push @messages, { type => 'error', code => 'does_not_exist' };
193     }
194     $op = $referer;
195
196 } elsif ( $op eq 'add_biblio' ) {
197     $shelfnumber = $query->param('shelfnumber');
198     $shelf = Koha::Virtualshelves->find($shelfnumber);
199     if ($shelf) {
200         if( my $barcode = $query->param('barcode') ) {
201             my $item = Koha::Items->find({ barcode => $barcode });
202             if ( $item ) {
203                 if ( $shelf->can_biblios_be_added( $loggedinuser ) ) {
204                     my $added = eval { $shelf->add_biblio( $item->biblionumber, $loggedinuser ); };
205                     if ($@) {
206                         push @messages, { type => 'error', code => ref($@), msg => $@ };
207                     } elsif ( $added ) {
208                         push @messages, { type => 'message', code => 'success_on_add_biblio' };
209                     } else {
210                         push @messages, { type => 'message', code => 'error_on_add_biblio' };
211                     }
212                 } else {
213                     push @messages, { type => 'error', code => 'unauthorized_on_add_biblio' };
214                 }
215             } else {
216                 push @messages, { type => 'error', code => 'item_does_not_exist' };
217             }
218         }
219     } else {
220         push @messages, { type => 'error', code => 'does_not_exist' };
221     }
222     $op = $referer;
223 } elsif ( $op eq 'remove_biblios' ) {
224     $shelfnumber = $query->param('shelfnumber');
225     $shelf = Koha::Virtualshelves->find($shelfnumber);
226     my @biblionumber = $query->multi_param('biblionumber');
227     if ($shelf) {
228         if ( $shelf->can_biblios_be_removed( $loggedinuser ) ) {
229             my $number_of_biblios_removed = eval {
230                 $shelf->remove_biblios(
231                     {
232                         biblionumbers => \@biblionumber,
233                         borrowernumber => $loggedinuser,
234                     }
235                 );
236             };
237             if ($@) {
238                 push @messages, { type => 'error', code => ref($@), msg => $@ };
239             } elsif ( $number_of_biblios_removed ) {
240                 push @messages, { type => 'message', code => 'success_on_remove_biblios' };
241             } else {
242                 push @messages, { type => 'error', code => 'no_biblio_removed' };
243             }
244         } else {
245             push @messages, { type => 'error', code => 'unauthorized_on_remove_biblios' };
246         }
247     } else {
248         push @messages, { type => 'error', code => 'does_not_exist' };
249     }
250     $op = 'view';
251 }
252
253 if ( $op eq 'view' ) {
254     $shelfnumber ||= $query->param('shelfnumber');
255     $shelf = Koha::Virtualshelves->find($shelfnumber);
256     if ( $shelf ) {
257         if ( $shelf->can_be_viewed( $loggedinuser ) ) {
258             $category = $shelf->category;
259             my( $sortfield, $direction );
260             if( defined( $query->param('sortfield') ) ){ # Passed in sorting overrides default sorting
261                 ( $sortfield, $direction ) = split /:/, $query->param('sortfield');
262             } else {
263                 $sortfield = $shelf->sortfield;
264                 $direction = 'asc';
265             }
266             $sortfield = 'title' if !$sortfield or !grep { $_ eq $sortfield } qw( title author copyrightdate itemcallnumber dateadded );
267             $direction = 'asc' if !$direction or ( $direction ne 'asc' and $direction ne 'desc' );
268             my ( $page, $rows );
269             unless ( $query->param('print') or $query->param('rss') ) {
270                 $rows = C4::Context->preference('OPACnumSearchResults') || 20;
271                 $page = ( $query->param('page') ? $query->param('page') : 1 );
272             }
273             my $order_by = $sortfield eq 'itemcallnumber' ? 'items.cn_sort' : $sortfield;
274             my $contents = $shelf->get_contents->search(
275                 {},
276                 {
277                     distinct => 'biblionumber',
278                     join     => [ { 'biblionumber' => { 'biblioitems' => 'items' } } ],
279                     page     => $page,
280                     rows     => $rows,
281                     order_by => { "-$direction" => $order_by },
282                 }
283             );
284
285             # get biblionumbers stored in the cart
286             my @cart_list;
287             if(my $cart_list = $query->cookie('bib_list')){
288                 @cart_list = split(/\//, $cart_list);
289             }
290
291             my $patron = Koha::Patrons->find( $loggedinuser );
292
293             my $categorycode; # needed for may_article_request
294             if( C4::Context->preference('ArticleRequests') ) {
295                 $categorycode = $patron ? $patron->categorycode : undef;
296             }
297
298             # Lists display falls back to search results configuration
299             my $xslfile = C4::Context->preference('OPACXSLTListsDisplay');
300             my $lang   = $xslfile ? C4::Languages::getlanguage()  : undef;
301             my $sysxml = $xslfile ? C4::XSLT::get_xslt_sysprefs() : undef;
302
303             my $record_processor = Koha::RecordProcessor->new({ filters => 'ViewPolicy' });
304
305             my $art_req_itypes;
306             if( C4::Context->preference('ArticleRequests') ) {
307                 $art_req_itypes = Koha::CirculationRules->guess_article_requestable_itemtypes({ $patron ? ( categorycode => $patron->categorycode ) : () });
308             }
309
310             my @items_info;
311             while ( my $content = $contents->next ) {
312                 my $biblionumber = $content->biblionumber;
313                 my $this_item    = GetBiblioData($biblionumber);
314                 my $record = GetMarcBiblio({ biblionumber => $biblionumber });
315                 my $framework = GetFrameworkCode( $biblionumber );
316                 my $biblio = Koha::Biblios->find( $biblionumber );
317                 $record_processor->options({
318                     interface => 'opac',
319                     frameworkcode => $framework
320                 });
321                 $record_processor->process($record);
322
323                 my $marcflavour = C4::Context->preference("marcflavour");
324                 my $itemtype = Koha::Biblioitems->search({ biblionumber => $content->biblionumber })->next->itemtype;
325                 $itemtype = Koha::ItemTypes->find( $itemtype );
326                 if( $itemtype ) {
327                     $this_item->{imageurl}          = C4::Koha::getitemtypeimagelocation( 'opac', $itemtype->imageurl );
328                     $this_item->{description}       = $itemtype->description; #FIXME Should not it be translated_description?
329                     $this_item->{notforloan}        = $itemtype->notforloan;
330                 }
331                 $this_item->{'coins'}           = $biblio->get_coins;
332                 $this_item->{'normalized_upc'}  = GetNormalizedUPC( $record, $marcflavour );
333                 $this_item->{'normalized_ean'}  = GetNormalizedEAN( $record, $marcflavour );
334                 $this_item->{'normalized_oclc'} = GetNormalizedOCLCNumber( $record, $marcflavour );
335                 $this_item->{'normalized_isbn'} = GetNormalizedISBN( undef, $record, $marcflavour );
336                 # BZ17530: 'Intelligent' guess if result can be article requested
337                 $this_item->{artreqpossible} = ( $art_req_itypes->{ $this_item->{itemtype} // q{} } || $art_req_itypes->{ '*' } ) ? 1 : q{};
338
339                 unless ( defined $this_item->{size} ) {
340
341                     #TT has problems with size
342                     $this_item->{size} = q||;
343                 }
344
345                 if (C4::Context->preference('TagsEnabled') and C4::Context->preference('TagsShowOnList')) {
346                     $this_item->{TagLoop} = get_tags({
347                         biblionumber => $biblionumber, approved=>1, 'sort'=>'-weight',
348                         limit => C4::Context->preference('TagsShowOnList'),
349                     });
350                 }
351
352                 my $items = $biblio->items->filter_by_visible_in_opac({ patron => $patron });
353                 my $allow_onshelf_holds;
354                 while ( my $item = $items->next ) {
355
356                     # This method must take a Koha::Items rs
357                     $allow_onshelf_holds ||= Koha::CirculationRules->get_onshelfholds_policy(
358                         { item => $item, patron => $patron } );
359
360                 }
361
362                 $this_item->{allow_onshelf_holds} = $allow_onshelf_holds;
363                 $this_item->{'ITEM_RESULTS'} = $items;
364
365                 if ($xslfile) {
366                     my $variables = {
367                         anonymous_session => ($loggedinuser) ? 0 : 1
368                     };
369                     $this_item->{XSLTBloc} = XSLTParse4Display(
370                         $biblionumber,          $record,
371                         "OPACXSLTListsDisplay", 1,
372                         undef,                 $sysxml,
373                         $xslfile,              $lang,
374                         $variables,            $items->reset
375                     );
376                 }
377
378                 if ( grep {$_ eq $biblionumber} @cart_list) {
379                     $this_item->{incart} = 1;
380                 }
381
382                 $this_item->{biblio_object} = $biblio;
383                 $this_item->{biblionumber}  = $biblionumber;
384                 push @items_info, $this_item;
385             }
386
387             $template->param(
388                 can_manage_shelf   => $shelf->can_be_managed($loggedinuser),
389                 can_delete_shelf   => $shelf->can_be_deleted($loggedinuser),
390                 can_remove_biblios => $shelf->can_biblios_be_removed($loggedinuser),
391                 can_add_biblios    => $shelf->can_biblios_be_added($loggedinuser),
392                 itemsloop          => \@items_info,
393                 sortfield          => $sortfield,
394                 direction          => $direction,
395                 csv_profiles => [
396                     Koha::CsvProfiles->search(
397                         { type => 'marc', used_for => 'export_records', staff_only => 0 }
398                     )
399                 ],
400             );
401             if ( $page ) {
402                 my $pager = $contents->pager;
403                 $template->param(
404                     pagination_bar => pagination_bar(
405                         q||, $pager->last_page - $pager->first_page + 1,
406                         $page, "page", { op => 'view', shelfnumber => $shelf->shelfnumber, sortfield => $sortfield, direction => $direction, }
407                     ),
408                 );
409             }
410         } else {
411             push @messages, { type => 'error', code => 'unauthorized_on_view' };
412             undef $shelf;
413         }
414     } else {
415         push @messages, { type => 'error', code => 'does_not_exist' };
416     }
417 }
418
419 if ( $op eq 'list' ) {
420     my $shelves;
421     my ( $page, $rows ) = ( $query->param('page') || 1, 20 );
422     if ( $category == 1 ) {
423         $shelves = Koha::Virtualshelves->get_private_shelves({ page => $page, rows => $rows, borrowernumber => $loggedinuser, });
424     } else {
425         $shelves = Koha::Virtualshelves->get_public_shelves({ page => $page, rows => $rows, });
426     }
427
428     my $pager = $shelves->pager;
429     $template->param(
430         shelves => $shelves,
431         pagination_bar => pagination_bar(
432             q||, $pager->last_page - $pager->first_page + 1,
433             $page, "page", { op => 'list', category => $category, }
434         ),
435     );
436 }
437
438 $template->param(
439     op       => $op,
440     referer  => $referer,
441     shelf    => $shelf,
442     messages => \@messages,
443     category => $category,
444     print    => scalar $query->param('print') || 0,
445     listsview => 1,
446 );
447
448 my $content_type = $query->param('rss')? 'rss' : 'html';
449 output_with_http_headers $query, $cookie, $template->output, $content_type;