1 package OpenILS::Application::Actor;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
5 $Data::Dumper::Indent = 0;
8 use Digest::MD5 qw(md5_hex);
10 use OpenSRF::EX qw(:try);
14 use OpenILS::Application::AppUtils;
16 use OpenILS::Utils::Fieldmapper;
17 use OpenILS::Application::Search::Actor;
18 use OpenILS::Utils::ModsParser;
19 use OpenSRF::Utils::Logger qw/$logger/;
20 use OpenSRF::Utils qw/:datetime/;
22 use OpenSRF::Utils::Cache;
25 use DateTime::Format::ISO8601;
27 use OpenILS::Application::Actor::Container;
30 OpenILS::Application::Actor::Container->initialize();
33 my $apputils = "OpenILS::Application::AppUtils";
36 sub _d { warn "Patron:\n" . Dumper(shift()); }
41 my $set_user_settings;
44 __PACKAGE__->register_method(
45 method => "set_user_settings",
46 api_name => "open-ils.actor.patron.settings.update",
48 sub set_user_settings {
49 my( $self, $client, $user_session, $uid, $settings ) = @_;
51 $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
53 my( $staff, $user, $evt ) =
54 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );
59 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
61 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper($params));
63 return $apputils->simplereq(
65 'open-ils.storage.direct.actor.user_setting.batch.merge', $params );
71 __PACKAGE__->register_method(
72 method => "set_ou_settings",
73 api_name => "open-ils.actor.org_unit.settings.update",
76 my( $self, $client, $user_session, $ouid, $settings ) = @_;
78 my( $staff, $evt ) = $apputils->checkses( $user_session );
80 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_UNIT' );
85 map { [{ org_unit => $ouid, name => $_}, {value => $$settings{$_}}] } keys %$settings;
87 $logger->activity("Updating org unit [$ouid] settings with: " . Dumper($params));
89 return $apputils->simplereq(
91 'open-ils.storage.direct.actor.org_unit_setting.merge', @$params );
95 my $fetch_user_settings;
96 my $fetch_ou_settings;
98 __PACKAGE__->register_method(
99 method => "user_settings",
100 api_name => "open-ils.actor.patron.settings.retrieve",
103 my( $self, $client, $user_session, $uid ) = @_;
105 my( $staff, $user, $evt ) =
106 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
109 $logger->debug("User " . $staff->id . " fetching user $uid\n");
110 my $s = $apputils->simplereq(
112 'open-ils.storage.direct.actor.user_setting.search.usr.atomic',$uid );
114 return { map { ($_->name,$_->value) } @$s };
119 __PACKAGE__->register_method(
120 method => "ou_settings",
121 api_name => "open-ils.actor.org_unit.settings.retrieve",
124 my( $self, $client, $ouid ) = @_;
126 my $s = $apputils->simplereq(
128 'open-ils.storage.direct.actor.org_unit_setting.search.org_unit.atomic', $ouid);
130 return { map { ($_->name,$_->value) } @$s };
135 __PACKAGE__->register_method(
136 method => "update_patron",
137 api_name => "open-ils.actor.patron.update",);
140 my( $self, $client, $user_session, $patron ) = @_;
142 my $session = $apputils->start_db_session();
145 $logger->info("Creating new patron...") if $patron->isnew;
146 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
148 my( $user_obj, $evt ) = $U->checkses($user_session);
151 # XXX does this user have permission to add/create users. Granularity?
152 # $new_patron is the patron in progress. $patron is the original patron
153 # passed in with the method. new_patron will change as the components
154 # of patron are added/updated.
158 # unflesh the real items on the patron
159 $patron->card( $patron->card->id ) if(ref($patron->card));
160 $patron->billing_address( $patron->billing_address->id )
161 if(ref($patron->billing_address));
162 $patron->mailing_address( $patron->mailing_address->id )
163 if(ref($patron->mailing_address));
165 # create/update the patron first so we can use his id
166 if($patron->isnew()) {
167 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
169 } else { $new_patron = $patron; }
171 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
174 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
177 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
180 # re-update the patron if anything has happened to him during this process
181 if($new_patron->ischanged()) {
182 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
186 #$session = OpenSRF::AppSession->create("open-ils.storage"); # why did i put this here?
188 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
191 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
194 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
197 $apputils->commit_db_session($session);
199 #warn "Patron Update/Create complete\n";
200 return flesh_user($new_patron->id());
206 __PACKAGE__->register_method(
207 method => "user_retrieve_fleshed_by_id",
208 api_name => "open-ils.actor.user.fleshed.retrieve",);
210 sub user_retrieve_fleshed_by_id {
211 my( $self, $client, $user_session, $user_id ) = @_;
213 my( $requestor, $target, $evt ) = $apputils->
214 checkses_requestor( $user_session, $user_id, 'VIEW_USER' );
217 return flesh_user($user_id);
221 # fleshes: card, cards, address, addresses, stat_cat_entries, standing_penalties
229 $session = OpenSRF::AppSession->create("open-ils.storage");
233 # grab the user with the given id
234 my $ureq = $session->request(
235 "open-ils.storage.direct.actor.user.retrieve", $id);
236 my $user = $ureq->gather(1);
238 if(!$user) { return undef; }
241 my $cards_req = $session->request(
242 "open-ils.storage.direct.actor.card.search.usr.atomic",
244 $user->cards( $cards_req->gather(1) );
246 for my $c(@{$user->cards}) {
247 if($c->id == $user->card || $c->id eq $user->card ) {
248 #warn "Setting my card to " . $c->id . "\n";
253 my $add_req = $session->request(
254 "open-ils.storage.direct.actor.user_address.search.usr.atomic",
256 $user->addresses( $add_req->gather(1) );
258 for my $c(@{$user->addresses}) {
259 if($c->id eq $user->billing_address ) { $user->billing_address($c); }
260 if($c->id eq $user->mailing_address ) { $user->mailing_address($c); }
263 my $stat_req = $session->request(
264 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr.atomic",
266 $user->stat_cat_entries($stat_req->gather(1));
268 my $standing_penalties_req = $session->request(
269 "open-ils.storage.direct.actor.user_standing_penalty.search.usr.atomic",
271 $user->standing_penalties($standing_penalties_req->gather(1));
273 if($kill) { $session->disconnect(); }
274 $user->clear_passwd();
280 # clone and clear stuff that would break the database
284 my $new_patron = $patron->clone;
286 # Using the Fieldmapper clone method
287 #my $new_patron = Fieldmapper::actor::user->new();
289 #my $fmap = $Fieldmapper::fieldmap;
290 #no strict; # shallow clone, may be useful in the fieldmapper
292 # (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
293 # $new_patron->$field( $patron->$field() );
298 $new_patron->clear_billing_address();
299 $new_patron->clear_mailing_address();
300 $new_patron->clear_addresses();
301 $new_patron->clear_card();
302 $new_patron->clear_cards();
303 $new_patron->clear_id();
304 $new_patron->clear_isnew();
305 $new_patron->clear_ischanged();
306 $new_patron->clear_isdeleted();
307 $new_patron->clear_stat_cat_entries();
308 $new_patron->clear_permissions();
309 $new_patron->clear_standing_penalties();
319 my $user_obj = shift;
321 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
322 return (undef, $evt) if $evt;
324 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
326 my $id = $session->request(
327 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
328 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
330 $logger->info("Successfully created new user [$id] in DB");
332 return ( $session->request(
333 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
338 my( $session, $patron, $user_obj) = @_;
340 $logger->info("Updating patron ".$patron->id." in DB");
341 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
342 return (undef, $evt) if $evt;
344 $patron->clear_passwd unless $patron->passwd;
346 my $stat = $session->request(
347 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
348 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
354 sub _add_update_addresses {
358 my $new_patron = shift;
362 my $current_id; # id of the address before creation
364 for my $address (@{$patron->addresses()}) {
366 $address->usr($new_patron->id());
368 if(ref($address) and $address->isnew()) {
370 $current_id = $address->id();
371 ($address, $evt) = _add_address($session,$address);
372 return (undef, $evt) if $evt;
374 if( $patron->billing_address() and
375 $patron->billing_address() == $current_id ) {
376 $new_patron->billing_address($address->id());
377 $new_patron->ischanged(1);
380 if( $patron->mailing_address() and
381 $patron->mailing_address() == $current_id ) {
382 $new_patron->mailing_address($address->id());
383 $new_patron->ischanged(1);
386 } elsif( ref($address) and $address->ischanged() ) {
388 $address->usr($new_patron->id());
389 ($address, $evt) = _update_address($session, $address);
390 return (undef, $evt) if $evt;
392 } elsif( ref($address) and $address->isdeleted() ) {
394 if( $address->id() == $new_patron->mailing_address() ) {
395 $new_patron->clear_mailing_address();
396 ($new_patron, $evt) = _update_patron($session, $new_patron);
397 return (undef, $evt) if $evt;
400 if( $address->id() == $new_patron->billing_address() ) {
401 $new_patron->clear_billing_address();
402 ($new_patron, $evt) = _update_patron($session, $new_patron);
403 return (undef, $evt) if $evt;
406 $evt = _delete_address($session, $address);
407 return (undef, $evt) if $evt;
411 return ( $new_patron, undef );
415 # adds an address to the db and returns the address with new id
417 my($session, $address) = @_;
418 $address->clear_id();
420 $logger->info("Creating new address at street ".$address->street1);
422 # put the address into the database
423 my $id = $session->request(
424 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
425 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
428 return ($address, undef);
432 sub _update_address {
433 my( $session, $address ) = @_;
435 $logger->info("Updating address ".$address->id." in the DB");
437 my $stat = $session->request(
438 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
440 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
441 return ($address, undef);
446 sub _add_update_cards {
450 my $new_patron = shift;
454 my $virtual_id; #id of the card before creation
455 for my $card (@{$patron->cards()}) {
457 $card->usr($new_patron->id());
459 if(ref($card) and $card->isnew()) {
461 $virtual_id = $card->id();
462 ( $card, $evt ) = _add_card($session,$card);
463 return (undef, $evt) if $evt;
465 #if(ref($patron->card)) { $patron->card($patron->card->id); }
466 if($patron->card() == $virtual_id) {
467 $new_patron->card($card->id());
468 $new_patron->ischanged(1);
471 } elsif( ref($card) and $card->ischanged() ) {
472 $card->usr($new_patron->id());
473 $evt = _update_card($session, $card);
474 return (undef, $evt) if $evt;
478 return ( $new_patron, undef );
482 # adds an card to the db and returns the card with new id
484 my( $session, $card ) = @_;
487 $logger->info("Adding new patron card ".$card->barcode);
489 my $id = $session->request(
490 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
491 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
492 $logger->info("Successfully created patron card $id");
495 return ( $card, undef );
499 # returns event on error. returns undef otherwise
501 my( $session, $card ) = @_;
502 $logger->info("Updating patron card ".$card->id);
504 my $stat = $session->request(
505 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
506 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
513 # returns event on error. returns undef otherwise
514 sub _delete_address {
515 my( $session, $address ) = @_;
517 $logger->info("Deleting address ".$address->id." from DB");
519 my $stat = $session->request(
520 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
522 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
528 sub _add_survey_responses {
529 my ($session, $patron, $new_patron) = @_;
531 $logger->info( "Updating survey responses for patron ".$new_patron->id );
533 my $responses = $patron->survey_responses;
537 $_->usr($new_patron->id) for (@$responses);
539 my $evt = $U->simplereq( "open-ils.circ",
540 "open-ils.circ.survey.submit.user_id", $responses );
542 return (undef, $evt) if defined($U->event_code($evt));
546 return ( $new_patron, undef );
550 sub _create_stat_maps {
552 my($session, $user_session, $patron, $new_patron) = @_;
554 my $maps = $patron->stat_cat_entries();
556 for my $map (@$maps) {
558 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
560 if ($map->isdeleted()) {
561 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
563 } elsif ($map->isnew()) {
564 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
569 $map->target_usr($new_patron->id);
572 $logger->info("Updating stat entry with method $method and map $map");
574 my $stat = $session->request($method, $map)->gather(1);
575 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
579 return ($new_patron, undef);
582 sub _create_perm_maps {
584 my($session, $user_session, $patron, $new_patron) = @_;
586 my $maps = $patron->permissions;
588 for my $map (@$maps) {
590 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
591 if ($map->isdeleted()) {
592 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
593 } elsif ($map->isnew()) {
594 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
599 $map->usr($new_patron->id);
601 #warn( "Updating permissions with method $method and session $user_session and map $map" );
602 $logger->info( "Updating permissions with method $method and map $map" );
604 my $stat = $session->request($method, $map)->gather(1);
605 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
609 return ($new_patron, undef);
613 sub _create_standing_penalties {
615 my($session, $user_session, $patron, $new_patron) = @_;
617 my $maps = $patron->standing_penalties;
620 for my $map (@$maps) {
622 if ($map->isdeleted()) {
623 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
624 } elsif ($map->isnew()) {
625 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
631 $map->usr($new_patron->id);
633 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
635 my $stat = $session->request($method, $map)->gather(1);
636 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
639 return ($new_patron, undef);
644 __PACKAGE__->register_method(
645 method => "search_username",
646 api_name => "open-ils.actor.user.search.username",
649 sub search_username {
650 my($self, $client, $username) = @_;
651 my $users = OpenILS::Application::AppUtils->simple_scalar_request(
653 "open-ils.storage.direct.actor.user.search.usrname.atomic",
661 __PACKAGE__->register_method(
662 method => "user_retrieve_by_barcode",
663 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
665 sub user_retrieve_by_barcode {
666 my($self, $client, $user_session, $barcode) = @_;
668 $logger->debug("Searching for user with barcode $barcode");
669 my ($user_obj, $evt) = $apputils->checkses($user_session);
672 my $session = OpenSRF::AppSession->create("open-ils.storage");
674 # find the card with the given barcode
675 my $creq = $session->request(
676 "open-ils.storage.direct.actor.card.search.barcode.atomic",
678 my $card = $creq->gather(1);
680 if(!$card || !$card->[0]) {
681 $session->disconnect();
682 return OpenILS::Event->new( 'USER_NOT_FOUND' );
686 my $user = flesh_user($card->usr(), $session);
687 $session->disconnect();
688 if(!$user) { return OpenILS::Event->new( 'USER_NOT_FOUND' ); }
695 __PACKAGE__->register_method(
696 method => "get_user_by_id",
697 api_name => "open-ils.actor.user.retrieve",);
700 my ($self, $client, $user_session, $id) = @_;
702 my $user_obj = $apputils->check_user_session( $user_session );
704 return $apputils->simple_scalar_request(
706 "open-ils.storage.direct.actor.user.retrieve",
712 __PACKAGE__->register_method(
713 method => "get_org_types",
714 api_name => "open-ils.actor.org_types.retrieve",);
718 my($self, $client) = @_;
720 return $org_types if $org_types;
722 $apputils->simple_scalar_request(
724 "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
729 __PACKAGE__->register_method(
730 method => "get_user_profiles",
731 api_name => "open-ils.actor.user.profiles.retrieve",
735 sub get_user_profiles {
736 return $user_profiles if $user_profiles;
738 return $user_profiles =
739 $apputils->simple_scalar_request(
741 "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
746 __PACKAGE__->register_method(
747 method => "get_user_ident_types",
748 api_name => "open-ils.actor.user.ident_types.retrieve",
751 sub get_user_ident_types {
752 return $ident_types if $ident_types;
753 return $ident_types =
754 $apputils->simple_scalar_request(
756 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
762 __PACKAGE__->register_method(
763 method => "get_org_unit",
764 api_name => "open-ils.actor.org_unit.retrieve",
769 my( $self, $client, $user_session, $org_id ) = @_;
771 if(defined($user_session) && !defined($org_id)) {
773 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
774 if(!defined($org_id)) {
775 $org_id = $user_obj->home_ou;
780 my $home_ou = OpenILS::Application::AppUtils->simple_scalar_request(
782 "open-ils.storage.direct.actor.org_unit.retrieve",
788 __PACKAGE__->register_method(
789 method => "search_org_unit",
790 api_name => "open-ils.actor.org_unit_list.search",
793 sub search_org_unit {
795 my( $self, $client, $field, $value ) = @_;
797 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
799 "open-ils.storage.direct.actor.org_unit.search.$field.atomic",
808 __PACKAGE__->register_method(
809 method => "get_org_tree",
810 api_name => "open-ils.actor.org_tree.retrieve",
812 note => "Returns the entire org tree structure",
816 my( $self, $client) = @_;
819 $cache_client = OpenSRF::Utils::Cache->new("global", 0);
821 # see if it's in the cache
822 #warn "Getting ORG Tree\n";
823 my $tree = $cache_client->get_cache('orgtree');
825 #warn "Found orgtree in cache. returning...\n";
829 my $orglist = $apputils->simple_scalar_request(
831 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
834 #warn "found org list\n";
837 $tree = $self->build_org_tree($orglist);
838 $cache_client->put_cache('orgtree', $tree);
844 # turns an org list into an org tree
847 my( $self, $orglist) = @_;
849 return $orglist unless (
850 ref($orglist) and @$orglist > 1 );
853 $a->ou_type <=> $b->ou_type ||
854 $a->name cmp $b->name } @$orglist;
856 for my $org (@list) {
858 next unless ($org and defined($org->parent_ou));
859 my ($parent) = grep { $_->id == $org->parent_ou } @list;
862 $parent->children([]) unless defined($parent->children);
863 push( @{$parent->children}, $org );
871 __PACKAGE__->register_method(
872 method => "get_org_descendants",
873 api_name => "open-ils.actor.org_tree.descendants.retrieve"
876 # depth is optional. org_unit is the id
877 sub get_org_descendants {
878 my( $self, $client, $org_unit, $depth ) = @_;
879 my $orglist = $apputils->simple_scalar_request(
881 "open-ils.storage.actor.org_unit.descendants.atomic",
883 return $self->build_org_tree($orglist);
887 __PACKAGE__->register_method(
888 method => "get_org_ancestors",
889 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
892 # depth is optional. org_unit is the id
893 sub get_org_ancestors {
894 my( $self, $client, $org_unit, $depth ) = @_;
895 my $orglist = $apputils->simple_scalar_request(
897 "open-ils.storage.actor.org_unit.ancestors.atomic",
899 return $self->build_org_tree($orglist);
903 __PACKAGE__->register_method(
904 method => "get_standings",
905 api_name => "open-ils.actor.standings.retrieve"
910 return $user_standings if $user_standings;
911 return $user_standings =
912 $apputils->simple_scalar_request(
914 "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
919 __PACKAGE__->register_method(
920 method => "get_my_org_path",
921 api_name => "open-ils.actor.org_unit.full_path.retrieve"
924 sub get_my_org_path {
925 my( $self, $client, $user_session, $org_id ) = @_;
926 my $user_obj = $apputils->check_user_session($user_session);
927 if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
929 return $apputils->simple_scalar_request(
931 "open-ils.storage.actor.org_unit.full_path.atomic",
936 __PACKAGE__->register_method(
937 method => "patron_adv_search",
938 api_name => "open-ils.actor.patron.search.advanced" );
940 sub patron_adv_search {
941 my( $self, $client, $staff_login, $search_hash ) = @_;
943 #warn "patron adv with $staff_login and search " .
944 #Dumper($search_hash) . "\n";
946 my $session = OpenSRF::AppSession->create("open-ils.storage");
947 my $req = $session->request(
948 "open-ils.storage.actor.user.crazy_search", $search_hash);
950 my $ans = $req->gather(1);
952 my %hash = map { ($_ =>1) } @$ans;
953 $ans = [ keys %hash ];
955 #warn "Returning @$ans\n";
957 $session->disconnect();
964 sub _verify_password {
965 my($user_session, $password) = @_;
966 my $user_obj = $apputils->check_user_session($user_session);
968 #grab the user with password
969 $user_obj = $apputils->simple_scalar_request(
971 "open-ils.storage.direct.actor.user.retrieve",
974 if($user_obj->passwd eq $password) {
982 __PACKAGE__->register_method(
983 method => "update_password",
984 api_name => "open-ils.actor.user.password.update");
986 __PACKAGE__->register_method(
987 method => "update_password",
988 api_name => "open-ils.actor.user.username.update");
990 __PACKAGE__->register_method(
991 method => "update_password",
992 api_name => "open-ils.actor.user.email.update");
994 sub update_password {
995 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
999 #warn "Updating user with method " .$self->api_name . "\n";
1000 my $user_obj = $apputils->check_user_session($user_session);
1002 if($self->api_name =~ /password/o) {
1004 #make sure they know the current password
1005 if(!_verify_password($user_session, md5_hex($current_password))) {
1006 return OpenILS::EX->new("USER_WRONG_PASSWORD")->ex;
1009 $user_obj->passwd($new_value);
1011 elsif($self->api_name =~ /username/o) {
1012 my $users = search_username(undef, undef, $new_value);
1013 if( $users and $users->[0] ) {
1014 return OpenILS::Event->new('USERNAME_EXISTS');
1016 $user_obj->usrname($new_value);
1019 elsif($self->api_name =~ /email/o) {
1020 #warn "Updating email to $new_value\n";
1021 $user_obj->email($new_value);
1024 my $session = $apputils->start_db_session();
1026 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj);
1027 return $evt if $evt;
1029 $apputils->commit_db_session($session);
1031 if($user_obj) { return 1; }
1036 __PACKAGE__->register_method(
1037 method => "check_user_perms",
1038 api_name => "open-ils.actor.user.perm.check",
1039 notes => <<" NOTES");
1040 Takes a login session, user id, an org id, and an array of perm type strings. For each
1041 perm type, if the user does *not* have the given permission it is added
1042 to a list which is returned from the method. If all permissions
1043 are allowed, an empty list is returned
1044 if the logged in user does not match 'user_id', then the logged in user must
1045 have VIEW_PERMISSION priveleges.
1048 sub check_user_perms {
1049 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1051 my( $staff, $evt ) = $apputils->checkses($login_session);
1052 return $evt if $evt;
1054 if($staff->id ne $user_id) {
1055 if( my $evt = $apputils->check_perms(
1056 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1062 for my $perm (@$perm_types) {
1063 if($apputils->check_perms($user_id, $org_id, $perm)) {
1064 push @not_allowed, $perm;
1068 return \@not_allowed
1071 __PACKAGE__->register_method(
1072 method => "check_user_perms2",
1073 api_name => "open-ils.actor.user.perm.check.multi_org",
1075 Checks the permissions on a list of perms and orgs for a user
1076 @param authtoken The login session key
1077 @param user_id The id of the user to check
1078 @param orgs The array of org ids
1079 @param perms The array of permission names
1080 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1081 if the logged in user does not match 'user_id', then the logged in user must
1082 have VIEW_PERMISSION priveleges.
1085 sub check_user_perms2 {
1086 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1088 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1089 $authtoken, $user_id, 'VIEW_PERMISSION' );
1090 return $evt if $evt;
1093 for my $org (@$orgs) {
1094 for my $perm (@$perms) {
1095 if($apputils->check_perms($user_id, $org, $perm)) {
1096 push @not_allowed, [ $org, $perm ];
1101 return \@not_allowed
1105 __PACKAGE__->register_method(
1106 method => 'check_user_perms3',
1107 api_name => 'open-ils.actor.user.perm.highest_org',
1109 Returns the highest org unit id at which a user has a given permission
1110 If the requestor does not match the target user, the requestor must have
1111 'VIEW_PERMISSION' rights at the home org unit of the target user
1112 @param authtoken The login session key
1113 @param userid The id of the user in question
1114 @param perm The permission to check
1115 @return The org unit highest in the org tree within which the user has
1116 the requested permission
1119 sub check_user_perms3 {
1120 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1122 my( $staff, $target, $org, $evt );
1124 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1125 $authtoken, $userid, 'VIEW_PERMISSION' );
1126 return $evt if $evt;
1128 my $tree = $self->get_org_tree();
1129 return _find_highest_perm_org( $perm, $userid, $target->home_ou, $tree );
1133 sub _find_highest_perm_org {
1134 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1135 my $org = $apputils->find_org($org_tree, $start_org );
1139 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1141 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1147 __PACKAGE__->register_method(
1148 method => 'check_user_perms4',
1149 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1151 Returns the highest org unit id at which a user has a given permission
1152 If the requestor does not match the target user, the requestor must have
1153 'VIEW_PERMISSION' rights at the home org unit of the target user
1154 @param authtoken The login session key
1155 @param userid The id of the user in question
1156 @param perms An array of perm names to check
1157 @return An array of orgId's representing the org unit
1158 highest in the org tree within which the user has the requested permission
1159 The arrah of orgId's has matches the order of the perms array
1162 sub check_user_perms4 {
1163 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1165 my( $staff, $target, $org, $evt );
1167 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1168 $authtoken, $userid, 'VIEW_PERMISSION' );
1169 return $evt if $evt;
1172 return [] unless ref($perms);
1173 my $tree = $self->get_org_tree();
1175 for my $p (@$perms) {
1176 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1184 __PACKAGE__->register_method(
1185 method => "user_fines_summary",
1186 api_name => "open-ils.actor.user.fines.summary",
1187 notes => <<" NOTES");
1188 Returns a short summary of the users total open fines, excluding voided fines
1189 Params are login_session, user_id
1190 Returns a 'mous' object.
1193 sub user_fines_summary {
1194 my( $self, $client, $login_session, $user_id ) = @_;
1196 my $user_obj = $apputils->check_user_session($login_session);
1197 if($user_obj->id ne $user_id) {
1198 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1199 return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY");
1203 return $apputils->simple_scalar_request(
1205 "open-ils.storage.direct.money.open_user_summary.search.usr",
1213 __PACKAGE__->register_method(
1214 method => "user_transactions",
1215 api_name => "open-ils.actor.user.transactions",
1216 notes => <<" NOTES");
1217 Returns a list of open user transactions (mbts objects);
1218 Params are login_session, user_id
1219 Optional third parameter is the transactions type. defaults to all
1222 __PACKAGE__->register_method(
1223 method => "user_transactions",
1224 api_name => "open-ils.actor.user.transactions.have_charge",
1225 notes => <<" NOTES");
1226 Returns a list of all open user transactions (mbts objects) that have an initial charge
1227 Params are login_session, user_id
1228 Optional third parameter is the transactions type. defaults to all
1231 __PACKAGE__->register_method(
1232 method => "user_transactions",
1233 api_name => "open-ils.actor.user.transactions.have_balance",
1234 notes => <<" NOTES");
1235 Returns a list of all open user transactions (mbts objects) that have a balance
1236 Params are login_session, user_id
1237 Optional third parameter is the transactions type. defaults to all
1240 __PACKAGE__->register_method(
1241 method => "user_transactions",
1242 api_name => "open-ils.actor.user.transactions.fleshed",
1243 notes => <<" NOTES");
1244 Returns an object/hash of transaction, circ, title where transaction = an open
1245 user transactions (mbts objects), circ is the attached circluation, and title
1246 is the title the circ points to
1247 Params are login_session, user_id
1248 Optional third parameter is the transactions type. defaults to all
1251 __PACKAGE__->register_method(
1252 method => "user_transactions",
1253 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1254 notes => <<" NOTES");
1255 Returns an object/hash of transaction, circ, title where transaction = an open
1256 user transactions that has an initial charge (mbts objects), circ is the
1257 attached circluation, and title is the title the circ points to
1258 Params are login_session, user_id
1259 Optional third parameter is the transactions type. defaults to all
1262 __PACKAGE__->register_method(
1263 method => "user_transactions",
1264 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1265 notes => <<" NOTES");
1266 Returns an object/hash of transaction, circ, title where transaction = an open
1267 user transaction that has a balance (mbts objects), circ is the attached
1268 circluation, and title is the title the circ points to
1269 Params are login_session, user_id
1270 Optional third parameter is the transaction type. defaults to all
1273 __PACKAGE__->register_method(
1274 method => "user_transactions",
1275 api_name => "open-ils.actor.user.transactions.count",
1276 notes => <<" NOTES");
1277 Returns an object/hash of transaction, circ, title where transaction = an open
1278 user transactions (mbts objects), circ is the attached circluation, and title
1279 is the title the circ points to
1280 Params are login_session, user_id
1281 Optional third parameter is the transactions type. defaults to all
1284 __PACKAGE__->register_method(
1285 method => "user_transactions",
1286 api_name => "open-ils.actor.user.transactions.have_charge.count",
1287 notes => <<" NOTES");
1288 Returns an object/hash of transaction, circ, title where transaction = an open
1289 user transactions that has an initial charge (mbts objects), circ is the
1290 attached circluation, and title is the title the circ points to
1291 Params are login_session, user_id
1292 Optional third parameter is the transactions type. defaults to all
1295 __PACKAGE__->register_method(
1296 method => "user_transactions",
1297 api_name => "open-ils.actor.user.transactions.have_balance.count",
1298 notes => <<" NOTES");
1299 Returns an object/hash of transaction, circ, title where transaction = an open
1300 user transaction that has a balance (mbts objects), circ is the attached
1301 circluation, and title is the title the circ points to
1302 Params are login_session, user_id
1303 Optional third parameter is the transaction type. defaults to all
1306 __PACKAGE__->register_method(
1307 method => "user_transactions",
1308 api_name => "open-ils.actor.user.transactions.have_balance.total",
1309 notes => <<" NOTES");
1310 Returns an object/hash of transaction, circ, title where transaction = an open
1311 user transaction that has a balance (mbts objects), circ is the attached
1312 circluation, and title is the title the circ points to
1313 Params are login_session, user_id
1314 Optional third parameter is the transaction type. defaults to all
1319 sub user_transactions {
1320 my( $self, $client, $login_session, $user_id, $type ) = @_;
1322 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1323 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1324 return $evt if $evt;
1326 my $api = $self->api_name();
1330 if(defined($type)) { @xact = (xact_type => $type);
1332 } else { @xact = (); }
1334 if($api =~ /have_charge/o) {
1336 $trans = $apputils->simple_scalar_request(
1338 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1339 { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1341 } elsif($api =~ /have_balance/o) {
1343 $trans = $apputils->simple_scalar_request(
1345 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1346 { usr => $user_id, balance_owed => { ">" => 0 }, @xact });
1350 $trans = $apputils->simple_scalar_request(
1352 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1353 { usr => $user_id, @xact });
1356 if($api =~ /total/o) {
1358 for my $t (@$trans) {
1359 $total += $t->balance_owed;
1362 $logger->debug("Total balance owed by user $user_id: $total");
1366 if($api =~ /count/o) { return scalar @$trans; }
1367 if($api !~ /fleshed/o) { return $trans; }
1369 #warn "API: $api\n";
1372 for my $t (@$trans) {
1374 #warn $t->id . "\n";
1377 if( $t->xact_type ne 'circulation' ) {
1378 push @resp, {transaction => $t};
1382 my $circ = $apputils->simple_scalar_request(
1384 "open-ils.storage.direct.action.circulation.retrieve",
1389 my $title = $apputils->simple_scalar_request(
1391 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1392 $circ->target_copy );
1396 my $u = OpenILS::Utils::ModsParser->new();
1397 $u->start_mods_batch($title->marc());
1398 my $mods = $u->finish_mods_batch();
1400 push @resp, {transaction => $t, circ => $circ, record => $mods };
1408 __PACKAGE__->register_method(
1409 method => "user_transaction_retrieve",
1410 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1412 notes => <<" NOTES");
1413 Returns a fleshedtransaction record
1415 __PACKAGE__->register_method(
1416 method => "user_transaction_retrieve",
1417 api_name => "open-ils.actor.user.transaction.retrieve",
1419 notes => <<" NOTES");
1420 Returns a transaction record
1422 sub user_transaction_retrieve {
1423 my( $self, $client, $login_session, $bill_id ) = @_;
1425 my $trans = $apputils->simple_scalar_request(
1427 "open-ils.storage.direct.money.billable_transaction_summary.retrieve",
1431 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1432 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1433 return $evt if $evt;
1435 my $api = $self->api_name();
1436 if($api !~ /fleshed/o) { return $trans; }
1438 if( $trans->xact_type ne 'circulation' ) {
1439 $logger->debug("Returning non-circ transaction");
1440 return {transaction => $trans};
1443 my $circ = $apputils->simple_scalar_request(
1445 "open-ils.storage.direct.action.circulation.retrieve",
1448 return {transaction => $trans} unless $circ;
1449 $logger->debug("Found the circ transaction");
1451 my $title = $apputils->simple_scalar_request(
1453 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1454 $circ->target_copy );
1456 return {transaction => $trans, circ => $circ } unless $title;
1457 $logger->debug("Found the circ title");
1461 my $u = OpenILS::Utils::ModsParser->new();
1462 $u->start_mods_batch($title->marc());
1463 $mods = $u->finish_mods_batch();
1465 if ($title->id == -1) {
1466 my $copy = $apputils->simple_scalar_request(
1468 "open-ils.storage.direct.asset.copy.retrieve",
1469 $circ->target_copy );
1471 $mods = new Fieldmapper::metabib::virtual_record;
1473 $mods->title($copy->dummy_title);
1474 $mods->author($copy->dummy_author);
1478 $logger->debug("MODSized the circ title");
1480 return {transaction => $trans, circ => $circ, record => $mods };
1484 __PACKAGE__->register_method(
1485 method => "hold_request_count",
1486 api_name => "open-ils.actor.user.hold_requests.count",
1488 notes => <<" NOTES");
1489 Returns hold ready/total counts
1491 sub hold_request_count {
1492 my( $self, $client, $login_session, $userid ) = @_;
1494 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1495 $login_session, $userid, 'VIEW_HOLD' );
1496 return $evt if $evt;
1499 my $holds = $apputils->simple_scalar_request(
1501 "open-ils.storage.direct.action.hold_request.search_where.atomic",
1503 fulfillment_time => {"=" => undef } }
1507 for my $h (@$holds) {
1508 next unless $h->capture_time;
1510 my $copy = $apputils->simple_scalar_request(
1512 "open-ils.storage.direct.asset.copy.retrieve",
1516 if ($copy->status == 8) {
1521 return { total => scalar(@$holds), ready => scalar(@ready) };
1525 __PACKAGE__->register_method(
1526 method => "checkedout_count",
1527 api_name => "open-ils.actor.user.checked_out.count",
1529 notes => <<" NOTES");
1530 Returns a transaction record
1532 sub checkedout_count {
1533 my( $self, $client, $login_session, $userid ) = @_;
1535 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1536 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1537 return $evt if $evt;
1540 my $circs = $apputils->simple_scalar_request(
1542 "open-ils.storage.direct.action.circulation.search_where.atomic",
1544 checkin_time => {"=" => undef } }
1547 my $parser = DateTime::Format::ISO8601->new;
1550 for my $c (@$circs) {
1551 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1552 my $due = $due_dt->epoch;
1559 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1562 __PACKAGE__->register_method(
1563 method => "user_transaction_history",
1564 api_name => "open-ils.actor.user.transactions.history",
1566 notes => <<" NOTES");
1567 Returns a list of billable transaction ids for a user, optionally by type
1569 sub user_transaction_history {
1570 my( $self, $client, $login_session, $user_id, $type ) = @_;
1572 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1573 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1574 return $evt if $evt;
1576 my $api = $self->api_name();
1579 @xact = (xact_type => $type) if(defined($type));
1581 my $trans = $apputils->simple_scalar_request(
1583 "open-ils.storage.direct.money.billable_transaction_summary.search_where.atomic",
1584 { usr => $user_id, @xact }, { order_by => 'xact_start DESC' });
1586 return [ map { $_->id } @$trans ];
1590 __PACKAGE__->register_method(
1591 method => "user_perms",
1592 api_name => "open-ils.actor.permissions.user_perms.retrieve",
1594 notes => <<" NOTES");
1595 Returns a list of permissions
1598 my( $self, $client, $authtoken, $user ) = @_;
1600 my( $staff, $evt ) = $apputils->checkses($authtoken);
1601 return $evt if $evt;
1603 $user ||= $staff->id;
1605 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1609 return $apputils->simple_scalar_request(
1611 "open-ils.storage.permission.user_perms.atomic",
1615 __PACKAGE__->register_method(
1616 method => "retrieve_perms",
1617 api_name => "open-ils.actor.permissions.retrieve",
1618 notes => <<" NOTES");
1619 Returns a list of permissions
1621 sub retrieve_perms {
1622 my( $self, $client ) = @_;
1623 return $apputils->simple_scalar_request(
1625 "open-ils.storage.direct.permission.perm_list.retrieve.all.atomic");
1628 __PACKAGE__->register_method(
1629 method => "retrieve_groups",
1630 api_name => "open-ils.actor.groups.retrieve",
1631 notes => <<" NOTES");
1632 Returns a list of user groupss
1634 sub retrieve_groups {
1635 my( $self, $client ) = @_;
1636 return $apputils->simple_scalar_request(
1638 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1641 __PACKAGE__->register_method(
1642 method => "retrieve_groups_tree",
1643 api_name => "open-ils.actor.groups.tree.retrieve",
1644 notes => <<" NOTES");
1645 Returns a list of user groups
1647 sub retrieve_groups_tree {
1648 my( $self, $client ) = @_;
1649 my $groups = $apputils->simple_scalar_request(
1651 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1652 return $self->build_group_tree($groups);
1656 # turns an org list into an org tree
1657 sub build_group_tree {
1659 my( $self, $grplist) = @_;
1661 return $grplist unless (
1662 ref($grplist) and @$grplist > 1 );
1664 my @list = sort { $a->name cmp $b->name } @$grplist;
1667 for my $grp (@list) {
1669 if ($grp and !defined($grp->parent)) {
1673 my ($parent) = grep { $_->id == $grp->parent} @list;
1675 $parent->children([]) unless defined($parent->children);
1676 push( @{$parent->children}, $grp );
1684 __PACKAGE__->register_method(
1685 method => "add_user_to_groups",
1686 api_name => "open-ils.actor.user.set_groups",
1687 notes => <<" NOTES");
1688 Adds a user to one or more permission groups
1691 sub add_user_to_groups {
1692 my( $self, $client, $authtoken, $userid, $groups ) = @_;
1694 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1695 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1696 return $evt if $evt;
1698 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1699 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
1700 return $evt if $evt;
1702 $apputils->simplereq(
1704 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
1706 for my $group (@$groups) {
1707 my $link = Fieldmapper::permission::usr_grp_map->new;
1709 $link->usr($userid);
1711 my $id = $apputils->simplereq(
1713 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
1719 __PACKAGE__->register_method(
1720 method => "get_user_perm_groups",
1721 api_name => "open-ils.actor.user.get_groups",
1722 notes => <<" NOTES");
1723 Retrieve a user's permission groups.
1727 sub get_user_perm_groups {
1728 my( $self, $client, $authtoken, $userid ) = @_;
1730 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1731 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
1732 return $evt if $evt;
1734 return $apputils->simplereq(
1736 'open-ils.storage.direct.permission.usr_grp_map.search.usr.atomic', $userid );
1741 __PACKAGE__->register_method (
1742 method => 'register_workstation',
1743 api_name => 'open-ils.actor.workstation.register',
1745 Registers a new workstion in the system
1746 @param authtoken The login session key
1747 @param name The name of the workstation id
1748 @param owner The org unit that owns this workstation
1749 @return The workstation id on success, WORKSTATION_NAME_EXISTS
1750 if the name is already in use.
1753 sub register_workstation {
1754 my( $self, $connection, $authtoken, $name, $owner ) = @_;
1755 my( $requestor, $evt ) = $U->checkses($authtoken);
1756 return $evt if $evt;
1757 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
1758 return $evt if $evt;
1760 my $ws = $U->storagereq(
1761 'open-ils.storage.direct.actor.workstation.search.name', $name );
1762 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
1764 $ws = Fieldmapper::actor::workstation->new;
1765 $ws->owning_lib($owner);
1768 my $id = $U->storagereq(
1769 'open-ils.storage.direct.actor.workstation.create', $ws );
1770 return $U->DB_UPDATE_FAILED($ws) unless $id;