]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/WWW/EGCatLoader.pm
Merge branch 'master' of git+ssh://yeti.esilibrary.com/home/evergreen/evergreen-equin...
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / WWW / EGCatLoader.pm
1 package OpenILS::WWW::EGCatLoader;
2 use strict; use warnings;
3 use CGI;
4 use XML::LibXML;
5 use Digest::MD5 qw(md5_hex);
6 use Apache2::Const -compile => qw(OK DECLINED HTTP_INTERNAL_SERVER_ERROR REDIRECT HTTP_BAD_REQUEST);
7 use OpenSRF::AppSession;
8 use OpenSRF::EX qw/:try/;
9 use OpenSRF::Utils::Logger qw/$logger/;
10 use OpenILS::Application::AppUtils;
11 use OpenILS::Utils::CStoreEditor qw/:funcs/;
12 use OpenILS::Utils::Fieldmapper;
13 my $U = 'OpenILS::Application::AppUtils';
14
15 my %cache; # proc-level cache
16
17 sub new {
18     my($class, $apache, $ctx) = @_;
19
20     my $self = bless({}, ref($class) || $class);
21
22     $self->apache($apache);
23     $self->ctx($ctx);
24     $self->cgi(CGI->new);
25
26     OpenILS::Utils::CStoreEditor->init; # just in case
27     $self->editor(new_editor());
28
29     return $self;
30 }
31
32
33 # current Apache2::RequestRec;
34 sub apache {
35     my($self, $apache) = @_;
36     $self->{apache} = $apache if $apache;
37     return $self->{apache};
38 }
39
40 # runtime context
41 sub ctx {
42     my($self, $ctx) = @_;
43     $self->{ctx} = $ctx if $ctx;
44     return $self->{ctx};
45 }
46
47 # cstore editor
48 sub editor {
49     my($self, $editor) = @_;
50     $self->{editor} = $editor if $editor;
51     return $self->{editor};
52 }
53
54 # CGI handle
55 sub cgi {
56     my($self, $cgi) = @_;
57     $self->{cgi} = $cgi if $cgi;
58     return $self->{cgi};
59 }
60
61
62 # load common data, then load page data
63 sub load {
64     my $self = shift;
65
66     my $path = $self->apache->path_info;
67     $self->load_helpers;
68
69     my $stat = $self->load_common;
70     return $stat unless $stat == Apache2::Const::OK;
71
72     return $self->load_home if $path =~ /opac\/home/;
73     return $self->load_login if $path =~ /opac\/login/;
74     return $self->load_logout if $path =~ /opac\/logout/;
75     return $self->load_rresults if $path =~ /opac\/results/;
76     return $self->load_record if $path =~ /opac\/record/;
77     return $self->load_myopac if $path =~ /opac\/myopac/;
78     return $self->load_place_hold if $path =~ /opac\/place_hold/;
79
80     return Apache2::Const::OK;
81 }
82
83 # general purpose utility functions added to the environment
84 # context additions: 
85 #   find_org_unit : function(id) => aou object
86 #   org_tree : function(id) => aou object, top of tree, fleshed
87 sub load_helpers {
88     my $self = shift;
89     $cache{org_unit_map} = {};
90
91     # pull the org unit from the cached org tree
92     $self->ctx->{find_org_unit} = sub {
93         my $org_id = shift;
94         return undef unless defined $org_id;
95         return $cache{org_unit_map}{$org_id} if defined $cache{org_unit_map}{$org_id};
96         my $tree = shift || $self->ctx->{org_tree}->();
97         return $cache{org_unit_map}{$org_id} = $tree if $tree->id == $org_id;
98         for my $child (@{$tree->children}) {
99             my $node = $self->ctx->{find_org_unit}->($org_id, $child);
100             return $node if $node;
101         }
102         return undef;
103     };
104
105     $self->ctx->{org_tree} = sub {
106         unless($cache{org_tree}) {
107             $cache{org_tree} = $self->editor->search_actor_org_unit([
108                             {   parent_ou => undef},
109                             {   flesh            => -1,
110                                     flesh_fields    => {aou =>  ['children', 'ou_type']},
111                                     order_by        => {aou => 'name'}
112                             }
113                     ])->[0];
114         }
115         return $cache{org_tree};
116     }
117 }
118
119 # context additions: 
120 #   authtoken : string
121 #   user : au object
122 #   user_status : hash of user circ numbers
123 sub load_common {
124     my $self = shift;
125
126     my $e = $self->editor;
127     my $ctx = $self->ctx;
128
129     if($e->authtoken($self->cgi->cookie('ses'))) {
130
131         if($e->checkauth) {
132
133             $ctx->{authtoken} = $e->authtoken;
134             $ctx->{user} = $e->requestor;
135             $ctx->{user_stats} = $U->simplereq(
136                 'open-ils.actor', 
137                 'open-ils.actor.user.opac.vital_stats', 
138                 $e->authtoken, $e->requestor->id);
139
140         } else {
141
142             return $self->load_logout;
143         }
144     }
145
146     return Apache2::Const::OK;
147 }
148
149 sub load_home {
150     my $self = shift;
151     $self->ctx->{page} = 'home';
152     return Apache2::Const::OK;
153 }
154
155
156 sub load_login {
157     my $self = shift;
158     my $cgi = $self->cgi;
159
160     $self->ctx->{page} = 'login';
161
162     my $username = $cgi->param('username');
163     my $password = $cgi->param('password');
164
165     return Apache2::Const::OK unless $username and $password;
166
167         my $seed = $U->simplereq(
168         'open-ils.auth', 
169                 'open-ils.auth.authenticate.init',
170         $username);
171
172         my $response = $U->simplereq(
173         'open-ils.auth', 
174                 'open-ils.auth.authenticate.complete', 
175                 {       username => $username, 
176                         password => md5_hex($seed . md5_hex($password)), 
177                         type => 'opac' 
178         }
179     );
180
181     # XXX check event, redirect as necessary
182
183     my $home = $self->apache->unparsed_uri;
184     $home =~ s/\/login/\/home/;
185
186     $self->apache->print(
187         $cgi->redirect(
188             -url => $cgi->param('origin') || $home,
189             -cookie => $cgi->cookie(
190                 -name => 'ses',
191                 -path => '/',
192                 -secure => 1,
193                 -value => $response->{payload}->{authtoken},
194                 -expires => CORE::time + $response->{payload}->{authtime}
195             )
196         )
197     );
198
199     return Apache2::Const::REDIRECT;
200 }
201
202 sub load_logout {
203     my $self = shift;
204
205     my $path = $self->apache->uri;
206     $path =~ s/(\/[^\/]+$)/\/home/;
207     my $url = 'http://' . $self->apache->hostname . "$path";
208
209     $self->apache->print(
210         $self->cgi->redirect(
211             -url => $url,
212             -cookie => $self->cgi->cookie(
213                 -name => 'ses',
214                 -path => '/',
215                 -value => '',
216                 -expires => '-1h'
217             )
218         )
219     );
220
221     return Apache2::Const::REDIRECT;
222 }
223
224 # context additions: 
225 #   page_size
226 #   hit_count
227 #   records : list of bre's and copy-count objects
228 sub load_rresults {
229     my $self = shift;
230     my $cgi = $self->cgi;
231     my $ctx = $self->ctx;
232     my $e = $self->editor;
233
234     $ctx->{page} = 'rresult';
235     my $page = $cgi->param('page') || 0;
236     my $facet = $cgi->param('facet');
237     my $query = $cgi->param('query');
238     my $limit = $cgi->param('limit') || 10; # XXX user settings
239     my $args = {limit => $limit, offset => $page * $limit}; 
240     $query = "$query $facet" if $facet;
241     my $results;
242
243     try {
244         $results = $U->simplereq(
245             'open-ils.search',
246             'open-ils.search.biblio.multiclass.query.staff', 
247             $args, $query, 1);
248
249     } catch Error with {
250         my $err = shift;
251         $logger->error("multiclass search error: $err");
252         $results = {count => 0, ids => []};
253     };
254
255     my $rec_ids = [map { $_->[0] } @{$results->{ids}}];
256
257     $ctx->{records} = [];
258     $ctx->{search_facets} = {};
259     $ctx->{page_size} = $limit;
260     $ctx->{hit_count} = $results->{count};
261
262     return Apache2::Const::OK if @$rec_ids == 0;
263
264     my $cstore1 = OpenSRF::AppSession->create('open-ils.cstore');
265     my $bre_req = $cstore1->request(
266         'open-ils.cstore.direct.biblio.record_entry.search', {id => $rec_ids});
267
268     my $search = OpenSRF::AppSession->create('open-ils.search');
269     my $facet_req = $search->request('open-ils.search.facet_cache.retrieve', $results->{facet_key}, 10);
270
271     unless($cache{cmf}) {
272         $cache{cmf} = $e->search_config_metabib_field({id => {'!=' => undef}});
273         $ctx->{metabib_field} = $cache{cmf};
274         #$cache{cmc} = $e->search_config_metabib_class({name => {'!=' => undef}});
275         #$ctx->{metabib_class} = $cache{cmc};
276     }
277
278     my @data;
279     while(my $resp = $bre_req->recv) {
280         my $bre = $resp->content; 
281
282         # XXX farm out to multiple cstore sessions before loop, then collect after
283         my $copy_counts = $e->json_query(
284             {from => ['asset.record_copy_count', 1, $bre->id, 0]})->[0];
285
286         push(@data,
287             {
288                 bre => $bre,
289                 marc_xml => XML::LibXML->new->parse_string($bre->marc),
290                 copy_counts => $copy_counts
291             }
292         );
293     }
294
295     $cstore1->kill_me;
296
297     # shove recs into context in search results order
298     for my $rec_id (@$rec_ids) { 
299         push(
300             @{$ctx->{records}},
301             grep { $_->{bre}->id == $rec_id } @data
302         );
303     }
304
305     my $facets = $facet_req->gather(1);
306
307     for my $cmf_id (keys %$facets) {  # quick-n-dirty
308         my ($cmf) = grep { $_->id eq $cmf_id } @{$cache{cmf}};
309         $facets->{$cmf_id} = {cmf => $cmf, data => $facets->{$cmf_id}};
310     }
311     $ctx->{search_facets} = $facets;
312
313     return Apache2::Const::OK;
314 }
315
316 # context additions: 
317 #   record : bre object
318 sub load_record {
319     my $self = shift;
320
321     my $rec_id = $self->ctx->{page_args}->[0]
322         or return Apache2::Const::HTTP_BAD_REQUEST;
323
324     $self->ctx->{record} = $self->editor->retrieve_biblio_record_entry([
325         $rec_id,
326         {
327             flesh => 2, 
328             flesh_fields => {
329                 bre => ['call_numbers'],
330                 acn => ['copies'] # limit, paging, etc.
331             }
332         }
333     ]);
334
335     $self->ctx->{marc_xml} = XML::LibXML->new->parse_string($self->ctx->{record}->marc);
336
337     return Apache2::Const::OK;
338 }
339
340 # context additions: 
341 #   user : au object, fleshed
342 sub load_myopac {
343     my $self = shift;
344
345     $self->ctx->{user} = $self->editor->retrieve_actor_user([
346         $self->ctx->{user}->id,
347         {
348             flesh => 1,
349             flesh_fields => {
350                 au => ['card']
351                 # ...
352             }
353         }
354     ]);
355
356     return Apache2::Const::OK;
357 }
358
359 # context additions: 
360 sub load_place_hold {
361     my $self = shift;
362     my $ctx = $self->ctx;
363     my $e = $self->editor;
364
365     $ctx->{hold_target} = $self->cgi->param('hold_target');
366     $ctx->{hold_type} = $self->cgi->param('hold_type');
367     $ctx->{default_pickup_lib} = $e->requestor->home_ou; # XXX staff
368
369     if($ctx->{hold_type} eq 'T') {
370         $ctx->{record} = $e->retrieve_biblio_record_entry($ctx->{hold_target});
371     }
372     # ...
373
374     $ctx->{marc_xml} = XML::LibXML->new->parse_string($ctx->{record}->marc);
375
376     if(my $pickup_lib = $self->cgi->param('pickup_lib')) {
377
378         my $args = {
379             patronid => $e->requestor->id,
380             titleid => $ctx->{hold_target}, # XXX
381             pickup_lib => $pickup_lib,
382             depth => 0, # XXX
383         };
384
385         my $allowed = $U->simplereq(
386             'open-ils.circ',
387             'open-ils.circ.title_hold.is_possible',
388             $e->authtoken, $args
389         );
390
391         if($allowed->{success} == 1) {
392             my $hold = Fieldmapper::action::hold_request->new;
393
394             $hold->pickup_lib($pickup_lib);
395             $hold->requestor($e->requestor->id);
396             $hold->usr($e->requestor->id); # XXX staff
397             $hold->target($ctx->{hold_target});
398             $hold->hold_type($ctx->{hold_type});
399             # frozen, expired, etc..
400
401             my $stat = $U->simplereq(
402                 'open-ils.circ',
403                 'open-ils.circ.holds.create',
404                 $e->authtoken, $hold
405             );
406
407             if($stat and $stat > 0) {
408                 $ctx->{hold_success} = 1;
409             } else {
410                 $ctx->{hold_failed} = 1; # XXX process the events, etc
411             }
412         }
413
414         # place the hold and deliver results
415     }
416
417     return Apache2::Const::OK;
418 }
419
420 1;