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