Bug 15182: Conditionally load Koha::NorwegianPatronDB
[koha.git] / opac / opac-shareshelf.pl
blob7bc07eefeea894d078fb0bb0175cd7f9bc3fad67
1 #!/usr/bin/perl
3 # Copyright 2013 Rijksmuseum
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>.
20 use Modern::Perl;
22 use constant KEYLENGTH => 10;
23 use constant TEMPLATE_NAME => 'opac-shareshelf.tt';
24 use constant SHELVES_URL =>
25 '/cgi-bin/koha/opac-shelves.pl?display=privateshelves&viewshelf=';
27 use CGI qw ( -utf8 );
28 use Email::Valid;
30 use C4::Auth;
31 use C4::Context;
32 use C4::Letters;
33 use C4::Members ();
34 use C4::Output;
36 use Koha::Virtualshelves;
37 use Koha::Virtualshelfshares;
39 #-------------------------------------------------------------------------------
41 my $pvar = _init( {} );
42 if ( !$pvar->{errcode} ) {
43 show_invite($pvar) if $pvar->{op} eq 'invite';
44 confirm_invite($pvar) if $pvar->{op} eq 'conf_invite';
45 show_accept($pvar) if $pvar->{op} eq 'accept';
47 load_template_vars($pvar);
48 output_html_with_http_headers $pvar->{query}, $pvar->{cookie},
49 $pvar->{template}->output;
51 #-------------------------------------------------------------------------------
53 sub _init {
54 my ($param) = @_;
55 my $query = new CGI;
56 $param->{query} = $query;
57 $param->{shelfnumber} = $query->param('shelfnumber') || 0;
58 $param->{op} = $query->param('op') || '';
59 $param->{addrlist} = $query->param('invite_address') || '';
60 $param->{key} = $query->param('key') || '';
61 $param->{appr_addr} = [];
62 $param->{fail_addr} = [];
63 $param->{errcode} = check_common_errors($param);
65 # trim email address
66 if ( $param->{addrlist} ) {
67 $param->{addrlist} =~ s|^\s+||;
68 $param->{addrlist} =~ s|\s+$||;
71 #get some list details
72 my $shelf;
73 my $shelfnumber = $param->{shelfnumber};
74 $shelf = Koha::Virtualshelves->find( $shelfnumber ) unless $param->{errcode};
75 $param->{shelfname} = $shelf ? $shelf->shelfname : q||;
76 $param->{owner} = $shelf ? $shelf->owner : -1;
77 $param->{category} = $shelf ? $shelf->category : -1;
79 load_template($param);
80 return $param;
83 sub check_common_errors {
84 my ($param) = @_;
85 if ( $param->{op} !~ /^(invite|conf_invite|accept)$/ ) {
86 return 1; #no operation specified
88 if ( $param->{shelfnumber} !~ /^\d+$/ ) {
89 return 2; #invalid shelf number
91 if ( !C4::Context->preference('OpacAllowSharingPrivateLists') ) {
92 return 3; #not or no longer allowed?
94 return;
97 sub show_invite {
98 my ($param) = @_;
99 return unless check_owner_category($param);
102 sub confirm_invite {
103 my ($param) = @_;
104 return unless check_owner_category($param);
105 process_addrlist($param);
106 if ( @{ $param->{appr_addr} } ) {
107 send_invitekey($param);
109 else {
110 $param->{errcode} = 6; #not one valid address
114 sub show_accept {
115 my ($param) = @_;
117 my $shelfnumber = $param->{shelfnumber};
118 my $shelf = Koha::Virtualshelves->find( $shelfnumber );
120 # The key for accepting is checked later in Koha::Virtualshelf->share
121 # You must not be the owner and the list must be private
122 if ( $shelf->category == 2 or $shelf->owner == $param->{loggedinuser} ) {
123 return;
126 # We could have used ->find with the share id, but we don't want to change
127 # the url sent to the patron
128 my $shared_shelf = Koha::Virtualshelfshares->search(
130 shelfnumber => $param->{shelfnumber},
133 order_by => 'sharedate desc',
134 limit => 1,
138 if ( $shared_shelf ) {
139 $shared_shelf = $shared_shelf->next;
140 my $key = keytostring( stringtokey( $param->{key}, 0 ), 1 );
141 my $is_accepted = eval { $shared_shelf->accept( $key, $param->{loggedinuser} ) };
142 if ( $is_accepted ) {
143 notify_owner($param);
145 #redirect to view of this shared list
146 print $param->{query}->redirect(
147 -uri => SHELVES_URL . $param->{shelfnumber},
148 -cookie => $param->{cookie}
150 exit;
152 $param->{errcode} = 7; #not accepted (key not found or expired)
153 } else {
154 # This shelf is not shared
158 sub notify_owner {
159 my ($param) = @_;
161 my $toaddr = C4::Members::GetNoticeEmailAddress( $param->{owner} );
162 return if !$toaddr;
164 #prepare letter
165 my $letter = C4::Letters::GetPreparedLetter(
166 module => 'members',
167 letter_code => 'SHARE_ACCEPT',
168 branchcode => C4::Context->userenv->{"branch"},
169 tables => { borrowers => $param->{loggedinuser}, },
170 substitute => { listname => $param->{shelfname}, },
173 #send letter to queue
174 C4::Letters::EnqueueLetter(
176 letter => $letter,
177 message_transport_type => 'email',
178 from_address => C4::Context->preference('KohaAdminEmailAddress'),
179 to_address => $toaddr,
184 sub process_addrlist {
185 my ($param) = @_;
186 my @temp = split /[,:;]/, $param->{addrlist};
187 my @appr_addr;
188 my @fail_addr;
189 foreach my $a (@temp) {
190 $a =~ s/^\s+//;
191 $a =~ s/\s+$//;
192 if ( IsEmailAddress($a) ) {
193 push @appr_addr, $a;
195 else {
196 push @fail_addr, $a;
199 $param->{appr_addr} = \@appr_addr;
200 $param->{fail_addr} = \@fail_addr;
203 sub send_invitekey {
204 my ($param) = @_;
205 my $fromaddr = C4::Context->preference('KohaAdminEmailAddress');
206 my $url =
207 C4::Context->preference('OPACBaseURL')
208 . "/cgi-bin/koha/opac-shareshelf.pl?shelfnumber="
209 . $param->{shelfnumber}
210 . "&op=accept&key=";
212 #TODO Waiting for the right http or https solution (BZ 8952 a.o.)
214 my @ok; #the addresses that were processed well
215 foreach my $a ( @{ $param->{appr_addr} } ) {
216 my @newkey = randomlist( KEYLENGTH, 64 ); #generate a new key
218 #add a preliminary share record
219 my $shelf = Koha::Virtualshelves->find( $param->{shelfnumber} );
220 my $key = keytostring( \@newkey, 1 );
221 my $is_shared = eval { $shelf->share( $key ); };
222 # TODO Better error handling, catch the exceptions
223 if ( $@ or not $is_shared ) {
224 push @{ $param->{fail_addr} }, $a;
225 next;
227 push @ok, $a;
229 #prepare letter
230 my $letter = C4::Letters::GetPreparedLetter(
231 module => 'members',
232 letter_code => 'SHARE_INVITE',
233 branchcode => C4::Context->userenv->{"branch"},
234 tables => { borrowers => $param->{loggedinuser}, },
235 substitute => {
236 listname => $param->{shelfname},
237 shareurl => $url . keytostring( \@newkey, 0 ),
241 #send letter to queue
242 C4::Letters::EnqueueLetter(
244 letter => $letter,
245 message_transport_type => 'email',
246 from_address => $fromaddr,
247 to_address => $a,
251 $param->{appr_addr} = \@ok;
254 sub check_owner_category {
255 my ($param) = @_;
257 #sharing user should be the owner
258 #list should be private
259 $param->{errcode} = 4 if $param->{owner} != $param->{loggedinuser};
260 $param->{errcode} = 5 if !$param->{errcode} && $param->{category} != 1;
261 return !defined $param->{errcode};
264 sub load_template {
265 my ($param) = @_;
266 ( $param->{template}, $param->{loggedinuser}, $param->{cookie} ) =
267 get_template_and_user(
269 template_name => TEMPLATE_NAME,
270 query => $param->{query},
271 type => "opac",
272 authnotrequired => 0, #should be a user
277 sub load_template_vars {
278 my ($param) = @_;
279 my $template = $param->{template};
280 my $appr = join '; ', @{ $param->{appr_addr} };
281 my $fail = join '; ', @{ $param->{fail_addr} };
282 $template->param(
283 errcode => $param->{errcode},
284 op => $param->{op},
285 shelfnumber => $param->{shelfnumber},
286 shelfname => $param->{shelfname},
287 approvedaddress => $appr,
288 failaddress => $fail,
292 sub IsEmailAddress {
294 #TODO candidate for a module?
295 return Email::Valid->address( $_[0] ) ? 1 : 0;
298 sub randomlist {
300 #uses rand, safe enough for this application but not for more sensitive data
301 my ( $length, $base ) = @_;
302 return map { int( rand($base) ); } 1 .. $length;
305 sub keytostring {
306 my ( $keyref, $flgBase64 ) = @_;
307 if ($flgBase64) {
308 my $alphabet = [ 'A' .. 'Z', 'a' .. 'z', 0 .. 9, '+', '/' ];
309 return join '', map { alphabet_char( $_, $alphabet ); } @$keyref;
311 return join '', map { sprintf( "%02d", $_ ); } @$keyref;
314 sub stringtokey {
315 my ( $str, $flgBase64 ) = @_;
316 my @temp = split '', $str || '';
317 if ($flgBase64) {
318 my $alphabet = [ 'A' .. 'Z', 'a' .. 'z', 0 .. 9, '+', '/' ];
319 return [ map { alphabet_ordinal( $_, $alphabet ); } @temp ];
321 return [] if $str !~ /^\d+$/;
322 my @retval;
323 for ( my $i = 0 ; $i < @temp - 1 ; $i += 2 ) {
324 push @retval, $temp[$i] * 10 + $temp[ $i + 1 ];
326 return \@retval;
329 sub alphabet_ordinal {
330 my ( $char, $alphabet ) = @_;
331 for my $ord ( 0 .. $#$alphabet ) {
332 return $ord if $char eq $alphabet->[$ord];
334 return ''; #ignore missing chars
337 sub alphabet_char {
339 #reverse operation for ordinal; ignore invalid numbers
340 my ( $num, $alphabet ) = @_;
341 return $num =~ /^\d+$/ && $num <= $#$alphabet ? $alphabet->[$num] : '';