ignoring wide chars in cache keys
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Actor.pm
1 package OpenILS::Application::Actor;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
4 use Data::Dumper;
5 use OpenSRF::EX qw(:try);
6 use OpenILS::Application::AppUtils;
7 use OpenILS::Utils::Fieldmapper;
8 use OpenILS::Application::Search::Actor;
9
10 my $apputils = "OpenILS::Application::AppUtils";
11 sub _d { warn "Patron:\n" . Dumper(shift()); }
12 my $cache_client = OpenSRF::Utils::Cache->new( "global", 0 );
13
14
15 __PACKAGE__->register_method(
16         method  => "update_patron",
17         api_name        => "open-ils.actor.patron.update",
18 );
19
20
21 sub update_patron {
22         my( $self, $client, $user_session, $patron ) = @_;
23
24         my $session = $apputils->start_db_session();
25         my $err = undef;
26
27         warn $user_session . " " . $patron . "\n";
28         _d($patron);
29
30         my $user_obj = 
31                 OpenILS::Application::AppUtils->check_user_session( 
32                                 $user_session ); #throws EX on error
33
34         # XXX does this user have permission to add/create users.  Granularity?
35
36         # $new_patron is the patron in progress.  $patron is the original patron
37         # passed in with the method.  new_patron will change as the components
38         # of patron are added/updated.
39
40         my $new_patron;
41
42         try {
43                 # create/update the patron first so we can use his id
44                 if($patron->isnew()) {
45                         $new_patron = _add_patron(
46                                         $session, _clone_patron($patron));
47                 } else { 
48                         $new_patron = $patron; 
49                 }
50
51                 $new_patron = _add_update_addresses($session, $patron, $new_patron);
52                 $new_patron = _add_update_cards($session, $patron, $new_patron);
53                 $new_patron = _add_survey_responses($session, $patron, $new_patron);
54                 $new_patron     = _create_stat_maps($user_session, $patron, $new_patron);
55
56                 # re-update the patron if anything has happened to him during this process
57                 if($new_patron->ischanged()) {
58                         $new_patron = _update_patron($session, $new_patron);
59                 }
60                 $apputils->commit_db_session($session);
61
62         } catch Error with { 
63                 my $e = shift;
64                 $err =  "-*- Failure adding user: $e";
65                 $apputils->rollback_db_session($session);
66                 warn $err;
67         };
68
69         if($err) { throw OpenSRF::EX::ERROR ($err); }
70         warn "Patron Update/Create complete\n";
71         return flesh_user($new_patron->id());
72 }
73
74
75 __PACKAGE__->register_method(
76         method  => "user_retrieve_fleshed_by_id",
77         api_name        => "open-ils.actor.user.fleshed.retrieve",);
78
79 sub user_retrieve_fleshed_by_id {
80         my( $self, $client, $user_session, $user_id ) = @_;
81         my $user_obj = $apputils->check_user_session( $user_session ); 
82         return flesh_user($user_id);
83 }
84
85
86 sub flesh_user {
87         my $id = shift;
88         my $session = shift;
89
90         my $kill = 0;
91
92         if(!$session) {
93                 $session = OpenSRF::AppSession->create("open-ils.storage");
94                 $kill = 1;
95         }
96
97         # grab the user with the given card
98         my $ureq = $session->request(
99                         "open-ils.storage.direct.actor.user.retrieve",
100                         $id);
101         my $user = $ureq->gather(1);
102
103         # grab the cards
104         my $cards_req = $session->request(
105                         "open-ils.storage.direct.actor.card.search.usr",
106                         $user->id() );
107         $user->cards( $cards_req->gather(1) );
108
109         my $add_req = $session->request(
110                         "open-ils.storage.direct.actor.user_address.search.usr",
111                         $user->id() );
112         $user->addresses( $add_req->gather(1) );
113
114         my $stat_req = $session->request(
115                 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr",
116                 $user->id() );
117         $user->stat_cat_entries($stat_req->gather(1));
118
119         if($kill) { $session->disconnect(); }
120         $user->clear_passwd();
121         warn Dumper $user;
122
123         return $user;
124
125 }
126
127
128 # clone and clear stuff that would break the database
129 sub _clone_patron {
130         my $patron = shift;
131
132         my $new_patron = Fieldmapper::actor::user->new();
133
134         my $fmap = $Fieldmapper::fieldmap;
135         no strict; # shallow clone, may be useful in the fieldmapper
136         for my $field 
137                 (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
138                         $new_patron->$field( $patron->$field() );
139         }
140         use strict;
141
142         # clear these
143         $new_patron->clear_billing_address();
144         $new_patron->clear_mailing_address();
145         $new_patron->clear_addresses();
146         $new_patron->clear_card();
147         $new_patron->clear_cards();
148         $new_patron->clear_id();
149         $new_patron->clear_isnew();
150         $new_patron->clear_changed();
151         $new_patron->clear_deleted();
152         $new_patron->clear_stat_cat_entries();
153
154         return $new_patron;
155 }
156
157
158 sub _add_patron {
159         my $session             = shift;
160         my $patron              = shift;
161
162         warn "Creating new patron\n";
163         _d($patron);
164
165         my $req = $session->request(
166                 "open-ils.storage.direct.actor.user.create",$patron);
167         my $id = $req->gather(1);
168         if(!$id) { throw OpenSRF::EX::ERROR ("Unable to create new user"); }
169         warn "Created new patron with id $id\n";
170
171         # retrieve the patron from the db to collect defaults
172         my $ureq = $session->request(
173                         "open-ils.storage.direct.actor.user.retrieve",
174                         $id);
175         return $ureq->gather(1);
176 }
177
178
179 sub _update_patron {
180         my( $session, $patron) = @_;
181
182         warn "updating patron " . Dumper($patron) . "\n";
183
184         my $req = $session->request(
185                 "open-ils.storage.direct.actor.user.update",$patron );
186         my $status = $req->gather(1);
187         if(!defined($status)) { 
188                 throw OpenSRF::EX::ERROR 
189                         ("Unknown error updating patron"); 
190         }
191         return $patron;
192 }
193
194
195 sub _add_update_addresses {
196         my $session = shift;
197         my $patron = shift;
198         my $new_patron = shift;
199
200         my $current_id; # id of the address before creation
201
202         for my $address (@{$patron->addresses()}) {
203
204                 $address->usr($new_patron->id());
205
206                 if(ref($address) and $address->isnew()) {
207                         warn "Adding new address at street " . $address->street1() . "\n";
208
209                         $current_id = $address->id();
210                         $address = _add_address($session,$address);
211
212                         if( $patron->billing_address() and 
213                                         $patron->billing_address() == $current_id ) {
214                                 $new_patron->billing_address($address->id());
215                                 $new_patron->ischanged(1);
216                         }
217
218                         if( $patron->mailing_address() and
219                                         $patron->mailing_address() == $current_id ) {
220                                 $new_patron->mailing_address($address->id());
221                                 $new_patron->ischanged(1);
222                         }
223
224                 } elsif( ref($address) and $address->ischanged() ) {
225                         warn "Updating address at street " . $address->street1();
226                         $address->usr($new_patron->id());
227                         _update_address($session,$address);
228
229                 } elsif( ref($address) and $address->isdeleted() ) {
230                         warn "Deleting address at street " . $address->street1();
231
232                         if( $address->id() == $new_patron->mailing_address() ) {
233                                 $new_patron->clear_mailing_address();
234                                 _update_patron($session, $new_patron);
235                         }
236
237                         if( $address->id() == $new_patron->billing_address() ) {
238                                 $new_patron->clear_billing_address();
239                                 _update_patron($session, $new_patron);
240                         }
241
242                         _delete_address($session,$address);
243                 }
244         }
245
246         return $new_patron;
247 }
248
249
250 # adds an address to the db and returns the address with new id
251 sub _add_address {
252         my($session, $address) = @_;
253         $address->clear_id();
254
255         # put the address into the database
256         my $req = $session->request(
257                 "open-ils.storage.direct.actor.user_address.create",
258                 $address );
259
260         #update the id
261         my $id = $req->gather(1);
262         if(!$id) { 
263                 throw OpenSRF::EX::ERROR 
264                         ("Unable to create new user address"); 
265         }
266
267         warn "Created address with id $id\n";
268
269         # update all the necessary id's
270         $address->id( $id );
271         return $address;
272 }
273
274
275 sub _update_address {
276         my( $session, $address ) = @_;
277         my $req = $session->request(
278                 "open-ils.storage.direct.actor.user_address.update",
279                 $address );
280         my $status = $req->gather(1);
281         if(!defined($status)) { 
282                 throw OpenSRF::EX::ERROR 
283                         ("Unknown error updating address"); 
284         }
285         return $address;
286 }
287
288
289
290 sub _add_update_cards {
291
292         my $session = shift;
293         my $patron = shift;
294         my $new_patron = shift;
295
296         my $virtual_id; #id of the card before creation
297         for my $card (@{$patron->cards()}) {
298
299                 $card->usr($new_patron->id());
300
301                 if(ref($card) and $card->isnew()) {
302
303                         $virtual_id = $card->id();
304                         $card = _add_card($session,$card);
305
306                         if($patron->card() == $virtual_id) {
307                                 $new_patron->card($card->id());
308                                 $new_patron->ischanged(1);
309                         }
310
311                 } elsif( ref($card) and $card->ischanged() ) {
312                         $card->usr($new_patron->id());
313                         _update_card($session, $card);
314                 }
315         }
316         return $new_patron;
317 }
318
319
320 # adds an card to the db and returns the card with new id
321 sub _add_card {
322         my( $session, $card ) = @_;
323         $card->clear_id();
324
325         warn "Adding card with barcode " . $card->barcode() . "\n";
326         my $req = $session->request(
327                 "open-ils.storage.direct.actor.card.create",
328                 $card );
329
330         my $id = $req->gather(1);
331         if(!$id) { 
332                 throw OpenSRF::EX::ERROR 
333                         ("Unknown error creating card"); 
334         }
335
336         $card->id($id);
337         warn "Created patron card with id $id\n";
338         return $card;
339 }
340
341
342 sub _update_card {
343         my( $session, $card ) = @_;
344         warn Dumper $card;
345
346         my $req = $session->request(
347                 "open-ils.storage.direct.actor.card.update",
348                 $card );
349         my $status = $req->gather(1);
350         if(!defined($status)) { 
351                 throw OpenSRF::EX::ERROR 
352                         ("Unknown error updating card"); 
353         }
354         return $card;
355 }
356
357
358
359
360 sub _delete_address {
361         my( $session, $address ) = @_;
362
363         warn "Deleting address " . $address->street1() . "\n";
364
365         my $req = $session->request(
366                 "open-ils.storage.direct.actor.user_address.delete",
367                 $address );
368         my $status = $req->gather(1);
369         if(!defined($status)) { 
370                 throw OpenSRF::EX::ERROR 
371                         ("Unknown error updating address"); 
372         }
373         warn "Delete address status is $status\n";
374 }
375
376
377
378 sub _add_survey_responses {
379         my ($session, $patron, $new_patron) = @_;
380
381         warn "updating responses for user " . $new_patron->id . "\n";
382
383         my $responses = $patron->survey_responses;
384         for my $resp( @$responses ) {
385                 $resp->usr($new_patron->id);
386         }
387
388         my $status = $apputils->simple_scalar_request(
389                 "open-ils.circ", 
390                 "open-ils.circ.survey.submit.user_id",
391                 $responses );
392
393         return $new_patron;
394 }
395
396
397 sub _create_stat_maps {
398
399         my($user_session, $patron, $new_patron) = @_;
400         my $maps = $patron->stat_cat_entries();
401
402         my $session = OpenSRF::AppSession->create("open-ils.circ");
403
404         for my $map (@$maps) {
405
406                 next unless($map->isnew() || $map->ischanged());
407
408                 my $method = "open-ils.circ.stat_cat.actor.user_map.update";
409                 if($map->isnew()) {
410                         $method = "open-ils.circ.stat_cat.actor.user_map.create";
411                 }
412
413                 warn "Updating stat entry with method $method and 
414                         session $user_session and map $map\n";
415
416                 my $req = $session->request($method, $user_session, $map);
417                 my $status = $req->gather(1);
418
419                 warn "Updated\n";
420
421                 if(!$status) {
422                         throw OpenSRF::EX::ERROR 
423                                 ("Error updating stat map with method $method");        
424                 }
425         }
426
427         $session->disconnect();
428         return $new_patron;
429 }
430
431
432
433 __PACKAGE__->register_method(
434         method  => "search_username",
435         api_name        => "open-ils.actor.user.search.username",
436 );
437
438 sub search_username {
439         my($self, $client, $username) = @_;
440         my $users = OpenILS::Application::AppUtils->simple_scalar_request(
441                         "open-ils.storage", 
442                         "open-ils.storage.direct.actor.user.search.usrname",
443                         $username );
444         return $users;
445 }
446
447
448
449
450 __PACKAGE__->register_method(
451         method  => "user_retrieve_by_barcode",
452         api_name        => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
453
454 sub user_retrieve_by_barcode {
455         my($self, $client, $user_session, $barcode) = @_;
456         warn "Searching for user with barcode $barcode\n";
457         my $user_obj = $apputils->check_user_session( $user_session ); 
458
459         my $session = OpenSRF::AppSession->create("open-ils.storage");
460
461         # find the card with the given barcode
462         my $creq        = $session->request(
463                         "open-ils.storage.direct.actor.card.search.barcode",
464                         $barcode );
465         my $card = $creq->gather(1);
466         $card = $card->[0];
467         my $user = flesh_user($card->usr(), $session);
468         $session->disconnect();
469         return $user;
470
471 }
472
473
474
475 __PACKAGE__->register_method(
476         method  => "get_user_by_id",
477         api_name        => "open-ils.actor.user.retrieve",);
478
479 sub get_user_by_id {
480         my ($self, $client, $user_session, $id) = @_;
481
482         my $user_obj = $apputils->check_user_session( $user_session ); 
483
484         return $apputils->simple_scalar_request(
485                 "open-ils.storage",
486                 "open-ils.storage.direct.actor.user.retrieve",
487                 $id );
488 }
489
490
491
492 __PACKAGE__->register_method(
493         method  => "get_org_types",
494         api_name        => "open-ils.actor.org_types.retrieve",);
495
496 my $org_types;
497 sub get_org_types {
498         my($self, $client) = @_;
499
500         return $org_types if $org_types;
501          return $org_types = 
502                  $apputils->simple_scalar_request(
503                         "open-ils.storage",
504                         "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
505 }
506
507
508
509 __PACKAGE__->register_method(
510         method  => "get_user_profiles",
511         api_name        => "open-ils.actor.user.profiles.retrieve",
512 );
513
514 my $user_profiles;
515 sub get_user_profiles {
516         return $user_profiles if $user_profiles;
517
518         return $user_profiles = 
519                 $apputils->simple_scalar_request(
520                         "open-ils.storage",
521                         "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
522 }
523
524
525
526 __PACKAGE__->register_method(
527         method  => "get_user_ident_types",
528         api_name        => "open-ils.actor.user.ident_types.retrieve",
529 );
530 my $ident_types;
531 sub get_user_ident_types {
532         return $ident_types if $ident_types;
533         return $ident_types = 
534                 $apputils->simple_scalar_request(
535                 "open-ils.storage",
536                 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
537 }
538
539
540
541
542 __PACKAGE__->register_method(
543         method  => "get_org_unit",
544         api_name        => "open-ils.actor.org_unit.retrieve",
545 );
546
547 sub get_org_unit {
548
549         my( $self, $client, $user_session ) = @_;
550
551         my $user_obj = 
552                 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
553
554         my $home_ou = OpenILS::Application::AppUtils->simple_scalar_request(
555                 "open-ils.storage",
556                 "open-ils.storage.direct.actor.org_unit.retrieve", 
557                 $user_obj->home_ou );
558
559         return $home_ou;
560 }
561
562
563 # build the org tree
564
565 __PACKAGE__->register_method(
566         method  => "get_org_tree",
567         api_name        => "open-ils.actor.org_tree.retrieve",
568         argc            => 1, 
569         note            => "Returns the entire org tree structure",
570 );
571
572 sub get_org_tree {
573         my( $self, $client) = @_;
574
575         # see if it's in the cache
576         warn "Getting ORG Tree\n";
577         my $tree = $cache_client->get_cache('orgtree');
578         if($tree) { 
579                 warn "Found orgtree in cache. returning...\n";
580                 return $tree; 
581         }
582
583         my $orglist = $apputils->simple_scalar_request( 
584                 "open-ils.storage", 
585                 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
586
587         $tree = $self->build_org_tree($orglist);
588         $cache_client->put_cache('orgtree', $tree);
589
590         return $tree;
591
592 }
593
594 # turns an org list into an org tree
595 sub build_org_tree {
596
597         my( $self, $orglist) = @_;
598
599         return $orglist unless ( 
600                         ref($orglist) and @$orglist > 1 );
601
602         my @list = sort { 
603                 $a->ou_type <=> $b->ou_type ||
604                 $a->name cmp $b->name } @$orglist;
605
606         for my $org (@list) {
607
608                 next unless ($org and defined($org->parent_ou));
609                 my ($parent) = grep { $_->id == $org->parent_ou } @list;
610                 next unless $parent;
611
612                 $parent->children([]) unless defined($parent->children); 
613                 push( @{$parent->children}, $org );
614         }
615
616         return $list[0];
617
618 }
619
620
621 __PACKAGE__->register_method(
622         method  => "get_org_descendants",
623         api_name        => "open-ils.actor.org_tree.descendants.retrieve"
624 );
625
626 # depth is optional.  org_unit is the id
627 sub get_org_descendants {
628         my( $self, $client, $org_unit, $depth ) = @_;
629         my $orglist = $apputils->simple_scalar_request(
630                         "open-ils.storage", 
631                         "open-ils.storage.actor.org_unit.descendants.atomic",
632                         $org_unit, $depth );
633         return $self->build_org_tree($orglist);
634 }
635
636
637 __PACKAGE__->register_method(
638         method  => "get_org_ancestors",
639         api_name        => "open-ils.actor.org_tree.ancestors.retrieve"
640 );
641
642 # depth is optional.  org_unit is the id
643 sub get_org_ancestors {
644         my( $self, $client, $org_unit, $depth ) = @_;
645         my $orglist = $apputils->simple_scalar_request(
646                         "open-ils.storage", 
647                         "open-ils.storage.actor.org_unit.ancestors.atomic",
648                         $org_unit, $depth );
649         return $self->build_org_tree($orglist);
650 }
651
652
653 __PACKAGE__->register_method(
654         method  => "get_standings",
655         api_name        => "open-ils.actor.standings.retrieve"
656 );
657
658 my $user_standings;
659 sub get_standings {
660         return $user_standings if $user_standings;
661         return $user_standings = 
662                 $apputils->simple_scalar_request(
663                         "open-ils.storage",
664                         "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
665 }
666
667
668
669 __PACKAGE__->register_method(
670         method  => "get_my_org_path",
671         api_name        => "open-ils.actor.org_unit.full_path.retrieve"
672 );
673
674 sub get_my_org_path {
675         my( $self, $client, $user_session, $org_id ) = @_;
676         my $user_obj = $apputils->check_user_session($user_session); 
677         if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
678
679         return $apputils->simple_scalar_request(
680                 "open-ils.storage",
681                 "open-ils.storage.actor.org_unit.full_path.atomic",
682                 $org_id );
683 }
684
685
686 __PACKAGE__->register_method(
687         method  => "patron_adv_search",
688         api_name        => "open-ils.actor.patron.search.advanced" );
689
690 sub patron_adv_search {
691         my( $self, $client, $staff_login, $search_hash ) = @_;
692
693         use Data::Dumper;
694         warn "patron adv with $staff_login and search " . 
695                 Dumper($search_hash) . "\n";
696
697         my $session = OpenSRF::AppSession->create("open-ils.storage");
698         my $req = $session->request(
699                 "open-ils.storage.actor.user.crazy_search", $search_hash);
700
701         my $ans = $req->gather(1);
702         $session->disconnect();
703         return $ans;
704
705 }
706
707
708
709
710
711
712
713
714 1;
715
716
717
718
719 __END__
720
721
722 some old methods that may be good to keep around for now
723
724 sub _delete_card {
725         my( $session, $card ) = @_;
726
727         warn "Deleting card with barcode " . $card->barcode() . "\n";
728         my $req = $session->request(
729                 "open-ils.storage.direct.actor.card.delete",
730                 $card );
731         my $status = $req->gather(1);
732         if(!defined($status)) { 
733                 throw OpenSRF::EX::ERROR 
734                         ("Unknown error updating card"); 
735         }
736 }
737
738
739
740 # deletes the patron and any attached addresses and cards
741 __PACKAGE__->register_method(
742         method  => "delete_patron",
743         api_name        => "open-ils.actor.patron.delete",
744 );
745
746 sub delete_patron {
747
748         my( $self, $client, $patron ) = @_;
749         my $session = $apputils->start_db_session();
750         my $err = undef;
751
752         try {
753
754                 $patron->clear_mailing_address();
755                 $patron->clear_billing_address();
756                 $patron->ischanged(1);
757
758                 _update_patron($session, $patron);
759                 _delete_address($session,$_) for (@{$patron->addresses()});
760                 _delete_card($session,$_) for (@{$patron->cards()});
761                 _delete_patron($session,$patron);
762                 $apputils->commit_db_session($session);
763
764         } catch Error with {
765                 my $e = shift;
766                 $err =  "-*- Failure deleting user: $e";
767                 $apputils->rollback_db_session($session);
768                 warn $err;
769         };
770
771         if($err) { throw OpenSRF::EX::ERROR ($err); }
772         warn "Patron Delete complete\n";
773         return 1;
774 }
775
776 sub _delete_patron {
777         my( $session, $patron ) = @_;
778
779         warn "Deleting patron " . $patron->usrname() . "\n";
780
781         my $req = $session->request(
782                 "open-ils.storage.direct.actor.user.delete",
783                 $patron );
784         my $status = $req->gather(1);
785         if(!defined($status)) { 
786                 throw OpenSRF::EX::ERROR 
787                         ("Unknown error updating patron"); 
788         }
789 }
790