382506bb2813cc5c07fddc35f2e7c1f1a11287ef
[koha.git] / Koha / Virtualshelf.pm
1 package Koha::Virtualshelf;
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18 use Modern::Perl;
19
20
21 use C4::Auth qw( haspermission );
22
23 use Koha::Patrons;
24 use Koha::Database;
25 use Koha::DateUtils qw( dt_from_string );
26 use Koha::Exceptions;
27 use Koha::Exceptions::Virtualshelf;
28 use Koha::Virtualshelfshare;
29 use Koha::Virtualshelfshares;
30 use Koha::Virtualshelfcontent;
31 use Koha::Virtualshelfcontents;
32
33 use base qw(Koha::Object);
34
35 =head1 NAME
36
37 Koha::Virtualshelf - Koha Virtualshelf Object class
38
39 =head1 API
40
41 =head2 Class methods
42
43 =cut
44
45 sub store {
46     my ( $self ) = @_;
47
48     unless ( $self->owner ) {
49         Koha::Exceptions::Virtualshelf::UseDbAdminAccount->throw;
50     }
51
52     unless ( $self->is_shelfname_valid ) {
53         Koha::Exceptions::Virtualshelf::DuplicateObject->throw;
54     }
55
56     $self->allow_change_from_owner( 1 )
57         unless defined $self->allow_change_from_owner;
58     $self->allow_change_from_others( 0 )
59         unless defined $self->allow_change_from_others;
60     $self->allow_change_from_staff( 0 )
61         unless defined $self->allow_change_from_staff;
62
63     $self->created_on( dt_from_string )
64         unless defined $self->created_on;
65
66     return $self->SUPER::store( $self );
67 }
68
69 sub is_public {
70     my ( $self ) = @_;
71     return $self->public;
72 }
73
74 sub is_private {
75     my ( $self ) = @_;
76     return !$self->public;
77 }
78
79 sub is_shelfname_valid {
80     my ( $self ) = @_;
81
82     my $conditions = {
83         shelfname => $self->shelfname,
84         ( $self->shelfnumber ? ( "me.shelfnumber" => { '!=', $self->shelfnumber } ) : () ),
85     };
86
87     if ( $self->is_private and defined $self->owner ) {
88         $conditions->{-or} = {
89             "virtualshelfshares.borrowernumber" => $self->owner,
90             "me.owner" => $self->owner,
91         };
92         $conditions->{public} = 0;
93     }
94     elsif ( $self->is_private and not defined $self->owner ) {
95         $conditions->{owner} = undef;
96         $conditions->{public} = 0;
97     }
98     else {
99         $conditions->{public} = 1;
100     }
101
102     my $count = Koha::Virtualshelves->search(
103         $conditions,
104         {
105             join => 'virtualshelfshares',
106         }
107     )->count;
108     return $count ? 0 : 1;
109 }
110
111 sub get_shares {
112     my ( $self ) = @_;
113     my $rs = $self->{_result}->virtualshelfshares;
114     my $shares = Koha::Virtualshelfshares->_new_from_dbic( $rs );
115     return $shares;
116 }
117
118 sub get_contents {
119     my ( $self ) = @_;
120     my $rs = $self->{_result}->virtualshelfcontents;
121     my $contents = Koha::Virtualshelfcontents->_new_from_dbic( $rs );
122     return $contents;
123 }
124
125 sub share {
126     my ( $self, $key ) = @_;
127     unless ( $key ) {
128         Koha::Exceptions::Virtualshelf::InvalidKeyOnSharing->throw;
129     }
130     Koha::Virtualshelfshare->new(
131         {
132             shelfnumber => $self->shelfnumber,
133             invitekey => $key,
134             sharedate => dt_from_string,
135         }
136     )->store;
137 }
138
139 sub is_shared {
140     my ( $self ) = @_;
141     return  $self->get_shares->search(
142         {
143             borrowernumber => { '!=' => undef },
144         }
145     )->count;
146 }
147
148 sub is_shared_with {
149     my ( $self, $borrowernumber ) = @_;
150     return unless $borrowernumber;
151     return  $self->get_shares->search(
152         {
153             borrowernumber => $borrowernumber,
154         }
155     )->count;
156 }
157
158 sub remove_share {
159     my ( $self, $borrowernumber ) = @_;
160     my $shelves = Koha::Virtualshelfshares->search(
161         {
162             shelfnumber => $self->shelfnumber,
163             borrowernumber => $borrowernumber,
164         }
165     );
166     return 0 unless $shelves->count;
167
168     # Only 1 share with 1 patron can exist
169     return $shelves->next->delete;
170 }
171
172 sub add_biblio {
173     my ( $self, $biblionumber, $borrowernumber ) = @_;
174     return unless $biblionumber;
175     my $already_exists = $self->get_contents->search(
176         {
177             biblionumber => $biblionumber,
178         }
179     )->count;
180     return if $already_exists;
181
182     # Check permissions
183     my $patron = Koha::Patrons->find( $borrowernumber ) or return 0;
184     return 0 unless ( $self->owner == $borrowernumber && $self->allow_change_from_owner ) || ( $self->allow_change_from_staff && $patron->can_patron_change_staff_only_lists ) || $self->allow_change_from_others;
185
186     my $content = Koha::Virtualshelfcontent->new(
187         {
188             shelfnumber => $self->shelfnumber,
189             biblionumber => $biblionumber,
190             borrowernumber => $borrowernumber,
191         }
192     )->store;
193     $self->lastmodified(dt_from_string);
194     $self->store;
195
196     return $content;
197 }
198
199 sub remove_biblios {
200     my ( $self, $params ) = @_;
201     my $biblionumbers = $params->{biblionumbers} || [];
202     my $borrowernumber = $params->{borrowernumber};
203     return unless @$biblionumbers;
204
205     my $number_removed = 0;
206     my $patron = Koha::Patrons->find( $borrowernumber ) or return 0;
207     if( ( $self->owner == $borrowernumber && $self->allow_change_from_owner )
208       || ( $self->allow_change_from_staff && $patron->can_patron_change_staff_only_lists )
209       || $self->allow_change_from_others ) {
210         $number_removed += $self->get_contents->search({
211             biblionumber => $biblionumbers,
212         })->delete;
213     }
214     return $number_removed;
215 }
216
217 sub can_be_viewed {
218     my ( $self, $borrowernumber ) = @_;
219     return 1 if $self->is_public;
220     return 0 unless $borrowernumber;
221     return 1 if $self->owner == $borrowernumber;
222     return $self->get_shares->search(
223         {
224             borrowernumber => $borrowernumber,
225         }
226     )->count;
227 }
228
229 sub can_be_deleted {
230     my ( $self, $borrowernumber ) = @_;
231
232     return 0 unless $borrowernumber;
233     return 1 if $self->owner == $borrowernumber;
234
235     my $patron = Koha::Patrons->find( $borrowernumber ) or return 0;
236
237     return 1 if $self->is_public and haspermission( $patron->userid, { lists => 'delete_public_lists' } );
238
239     return 0;
240 }
241
242 sub can_be_managed {
243     my ( $self, $borrowernumber ) = @_;
244     return 1
245       if $borrowernumber and $self->owner == $borrowernumber;
246
247     my $patron = Koha::Patrons->find( $borrowernumber ) or return 0;
248     return 1
249       if $self->is_public and haspermission( $patron->userid, { lists => 'edit_public_lists' } );
250     return 0;
251 }
252
253 sub can_biblios_be_added {
254     my ( $self, $borrowernumber ) = @_;
255
256     my $patron = Koha::Patrons->find( $borrowernumber ) or return 0;
257     return 1
258       if $borrowernumber
259       and ( ( $self->owner == $borrowernumber && $self->allow_change_from_owner ) or ( $self->allow_change_from_staff && $patron->can_patron_change_staff_only_lists ) or $self->allow_change_from_others );
260     return 0;
261 }
262
263 sub can_biblios_be_removed {
264     my ( $self, $borrowernumber ) = @_;
265     return $self->can_biblios_be_added( $borrowernumber );
266     # Same answer since bug 18228
267 }
268
269 =head3 cannot_be_transferred
270
271     $shelf->cannot_be_transferred({
272         by => $p1, to => $p2, interface => opac|intranet|undef,
273             # p1 and p2 are borrowernumbers
274     });
275
276     This routine has two main goals:
277     [1] Decide if patron may transfer a shared list to another
278         sharee (patron).
279     [2] Decide if staff member may transfer a public list.
280
281     If you pass interface, we'll check if it supports transfer too.
282     NOTE: The explicit passing is still more reliable than via context,
283     since we could switch interface after login in the same session.
284
285     Returns a true value (read: error_code) when not allowed.
286     The following error codes are possible:
287         unauthorized_transfer, missing_by_parameter, new_owner_not_found,
288         new_owner_has_no_share, missing_to_parameter.
289     Otherwise returns false (zero).
290
291 =cut
292
293 sub cannot_be_transferred {
294     my ( $self, $params ) = @_;
295     my $to = $params->{to};
296     my $by = $params->{by};
297     my $interface = $params->{interface};
298
299     # Check on interface: currently we don't support transfer shared on intranet, transfer public on OPAC
300     if( $interface ) {
301         return 'unauthorized_transfer'
302             if ( $self->public && $interface eq 'opac' ) or
303                ( $self->is_private && $interface eq 'intranet' );
304                    # is_private call is enough here, get_shares tested below
305     }
306
307     my $shares = $self->public ? undef : $self->get_shares->search({ borrowernumber => { '!=' => undef } });
308     return 'unauthorized_transfer' if $self->is_private && !$shares->count;
309
310     if( $by ) {
311         if( $self->public ) {
312             my $by_patron = Koha::Patrons->find($by);
313             return 'unauthorized_transfer'
314                 if !$by_patron || !haspermission( $by_patron->userid, { lists => 'edit_public_lists' });
315         } else {
316             return 'unauthorized_transfer' if !$self->can_be_managed($by);
317         }
318     } else {
319         return 'missing_by_parameter';
320     }
321
322     if( $to ) {
323         if( !Koha::Patrons->find($to) ) {
324             return 'new_owner_not_found';
325         }
326         if( !$self->public && !$shares->search({ borrowernumber => $to })->count ) {
327             return 'new_owner_has_no_share';
328         }
329     } else {
330         return 'missing_to_parameter';
331     }
332     return 0; # serving as green light
333 }
334
335 =head3 transfer_ownership
336
337     $list->transfer_ownership( $patron_id );
338
339 This method transfers the list ownership to the passed I<$patron_id>.
340
341 =cut
342
343 sub transfer_ownership {
344     my ( $self, $patron_id ) = @_;
345
346     Koha::Exceptions::MissingParameter->throw( "Mandatory parameter 'patron' missing" )
347       unless $patron_id;
348
349     $self->remove_share( $patron_id ) if $self->is_private;
350     return $self->set({ owner => $patron_id })->store;
351 }
352
353 =head2 Internal methods
354
355 =head3 _type
356
357 =cut
358
359 sub _type {
360     return 'Virtualshelve';
361 }
362
363 1;