1 package OpenILS::Application::Actor;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
6 use Digest::MD5 qw(md5_hex);
8 use OpenSRF::EX qw(:try);
11 use OpenILS::Application::AppUtils;
12 use OpenILS::Utils::Fieldmapper;
13 use OpenILS::Application::Search::Actor;
15 my $apputils = "OpenILS::Application::AppUtils";
16 sub _d { warn "Patron:\n" . Dumper(shift()); }
17 my $cache_client = OpenSRF::Utils::Cache->new("global", 0);
20 __PACKAGE__->register_method(
21 method => "update_patron",
22 api_name => "open-ils.actor.patron.update",);
25 my( $self, $client, $user_session, $patron ) = @_;
27 my $session = $apputils->start_db_session();
30 warn $user_session . " " . $patron . "\n";
34 OpenILS::Application::AppUtils->check_user_session(
35 $user_session ); #throws EX on error
37 # XXX does this user have permission to add/create users. Granularity?
39 # $new_patron is the patron in progress. $patron is the original patron
40 # passed in with the method. new_patron will change as the components
41 # of patron are added/updated.
46 # create/update the patron first so we can use his id
47 if($patron->isnew()) {
48 $new_patron = _add_patron(
49 $session, _clone_patron($patron));
50 if(UNIVERSAL::isa($new_patron, "OpenILS::EX")) {
51 $client->respond_complete($new_patron->ex);
56 $new_patron = $patron;
59 $new_patron = _add_update_addresses($session, $patron, $new_patron);
60 $new_patron = _add_update_cards($session, $patron, $new_patron);
62 if(UNIVERSAL::isa($new_patron,"OpenILS::EX")) {
63 $client->respond_complete($new_patron->ex);
67 $new_patron = _add_survey_responses($session, $patron, $new_patron);
68 $new_patron = _create_stat_maps($session, $user_session, $patron, $new_patron);
70 # re-update the patron if anything has happened to him during this process
71 if($new_patron->ischanged()) {
72 $new_patron = _update_patron($session, $new_patron);
74 $apputils->commit_db_session($session);
79 $err = "-*- Failure adding user: $e";
80 $apputils->rollback_db_session($session);
84 if($err) { throw OpenSRF::EX::ERROR ($err); }
87 warn "Patron Update/Create complete\n";
88 return flesh_user($new_patron->id());
94 __PACKAGE__->register_method(
95 method => "user_retrieve_fleshed_by_id",
96 api_name => "open-ils.actor.user.fleshed.retrieve",);
98 sub user_retrieve_fleshed_by_id {
99 my( $self, $client, $user_session, $user_id ) = @_;
100 my $user_obj = $apputils->check_user_session( $user_session );
101 return flesh_user($user_id);
112 $session = OpenSRF::AppSession->create("open-ils.storage");
116 # grab the user with the given card
117 my $ureq = $session->request(
118 "open-ils.storage.direct.actor.user.retrieve",
120 my $user = $ureq->gather(1);
123 my $cards_req = $session->request(
124 "open-ils.storage.direct.actor.card.search.usr",
126 $user->cards( $cards_req->gather(1) );
128 my $add_req = $session->request(
129 "open-ils.storage.direct.actor.user_address.search.usr",
131 $user->addresses( $add_req->gather(1) );
133 my $stat_req = $session->request(
134 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr",
136 $user->stat_cat_entries($stat_req->gather(1));
138 if($kill) { $session->disconnect(); }
139 $user->clear_passwd();
147 # clone and clear stuff that would break the database
151 my $new_patron = Fieldmapper::actor::user->new();
153 my $fmap = $Fieldmapper::fieldmap;
154 no strict; # shallow clone, may be useful in the fieldmapper
156 (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
157 $new_patron->$field( $patron->$field() );
162 $new_patron->clear_billing_address();
163 $new_patron->clear_mailing_address();
164 $new_patron->clear_addresses();
165 $new_patron->clear_card();
166 $new_patron->clear_cards();
167 $new_patron->clear_id();
168 $new_patron->clear_isnew();
169 $new_patron->clear_changed();
170 $new_patron->clear_deleted();
171 $new_patron->clear_stat_cat_entries();
181 warn "Creating new patron\n";
184 my $req = $session->request(
185 "open-ils.storage.direct.actor.user.create",$patron);
186 my $id = $req->gather(1);
188 return OpenILS::EX->new("DUPLICATE_USER_USERNAME");
191 # retrieve the patron from the db to collect defaults
192 my $ureq = $session->request(
193 "open-ils.storage.direct.actor.user.retrieve",
196 warn "Created new patron with id $id\n";
198 return $ureq->gather(1);
203 my( $session, $patron) = @_;
205 warn "updating patron " . Dumper($patron) . "\n";
207 my $req = $session->request(
208 "open-ils.storage.direct.actor.user.update",$patron );
209 my $status = $req->gather(1);
210 if(!defined($status)) {
211 throw OpenSRF::EX::ERROR
212 ("Unknown error updating patron");
218 sub _add_update_addresses {
221 my $new_patron = shift;
223 my $current_id; # id of the address before creation
225 for my $address (@{$patron->addresses()}) {
227 $address->usr($new_patron->id());
229 if(ref($address) and $address->isnew()) {
230 warn "Adding new address at street " . $address->street1() . "\n";
232 $current_id = $address->id();
233 $address = _add_address($session,$address);
235 if( $patron->billing_address() and
236 $patron->billing_address() == $current_id ) {
237 $new_patron->billing_address($address->id());
238 $new_patron->ischanged(1);
241 if( $patron->mailing_address() and
242 $patron->mailing_address() == $current_id ) {
243 $new_patron->mailing_address($address->id());
244 $new_patron->ischanged(1);
247 } elsif( ref($address) and $address->ischanged() ) {
248 warn "Updating address at street " . $address->street1();
249 $address->usr($new_patron->id());
250 _update_address($session,$address);
252 } elsif( ref($address) and $address->isdeleted() ) {
253 warn "Deleting address at street " . $address->street1();
255 if( $address->id() == $new_patron->mailing_address() ) {
256 $new_patron->clear_mailing_address();
257 _update_patron($session, $new_patron);
260 if( $address->id() == $new_patron->billing_address() ) {
261 $new_patron->clear_billing_address();
262 _update_patron($session, $new_patron);
265 _delete_address($session,$address);
273 # adds an address to the db and returns the address with new id
275 my($session, $address) = @_;
276 $address->clear_id();
278 # put the address into the database
279 my $req = $session->request(
280 "open-ils.storage.direct.actor.user_address.create",
284 my $id = $req->gather(1);
286 throw OpenSRF::EX::ERROR
287 ("Unable to create new user address");
290 warn "Created address with id $id\n";
292 # update all the necessary id's
298 sub _update_address {
299 my( $session, $address ) = @_;
300 my $req = $session->request(
301 "open-ils.storage.direct.actor.user_address.update",
303 my $status = $req->gather(1);
304 if(!defined($status)) {
305 throw OpenSRF::EX::ERROR
306 ("Unknown error updating address");
313 sub _add_update_cards {
317 my $new_patron = shift;
319 my $virtual_id; #id of the card before creation
320 for my $card (@{$patron->cards()}) {
322 $card->usr($new_patron->id());
324 if(ref($card) and $card->isnew()) {
326 $virtual_id = $card->id();
327 $card = _add_card($session,$card);
328 if(UNIVERSAL::isa($card,"OpenILS::EX")) {
332 if($patron->card() == $virtual_id) {
333 $new_patron->card($card->id());
334 $new_patron->ischanged(1);
337 } elsif( ref($card) and $card->ischanged() ) {
338 $card->usr($new_patron->id());
339 _update_card($session, $card);
346 # adds an card to the db and returns the card with new id
348 my( $session, $card ) = @_;
351 warn "Adding card with barcode " . $card->barcode() . "\n";
352 my $req = $session->request(
353 "open-ils.storage.direct.actor.card.create",
356 my $id = $req->gather(1);
358 return OpenILS::EX->new("DUPLICATE_INVALID_USER_BARCODE");
362 warn "Created patron card with id $id\n";
368 my( $session, $card ) = @_;
371 my $req = $session->request(
372 "open-ils.storage.direct.actor.card.update",
374 my $status = $req->gather(1);
375 if(!defined($status)) {
376 throw OpenSRF::EX::ERROR
377 ("Unknown error updating card");
385 sub _delete_address {
386 my( $session, $address ) = @_;
388 warn "Deleting address " . $address->street1() . "\n";
390 my $req = $session->request(
391 "open-ils.storage.direct.actor.user_address.delete",
393 my $status = $req->gather(1);
394 if(!defined($status)) {
395 throw OpenSRF::EX::ERROR
396 ("Unknown error updating address");
398 warn "Delete address status is $status\n";
403 sub _add_survey_responses {
404 my ($session, $patron, $new_patron) = @_;
406 warn "updating responses for user " . $new_patron->id . "\n";
408 my $responses = $patron->survey_responses;
409 for my $resp( @$responses ) {
410 $resp->usr($new_patron->id);
413 my $status = $apputils->simple_scalar_request(
415 "open-ils.circ.survey.submit.user_id",
422 sub _create_stat_maps {
424 my($session, $user_session, $patron, $new_patron) = @_;
426 my $maps = $patron->stat_cat_entries();
428 for my $map (@$maps) {
430 next unless($map->isnew() || $map->ischanged());
432 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
434 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
437 $map->target_usr($new_patron->id);
439 warn "Updating stat entry with method $method and session $user_session and map $map\n";
441 my $req = $session->request($method, $map);
442 my $status = $req->gather(1);
447 throw OpenSRF::EX::ERROR
448 ("Error updating stat map with method $method");
457 __PACKAGE__->register_method(
458 method => "search_username",
459 api_name => "open-ils.actor.user.search.username",
462 sub search_username {
463 my($self, $client, $username) = @_;
464 my $users = OpenILS::Application::AppUtils->simple_scalar_request(
466 "open-ils.storage.direct.actor.user.search.usrname",
474 __PACKAGE__->register_method(
475 method => "user_retrieve_by_barcode",
476 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
478 sub user_retrieve_by_barcode {
479 my($self, $client, $user_session, $barcode) = @_;
480 warn "Searching for user with barcode $barcode\n";
481 my $user_obj = $apputils->check_user_session( $user_session );
483 my $session = OpenSRF::AppSession->create("open-ils.storage");
485 # find the card with the given barcode
486 my $creq = $session->request(
487 "open-ils.storage.direct.actor.card.search.barcode",
489 my $card = $creq->gather(1);
491 if(!$card || !$card->[0]) {
492 $session->disconnect();
497 my $user = flesh_user($card->usr(), $session);
498 $session->disconnect();
505 __PACKAGE__->register_method(
506 method => "get_user_by_id",
507 api_name => "open-ils.actor.user.retrieve",);
510 my ($self, $client, $user_session, $id) = @_;
512 my $user_obj = $apputils->check_user_session( $user_session );
514 return $apputils->simple_scalar_request(
516 "open-ils.storage.direct.actor.user.retrieve",
522 __PACKAGE__->register_method(
523 method => "get_org_types",
524 api_name => "open-ils.actor.org_types.retrieve",);
528 my($self, $client) = @_;
530 return $org_types if $org_types;
532 $apputils->simple_scalar_request(
534 "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
539 __PACKAGE__->register_method(
540 method => "get_user_profiles",
541 api_name => "open-ils.actor.user.profiles.retrieve",
545 sub get_user_profiles {
546 return $user_profiles if $user_profiles;
548 return $user_profiles =
549 $apputils->simple_scalar_request(
551 "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
556 __PACKAGE__->register_method(
557 method => "get_user_ident_types",
558 api_name => "open-ils.actor.user.ident_types.retrieve",
561 sub get_user_ident_types {
562 return $ident_types if $ident_types;
563 return $ident_types =
564 $apputils->simple_scalar_request(
566 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
572 __PACKAGE__->register_method(
573 method => "get_org_unit",
574 api_name => "open-ils.actor.org_unit.retrieve",
579 my( $self, $client, $user_session, $org_id ) = @_;
582 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
585 $org_id = $user_obj->home_ou;
588 my $home_ou = OpenILS::Application::AppUtils->simple_scalar_request(
590 "open-ils.storage.direct.actor.org_unit.retrieve",
599 __PACKAGE__->register_method(
600 method => "get_org_tree",
601 api_name => "open-ils.actor.org_tree.retrieve",
603 note => "Returns the entire org tree structure",
607 my( $self, $client) = @_;
609 # see if it's in the cache
610 warn "Getting ORG Tree\n";
611 my $tree = $cache_client->get_cache('orgtree');
613 warn "Found orgtree in cache. returning...\n";
617 my $orglist = $apputils->simple_scalar_request(
619 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
621 $tree = $self->build_org_tree($orglist);
622 $cache_client->put_cache('orgtree', $tree);
628 # turns an org list into an org tree
631 my( $self, $orglist) = @_;
633 return $orglist unless (
634 ref($orglist) and @$orglist > 1 );
637 $a->ou_type <=> $b->ou_type ||
638 $a->name cmp $b->name } @$orglist;
640 for my $org (@list) {
642 next unless ($org and defined($org->parent_ou));
643 my ($parent) = grep { $_->id == $org->parent_ou } @list;
646 $parent->children([]) unless defined($parent->children);
647 push( @{$parent->children}, $org );
655 __PACKAGE__->register_method(
656 method => "get_org_descendants",
657 api_name => "open-ils.actor.org_tree.descendants.retrieve"
660 # depth is optional. org_unit is the id
661 sub get_org_descendants {
662 my( $self, $client, $org_unit, $depth ) = @_;
663 my $orglist = $apputils->simple_scalar_request(
665 "open-ils.storage.actor.org_unit.descendants.atomic",
667 return $self->build_org_tree($orglist);
671 __PACKAGE__->register_method(
672 method => "get_org_ancestors",
673 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
676 # depth is optional. org_unit is the id
677 sub get_org_ancestors {
678 my( $self, $client, $org_unit, $depth ) = @_;
679 my $orglist = $apputils->simple_scalar_request(
681 "open-ils.storage.actor.org_unit.ancestors.atomic",
683 return $self->build_org_tree($orglist);
687 __PACKAGE__->register_method(
688 method => "get_standings",
689 api_name => "open-ils.actor.standings.retrieve"
694 return $user_standings if $user_standings;
695 return $user_standings =
696 $apputils->simple_scalar_request(
698 "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
703 __PACKAGE__->register_method(
704 method => "get_my_org_path",
705 api_name => "open-ils.actor.org_unit.full_path.retrieve"
708 sub get_my_org_path {
709 my( $self, $client, $user_session, $org_id ) = @_;
710 my $user_obj = $apputils->check_user_session($user_session);
711 if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
713 return $apputils->simple_scalar_request(
715 "open-ils.storage.actor.org_unit.full_path.atomic",
720 __PACKAGE__->register_method(
721 method => "patron_adv_search",
722 api_name => "open-ils.actor.patron.search.advanced" );
724 sub patron_adv_search {
725 my( $self, $client, $staff_login, $search_hash ) = @_;
728 warn "patron adv with $staff_login and search " .
729 Dumper($search_hash) . "\n";
731 my $session = OpenSRF::AppSession->create("open-ils.storage");
732 my $req = $session->request(
733 "open-ils.storage.actor.user.crazy_search", $search_hash);
735 my $ans = $req->gather(1);
737 my %hash = map { ($_ =>1) } @$ans;
738 $ans = [ keys %hash ];
740 warn "Returning @$ans\n";
742 $session->disconnect();
749 sub _verify_password {
750 my($user_session, $password) = @_;
751 my $user_obj = $apputils->check_user_session($user_session);
753 #grab the user with password
754 $user_obj = $apputils->simple_scalar_request(
756 "open-ils.storage.direct.actor.user.retrieve",
759 if($user_obj->passwd eq $password) {
767 __PACKAGE__->register_method(
768 method => "update_password",
769 api_name => "open-ils.actor.user.password.update");
771 __PACKAGE__->register_method(
772 method => "update_password",
773 api_name => "open-ils.actor.user.username.update");
775 __PACKAGE__->register_method(
776 method => "update_password",
777 api_name => "open-ils.actor.user.email.update");
779 sub update_password {
780 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
782 my $user_obj = $apputils->check_user_session($user_session);
783 warn "Updating user with method " .$self->api_name . "\n";
785 if($self->api_name =~ /password/) {
787 #make sure they know the current password
788 if(!_verify_password($user_session, md5_hex($current_password))) {
789 return OpenILS::EX->new("USER_WRONG_PASSWORD")->ex;
792 $user_obj->passwd($new_value);
794 elsif($self->api_name =~ /username/) {
795 $user_obj->usrname($new_value);
798 elsif($self->api_name =~ /email/) {
799 $user_obj->email($new_value);
802 my $session = $apputils->start_db_session();
803 $user_obj = _update_patron($session, $user_obj);
804 $apputils->commit_db_session($session);
806 if($user_obj) { return 1; }
824 some old methods that may be good to keep around for now
827 my( $session, $card ) = @_;
829 warn "Deleting card with barcode " . $card->barcode() . "\n";
830 my $req = $session->request(
831 "open-ils.storage.direct.actor.card.delete",
833 my $status = $req->gather(1);
834 if(!defined($status)) {
835 throw OpenSRF::EX::ERROR
836 ("Unknown error updating card");
842 # deletes the patron and any attached addresses and cards
843 __PACKAGE__->register_method(
844 method => "delete_patron",
845 api_name => "open-ils.actor.patron.delete",
850 my( $self, $client, $patron ) = @_;
851 my $session = $apputils->start_db_session();
856 $patron->clear_mailing_address();
857 $patron->clear_billing_address();
858 $patron->ischanged(1);
860 _update_patron($session, $patron);
861 _delete_address($session,$_) for (@{$patron->addresses()});
862 _delete_card($session,$_) for (@{$patron->cards()});
863 _delete_patron($session,$patron);
864 $apputils->commit_db_session($session);
868 $err = "-*- Failure deleting user: $e";
869 $apputils->rollback_db_session($session);
873 if($err) { throw OpenSRF::EX::ERROR ($err); }
874 warn "Patron Delete complete\n";
879 my( $session, $patron ) = @_;
881 warn "Deleting patron " . $patron->usrname() . "\n";
883 my $req = $session->request(
884 "open-ils.storage.direct.actor.user.delete",
886 my $status = $req->gather(1);
887 if(!defined($status)) {
888 throw OpenSRF::EX::ERROR
889 ("Unknown error updating patron");