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;
62 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
64 $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper(\@params));
66 return $apputils->simplereq(
68 'open-ils.storage.direct.actor.user_setting.batch.merge', @params );
74 __PACKAGE__->register_method(
75 method => "set_ou_settings",
76 api_name => "open-ils.actor.org_unit.settings.update",
79 my( $self, $client, $user_session, $ouid, $settings ) = @_;
81 my( $staff, $evt ) = $apputils->checkses( $user_session );
83 $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_UNIT' );
88 map { [{ org_unit => $ouid, name => $_}, {value => $$settings{$_}}] } keys %$settings;
90 $logger->activity("Updating org unit [$ouid] settings with: " . Dumper($params));
92 return $apputils->simplereq(
94 'open-ils.storage.direct.actor.org_unit_setting.merge', @$params );
98 my $fetch_user_settings;
99 my $fetch_ou_settings;
101 __PACKAGE__->register_method(
102 method => "user_settings",
103 api_name => "open-ils.actor.patron.settings.retrieve",
106 my( $self, $client, $user_session, $uid ) = @_;
108 my( $staff, $user, $evt ) =
109 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
112 $logger->debug("User " . $staff->id . " fetching user $uid\n");
113 my $s = $apputils->simplereq(
115 'open-ils.storage.direct.actor.user_setting.search.usr.atomic',$uid );
117 return { map { ($_->name,$_->value) } @$s };
122 __PACKAGE__->register_method(
123 method => "ou_settings",
124 api_name => "open-ils.actor.org_unit.settings.retrieve",
127 my( $self, $client, $ouid ) = @_;
129 my $s = $apputils->simplereq(
131 'open-ils.storage.direct.actor.org_unit_setting.search.org_unit.atomic', $ouid);
133 return { map { ($_->name,$_->value) } @$s };
136 __PACKAGE__->register_method (
137 method => "ou_setting_delete",
138 api_name => 'open-ils.actor.org_setting.delete',
140 Deletes a specific org unit setting for a specific location
141 @param authtoken The login session key
142 @param orgid The org unit whose setting we're changing
143 @param setting The name of the setting to delete
144 @return True value on success.
148 sub ou_setting_delete {
149 my( $self, $conn, $authtoken, $orgid, $setting ) = @_;
150 my( $reqr, $evt) = $U->checkses($authtoken);
152 $evt = $U->check_perms($reqr->id, $orgid, 'UPDATE_ORG_SETTING');
155 my $id = $U->storagereq(
156 'open-ils.storage.id_list.actor.org_unit_setting.search_where',
157 { name => $setting, org_unit => $orgid } );
159 $logger->debug("Retrieved setting $id in org unit setting delete");
161 my $s = $U->storagereq(
162 'open-ils.storage.direct.actor.org_unit_setting.delete', $id );
164 $logger->activity("User ".$reqr->id." deleted org unit setting $id") if $s;
170 __PACKAGE__->register_method(
171 method => "update_patron",
172 api_name => "open-ils.actor.patron.update",);
175 my( $self, $client, $user_session, $patron ) = @_;
177 my $session = $apputils->start_db_session();
180 $logger->info("Creating new patron...") if $patron->isnew;
181 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
183 my( $user_obj, $evt ) = $U->checkses($user_session);
186 # XXX does this user have permission to add/create users. Granularity?
187 # $new_patron is the patron in progress. $patron is the original patron
188 # passed in with the method. new_patron will change as the components
189 # of patron are added/updated.
193 # unflesh the real items on the patron
194 $patron->card( $patron->card->id ) if(ref($patron->card));
195 $patron->billing_address( $patron->billing_address->id )
196 if(ref($patron->billing_address));
197 $patron->mailing_address( $patron->mailing_address->id )
198 if(ref($patron->mailing_address));
200 # create/update the patron first so we can use his id
201 if($patron->isnew()) {
202 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
204 } else { $new_patron = $patron; }
206 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
209 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
212 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
215 # re-update the patron if anything has happened to him during this process
216 if($new_patron->ischanged()) {
217 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
221 #$session = OpenSRF::AppSession->create("open-ils.storage"); # why did i put this here?
223 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
226 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
229 ($new_patron, $evt) = _create_standing_penalties($session, $user_session, $patron, $new_patron, $user_obj);
232 $apputils->commit_db_session($session);
234 #warn "Patron Update/Create complete\n";
235 return flesh_user($new_patron->id());
241 __PACKAGE__->register_method(
242 method => "user_retrieve_fleshed_by_id",
243 api_name => "open-ils.actor.user.fleshed.retrieve",);
245 sub user_retrieve_fleshed_by_id {
246 my( $self, $client, $user_session, $user_id ) = @_;
248 my( $requestor, $target, $evt ) = $apputils->
249 checkses_requestor( $user_session, $user_id, 'VIEW_USER' );
252 return flesh_user($user_id);
256 # fleshes: card, cards, address, addresses, stat_cat_entries, standing_penalties
264 $session = OpenSRF::AppSession->create("open-ils.storage");
268 # grab the user with the given id
269 my $ureq = $session->request(
270 "open-ils.storage.direct.actor.user.retrieve", $id);
271 my $user = $ureq->gather(1);
273 if(!$user) { return undef; }
276 my $cards_req = $session->request(
277 "open-ils.storage.direct.actor.card.search.usr.atomic",
279 $user->cards( $cards_req->gather(1) );
281 for my $c(@{$user->cards}) {
282 if($c->id == $user->card || $c->id eq $user->card ) {
283 #warn "Setting my card to " . $c->id . "\n";
288 my $add_req = $session->request(
289 "open-ils.storage.direct.actor.user_address.search.usr.atomic",
291 $user->addresses( $add_req->gather(1) );
293 for my $c(@{$user->addresses}) {
294 if($c->id eq $user->billing_address ) { $user->billing_address($c); }
295 if($c->id eq $user->mailing_address ) { $user->mailing_address($c); }
298 my $stat_req = $session->request(
299 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr.atomic",
301 $user->stat_cat_entries($stat_req->gather(1));
303 my $standing_penalties_req = $session->request(
304 "open-ils.storage.direct.actor.user_standing_penalty.search.usr.atomic",
306 $user->standing_penalties($standing_penalties_req->gather(1));
308 if($kill) { $session->disconnect(); }
309 $user->clear_passwd();
315 # clone and clear stuff that would break the database
319 my $new_patron = $patron->clone;
321 # Using the Fieldmapper clone method
322 #my $new_patron = Fieldmapper::actor::user->new();
324 #my $fmap = $Fieldmapper::fieldmap;
325 #no strict; # shallow clone, may be useful in the fieldmapper
327 # (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
328 # $new_patron->$field( $patron->$field() );
333 $new_patron->clear_billing_address();
334 $new_patron->clear_mailing_address();
335 $new_patron->clear_addresses();
336 $new_patron->clear_card();
337 $new_patron->clear_cards();
338 $new_patron->clear_id();
339 $new_patron->clear_isnew();
340 $new_patron->clear_ischanged();
341 $new_patron->clear_isdeleted();
342 $new_patron->clear_stat_cat_entries();
343 $new_patron->clear_permissions();
344 $new_patron->clear_standing_penalties();
354 my $user_obj = shift;
356 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
357 return (undef, $evt) if $evt;
359 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
361 my $id = $session->request(
362 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
363 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
365 $logger->info("Successfully created new user [$id] in DB");
367 return ( $session->request(
368 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
373 my( $session, $patron, $user_obj) = @_;
375 $logger->info("Updating patron ".$patron->id." in DB");
376 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
377 return (undef, $evt) if $evt;
379 $patron->clear_passwd unless $patron->passwd;
381 my $stat = $session->request(
382 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
383 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
389 sub _add_update_addresses {
393 my $new_patron = shift;
397 my $current_id; # id of the address before creation
399 for my $address (@{$patron->addresses()}) {
401 $address->usr($new_patron->id());
403 if(ref($address) and $address->isnew()) {
405 $current_id = $address->id();
406 ($address, $evt) = _add_address($session,$address);
407 return (undef, $evt) if $evt;
409 if( $patron->billing_address() and
410 $patron->billing_address() == $current_id ) {
411 $new_patron->billing_address($address->id());
412 $new_patron->ischanged(1);
415 if( $patron->mailing_address() and
416 $patron->mailing_address() == $current_id ) {
417 $new_patron->mailing_address($address->id());
418 $new_patron->ischanged(1);
421 } elsif( ref($address) and $address->ischanged() ) {
423 $address->usr($new_patron->id());
424 ($address, $evt) = _update_address($session, $address);
425 return (undef, $evt) if $evt;
427 } elsif( ref($address) and $address->isdeleted() ) {
429 if( $address->id() == $new_patron->mailing_address() ) {
430 $new_patron->clear_mailing_address();
431 ($new_patron, $evt) = _update_patron($session, $new_patron);
432 return (undef, $evt) if $evt;
435 if( $address->id() == $new_patron->billing_address() ) {
436 $new_patron->clear_billing_address();
437 ($new_patron, $evt) = _update_patron($session, $new_patron);
438 return (undef, $evt) if $evt;
441 $evt = _delete_address($session, $address);
442 return (undef, $evt) if $evt;
446 return ( $new_patron, undef );
450 # adds an address to the db and returns the address with new id
452 my($session, $address) = @_;
453 $address->clear_id();
455 $logger->info("Creating new address at street ".$address->street1);
457 # put the address into the database
458 my $id = $session->request(
459 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
460 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
463 return ($address, undef);
467 sub _update_address {
468 my( $session, $address ) = @_;
470 $logger->info("Updating address ".$address->id." in the DB");
472 my $stat = $session->request(
473 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
475 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
476 return ($address, undef);
481 sub _add_update_cards {
485 my $new_patron = shift;
489 my $virtual_id; #id of the card before creation
490 for my $card (@{$patron->cards()}) {
492 $card->usr($new_patron->id());
494 if(ref($card) and $card->isnew()) {
496 $virtual_id = $card->id();
497 ( $card, $evt ) = _add_card($session,$card);
498 return (undef, $evt) if $evt;
500 #if(ref($patron->card)) { $patron->card($patron->card->id); }
501 if($patron->card() == $virtual_id) {
502 $new_patron->card($card->id());
503 $new_patron->ischanged(1);
506 } elsif( ref($card) and $card->ischanged() ) {
507 $card->usr($new_patron->id());
508 $evt = _update_card($session, $card);
509 return (undef, $evt) if $evt;
513 return ( $new_patron, undef );
517 # adds an card to the db and returns the card with new id
519 my( $session, $card ) = @_;
522 $logger->info("Adding new patron card ".$card->barcode);
524 my $id = $session->request(
525 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
526 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
527 $logger->info("Successfully created patron card $id");
530 return ( $card, undef );
534 # returns event on error. returns undef otherwise
536 my( $session, $card ) = @_;
537 $logger->info("Updating patron card ".$card->id);
539 my $stat = $session->request(
540 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
541 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
548 # returns event on error. returns undef otherwise
549 sub _delete_address {
550 my( $session, $address ) = @_;
552 $logger->info("Deleting address ".$address->id." from DB");
554 my $stat = $session->request(
555 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
557 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
563 sub _add_survey_responses {
564 my ($session, $patron, $new_patron) = @_;
566 $logger->info( "Updating survey responses for patron ".$new_patron->id );
568 my $responses = $patron->survey_responses;
572 $_->usr($new_patron->id) for (@$responses);
574 my $evt = $U->simplereq( "open-ils.circ",
575 "open-ils.circ.survey.submit.user_id", $responses );
577 return (undef, $evt) if defined($U->event_code($evt));
581 return ( $new_patron, undef );
585 sub _create_stat_maps {
587 my($session, $user_session, $patron, $new_patron) = @_;
589 my $maps = $patron->stat_cat_entries();
591 for my $map (@$maps) {
593 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
595 if ($map->isdeleted()) {
596 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
598 } elsif ($map->isnew()) {
599 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
604 $map->target_usr($new_patron->id);
607 $logger->info("Updating stat entry with method $method and map $map");
609 my $stat = $session->request($method, $map)->gather(1);
610 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
614 return ($new_patron, undef);
617 sub _create_perm_maps {
619 my($session, $user_session, $patron, $new_patron) = @_;
621 my $maps = $patron->permissions;
623 for my $map (@$maps) {
625 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
626 if ($map->isdeleted()) {
627 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
628 } elsif ($map->isnew()) {
629 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
634 $map->usr($new_patron->id);
636 #warn( "Updating permissions with method $method and session $user_session and map $map" );
637 $logger->info( "Updating permissions with method $method and map $map" );
639 my $stat = $session->request($method, $map)->gather(1);
640 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
644 return ($new_patron, undef);
648 sub _create_standing_penalties {
650 my($session, $user_session, $patron, $new_patron) = @_;
652 my $maps = $patron->standing_penalties;
655 for my $map (@$maps) {
657 if ($map->isdeleted()) {
658 $method = "open-ils.storage.direct.actor.user_standing_penalty.delete";
659 } elsif ($map->isnew()) {
660 $method = "open-ils.storage.direct.actor.user_standing_penalty.create";
666 $map->usr($new_patron->id);
668 $logger->debug( "Updating standing penalty with method $method and session $user_session and map $map" );
670 my $stat = $session->request($method, $map)->gather(1);
671 return (undef, $U->DB_UPDATE_FAILED($map)) unless $stat;
674 return ($new_patron, undef);
679 __PACKAGE__->register_method(
680 method => "search_username",
681 api_name => "open-ils.actor.user.search.username",
684 sub search_username {
685 my($self, $client, $username) = @_;
686 my $users = OpenILS::Application::AppUtils->simple_scalar_request(
688 "open-ils.storage.direct.actor.user.search.usrname.atomic",
696 __PACKAGE__->register_method(
697 method => "user_retrieve_by_barcode",
698 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
700 sub user_retrieve_by_barcode {
701 my($self, $client, $user_session, $barcode) = @_;
703 $logger->debug("Searching for user with barcode $barcode");
704 my ($user_obj, $evt) = $apputils->checkses($user_session);
707 my $session = OpenSRF::AppSession->create("open-ils.storage");
709 # find the card with the given barcode
710 my $creq = $session->request(
711 "open-ils.storage.direct.actor.card.search.barcode.atomic",
713 my $card = $creq->gather(1);
715 if(!$card || !$card->[0]) {
716 $session->disconnect();
717 return OpenILS::Event->new( 'USER_NOT_FOUND' );
721 my $user = flesh_user($card->usr(), $session);
722 $session->disconnect();
723 if(!$user) { return OpenILS::Event->new( 'USER_NOT_FOUND' ); }
730 __PACKAGE__->register_method(
731 method => "get_user_by_id",
732 api_name => "open-ils.actor.user.retrieve",);
735 my ($self, $client, $user_session, $id) = @_;
737 my $user_obj = $apputils->check_user_session( $user_session );
739 return $apputils->simple_scalar_request(
741 "open-ils.storage.direct.actor.user.retrieve",
747 __PACKAGE__->register_method(
748 method => "get_org_types",
749 api_name => "open-ils.actor.org_types.retrieve",);
753 my($self, $client) = @_;
755 return $org_types if $org_types;
757 $apputils->simple_scalar_request(
759 "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
764 __PACKAGE__->register_method(
765 method => "get_user_profiles",
766 api_name => "open-ils.actor.user.profiles.retrieve",
770 sub get_user_profiles {
771 return $user_profiles if $user_profiles;
773 return $user_profiles =
774 $apputils->simple_scalar_request(
776 "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
781 __PACKAGE__->register_method(
782 method => "get_user_ident_types",
783 api_name => "open-ils.actor.user.ident_types.retrieve",
786 sub get_user_ident_types {
787 return $ident_types if $ident_types;
788 return $ident_types =
789 $apputils->simple_scalar_request(
791 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
797 __PACKAGE__->register_method(
798 method => "get_org_unit",
799 api_name => "open-ils.actor.org_unit.retrieve",
804 my( $self, $client, $user_session, $org_id ) = @_;
806 if(defined($user_session) && !defined($org_id)) {
808 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
809 if(!defined($org_id)) {
810 $org_id = $user_obj->home_ou;
815 my $home_ou = OpenILS::Application::AppUtils->simple_scalar_request(
817 "open-ils.storage.direct.actor.org_unit.retrieve",
823 __PACKAGE__->register_method(
824 method => "search_org_unit",
825 api_name => "open-ils.actor.org_unit_list.search",
828 sub search_org_unit {
830 my( $self, $client, $field, $value ) = @_;
832 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
834 "open-ils.storage.direct.actor.org_unit.search.$field.atomic",
843 __PACKAGE__->register_method(
844 method => "get_org_tree",
845 api_name => "open-ils.actor.org_tree.retrieve",
847 note => "Returns the entire org tree structure",
851 my( $self, $client) = @_;
854 $cache_client = OpenSRF::Utils::Cache->new("global", 0);
856 # see if it's in the cache
857 #warn "Getting ORG Tree\n";
858 my $tree = $cache_client->get_cache('orgtree');
860 #warn "Found orgtree in cache. returning...\n";
864 my $orglist = $apputils->simple_scalar_request(
866 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
869 #warn "found org list\n";
872 $tree = $self->build_org_tree($orglist);
873 $cache_client->put_cache('orgtree', $tree);
879 # turns an org list into an org tree
882 my( $self, $orglist) = @_;
884 return $orglist unless (
885 ref($orglist) and @$orglist > 1 );
888 $a->ou_type <=> $b->ou_type ||
889 $a->name cmp $b->name } @$orglist;
891 for my $org (@list) {
893 next unless ($org and defined($org->parent_ou));
894 my ($parent) = grep { $_->id == $org->parent_ou } @list;
897 $parent->children([]) unless defined($parent->children);
898 push( @{$parent->children}, $org );
906 __PACKAGE__->register_method(
907 method => "get_org_descendants",
908 api_name => "open-ils.actor.org_tree.descendants.retrieve"
911 # depth is optional. org_unit is the id
912 sub get_org_descendants {
913 my( $self, $client, $org_unit, $depth ) = @_;
914 my $orglist = $apputils->simple_scalar_request(
916 "open-ils.storage.actor.org_unit.descendants.atomic",
918 return $self->build_org_tree($orglist);
922 __PACKAGE__->register_method(
923 method => "get_org_ancestors",
924 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
927 # depth is optional. org_unit is the id
928 sub get_org_ancestors {
929 my( $self, $client, $org_unit, $depth ) = @_;
930 my $orglist = $apputils->simple_scalar_request(
932 "open-ils.storage.actor.org_unit.ancestors.atomic",
934 return $self->build_org_tree($orglist);
938 __PACKAGE__->register_method(
939 method => "get_standings",
940 api_name => "open-ils.actor.standings.retrieve"
945 return $user_standings if $user_standings;
946 return $user_standings =
947 $apputils->simple_scalar_request(
949 "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
954 __PACKAGE__->register_method(
955 method => "get_my_org_path",
956 api_name => "open-ils.actor.org_unit.full_path.retrieve"
959 sub get_my_org_path {
960 my( $self, $client, $user_session, $org_id ) = @_;
961 my $user_obj = $apputils->check_user_session($user_session);
962 if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
964 return $apputils->simple_scalar_request(
966 "open-ils.storage.actor.org_unit.full_path.atomic",
971 __PACKAGE__->register_method(
972 method => "patron_adv_search",
973 api_name => "open-ils.actor.patron.search.advanced" );
975 sub patron_adv_search {
976 my( $self, $client, $staff_login, $search_hash ) = @_;
978 #warn "patron adv with $staff_login and search " .
979 #Dumper($search_hash) . "\n";
981 my $session = OpenSRF::AppSession->create("open-ils.storage");
982 my $req = $session->request(
983 "open-ils.storage.actor.user.crazy_search", $search_hash);
985 my $ans = $req->gather(1);
987 my %hash = map { ($_ =>1) } @$ans;
988 $ans = [ keys %hash ];
990 #warn "Returning @$ans\n";
992 $session->disconnect();
999 sub _verify_password {
1000 my($user_session, $password) = @_;
1001 my $user_obj = $apputils->check_user_session($user_session);
1003 #grab the user with password
1004 $user_obj = $apputils->simple_scalar_request(
1006 "open-ils.storage.direct.actor.user.retrieve",
1009 if($user_obj->passwd eq $password) {
1017 __PACKAGE__->register_method(
1018 method => "update_password",
1019 api_name => "open-ils.actor.user.password.update");
1021 __PACKAGE__->register_method(
1022 method => "update_password",
1023 api_name => "open-ils.actor.user.username.update");
1025 __PACKAGE__->register_method(
1026 method => "update_password",
1027 api_name => "open-ils.actor.user.email.update");
1029 sub update_password {
1030 my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1034 #warn "Updating user with method " .$self->api_name . "\n";
1035 my $user_obj = $apputils->check_user_session($user_session);
1037 if($self->api_name =~ /password/o) {
1039 #make sure they know the current password
1040 if(!_verify_password($user_session, md5_hex($current_password))) {
1041 return OpenILS::EX->new("USER_WRONG_PASSWORD")->ex;
1044 $user_obj->passwd($new_value);
1046 elsif($self->api_name =~ /username/o) {
1047 my $users = search_username(undef, undef, $new_value);
1048 if( $users and $users->[0] ) {
1049 return OpenILS::Event->new('USERNAME_EXISTS');
1051 $user_obj->usrname($new_value);
1054 elsif($self->api_name =~ /email/o) {
1055 #warn "Updating email to $new_value\n";
1056 $user_obj->email($new_value);
1059 my $session = $apputils->start_db_session();
1061 ( $user_obj, $evt ) = _update_patron($session, $user_obj, $user_obj);
1062 return $evt if $evt;
1064 $apputils->commit_db_session($session);
1066 if($user_obj) { return 1; }
1071 __PACKAGE__->register_method(
1072 method => "check_user_perms",
1073 api_name => "open-ils.actor.user.perm.check",
1074 notes => <<" NOTES");
1075 Takes a login session, user id, an org id, and an array of perm type strings. For each
1076 perm type, if the user does *not* have the given permission it is added
1077 to a list which is returned from the method. If all permissions
1078 are allowed, an empty list is returned
1079 if the logged in user does not match 'user_id', then the logged in user must
1080 have VIEW_PERMISSION priveleges.
1083 sub check_user_perms {
1084 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1086 my( $staff, $evt ) = $apputils->checkses($login_session);
1087 return $evt if $evt;
1089 if($staff->id ne $user_id) {
1090 if( my $evt = $apputils->check_perms(
1091 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1097 for my $perm (@$perm_types) {
1098 if($apputils->check_perms($user_id, $org_id, $perm)) {
1099 push @not_allowed, $perm;
1103 return \@not_allowed
1106 __PACKAGE__->register_method(
1107 method => "check_user_perms2",
1108 api_name => "open-ils.actor.user.perm.check.multi_org",
1110 Checks the permissions on a list of perms and orgs for a user
1111 @param authtoken The login session key
1112 @param user_id The id of the user to check
1113 @param orgs The array of org ids
1114 @param perms The array of permission names
1115 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1116 if the logged in user does not match 'user_id', then the logged in user must
1117 have VIEW_PERMISSION priveleges.
1120 sub check_user_perms2 {
1121 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1123 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1124 $authtoken, $user_id, 'VIEW_PERMISSION' );
1125 return $evt if $evt;
1128 for my $org (@$orgs) {
1129 for my $perm (@$perms) {
1130 if($apputils->check_perms($user_id, $org, $perm)) {
1131 push @not_allowed, [ $org, $perm ];
1136 return \@not_allowed
1140 __PACKAGE__->register_method(
1141 method => 'check_user_perms3',
1142 api_name => 'open-ils.actor.user.perm.highest_org',
1144 Returns the highest org unit id at which a user has a given permission
1145 If the requestor does not match the target user, the requestor must have
1146 'VIEW_PERMISSION' rights at the home org unit of the target user
1147 @param authtoken The login session key
1148 @param userid The id of the user in question
1149 @param perm The permission to check
1150 @return The org unit highest in the org tree within which the user has
1151 the requested permission
1154 sub check_user_perms3 {
1155 my( $self, $client, $authtoken, $userid, $perm ) = @_;
1157 my( $staff, $target, $org, $evt );
1159 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1160 $authtoken, $userid, 'VIEW_PERMISSION' );
1161 return $evt if $evt;
1163 my $tree = $self->get_org_tree();
1164 return _find_highest_perm_org( $perm, $userid, $target->home_ou, $tree );
1168 sub _find_highest_perm_org {
1169 my ( $perm, $userid, $start_org, $org_tree ) = @_;
1170 my $org = $apputils->find_org($org_tree, $start_org );
1174 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1176 $org = $apputils->find_org( $org_tree, $org->parent_ou() );
1182 __PACKAGE__->register_method(
1183 method => 'check_user_perms4',
1184 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1186 Returns the highest org unit id at which a user has a given permission
1187 If the requestor does not match the target user, the requestor must have
1188 'VIEW_PERMISSION' rights at the home org unit of the target user
1189 @param authtoken The login session key
1190 @param userid The id of the user in question
1191 @param perms An array of perm names to check
1192 @return An array of orgId's representing the org unit
1193 highest in the org tree within which the user has the requested permission
1194 The arrah of orgId's has matches the order of the perms array
1197 sub check_user_perms4 {
1198 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1200 my( $staff, $target, $org, $evt );
1202 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1203 $authtoken, $userid, 'VIEW_PERMISSION' );
1204 return $evt if $evt;
1207 return [] unless ref($perms);
1208 my $tree = $self->get_org_tree();
1210 for my $p (@$perms) {
1211 push( @arr, _find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1219 __PACKAGE__->register_method(
1220 method => "user_fines_summary",
1221 api_name => "open-ils.actor.user.fines.summary",
1222 notes => <<" NOTES");
1223 Returns a short summary of the users total open fines, excluding voided fines
1224 Params are login_session, user_id
1225 Returns a 'mous' object.
1228 sub user_fines_summary {
1229 my( $self, $client, $login_session, $user_id ) = @_;
1231 my $user_obj = $apputils->check_user_session($login_session);
1232 if($user_obj->id ne $user_id) {
1233 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1234 return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY");
1238 return $apputils->simple_scalar_request(
1240 "open-ils.storage.direct.money.open_user_summary.search.usr",
1248 __PACKAGE__->register_method(
1249 method => "user_transactions",
1250 api_name => "open-ils.actor.user.transactions",
1251 notes => <<" NOTES");
1252 Returns a list of open user transactions (mbts objects);
1253 Params are login_session, user_id
1254 Optional third parameter is the transactions type. defaults to all
1257 __PACKAGE__->register_method(
1258 method => "user_transactions",
1259 api_name => "open-ils.actor.user.transactions.have_charge",
1260 notes => <<" NOTES");
1261 Returns a list of all open user transactions (mbts objects) that have an initial charge
1262 Params are login_session, user_id
1263 Optional third parameter is the transactions type. defaults to all
1266 __PACKAGE__->register_method(
1267 method => "user_transactions",
1268 api_name => "open-ils.actor.user.transactions.have_balance",
1269 notes => <<" NOTES");
1270 Returns a list of all open user transactions (mbts objects) that have a balance
1271 Params are login_session, user_id
1272 Optional third parameter is the transactions type. defaults to all
1275 __PACKAGE__->register_method(
1276 method => "user_transactions",
1277 api_name => "open-ils.actor.user.transactions.fleshed",
1278 notes => <<" NOTES");
1279 Returns an object/hash of transaction, circ, title where transaction = an open
1280 user transactions (mbts objects), circ is the attached circluation, and title
1281 is the title the circ points to
1282 Params are login_session, user_id
1283 Optional third parameter is the transactions type. defaults to all
1286 __PACKAGE__->register_method(
1287 method => "user_transactions",
1288 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1289 notes => <<" NOTES");
1290 Returns an object/hash of transaction, circ, title where transaction = an open
1291 user transactions that has an initial charge (mbts objects), circ is the
1292 attached circluation, and title is the title the circ points to
1293 Params are login_session, user_id
1294 Optional third parameter is the transactions type. defaults to all
1297 __PACKAGE__->register_method(
1298 method => "user_transactions",
1299 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1300 notes => <<" NOTES");
1301 Returns an object/hash of transaction, circ, title where transaction = an open
1302 user transaction that has a balance (mbts objects), circ is the attached
1303 circluation, and title is the title the circ points to
1304 Params are login_session, user_id
1305 Optional third parameter is the transaction type. defaults to all
1308 __PACKAGE__->register_method(
1309 method => "user_transactions",
1310 api_name => "open-ils.actor.user.transactions.count",
1311 notes => <<" NOTES");
1312 Returns an object/hash of transaction, circ, title where transaction = an open
1313 user transactions (mbts objects), circ is the attached circluation, and title
1314 is the title the circ points to
1315 Params are login_session, user_id
1316 Optional third parameter is the transactions type. defaults to all
1319 __PACKAGE__->register_method(
1320 method => "user_transactions",
1321 api_name => "open-ils.actor.user.transactions.have_charge.count",
1322 notes => <<" NOTES");
1323 Returns an object/hash of transaction, circ, title where transaction = an open
1324 user transactions that has an initial charge (mbts objects), circ is the
1325 attached circluation, and title is the title the circ points to
1326 Params are login_session, user_id
1327 Optional third parameter is the transactions type. defaults to all
1330 __PACKAGE__->register_method(
1331 method => "user_transactions",
1332 api_name => "open-ils.actor.user.transactions.have_balance.count",
1333 notes => <<" NOTES");
1334 Returns an object/hash of transaction, circ, title where transaction = an open
1335 user transaction that has a balance (mbts objects), circ is the attached
1336 circluation, and title is the title the circ points to
1337 Params are login_session, user_id
1338 Optional third parameter is the transaction type. defaults to all
1341 __PACKAGE__->register_method(
1342 method => "user_transactions",
1343 api_name => "open-ils.actor.user.transactions.have_balance.total",
1344 notes => <<" NOTES");
1345 Returns an object/hash of transaction, circ, title where transaction = an open
1346 user transaction that has a balance (mbts objects), circ is the attached
1347 circluation, and title is the title the circ points to
1348 Params are login_session, user_id
1349 Optional third parameter is the transaction type. defaults to all
1354 sub user_transactions {
1355 my( $self, $client, $login_session, $user_id, $type ) = @_;
1357 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1358 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1359 return $evt if $evt;
1361 my $api = $self->api_name();
1365 if(defined($type)) { @xact = (xact_type => $type);
1367 } else { @xact = (); }
1369 if($api =~ /have_charge/o) {
1371 $trans = $apputils->simple_scalar_request(
1373 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1374 { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1376 } elsif($api =~ /have_balance/o) {
1378 $trans = $apputils->simple_scalar_request(
1380 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1381 { usr => $user_id, balance_owed => { ">" => 0 }, @xact });
1385 $trans = $apputils->simple_scalar_request(
1387 "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1388 { usr => $user_id, @xact });
1391 if($api =~ /total/o) {
1393 for my $t (@$trans) {
1394 $total += $t->balance_owed;
1397 $logger->debug("Total balance owed by user $user_id: $total");
1401 if($api =~ /count/o) { return scalar @$trans; }
1402 if($api !~ /fleshed/o) { return $trans; }
1404 #warn "API: $api\n";
1407 for my $t (@$trans) {
1409 #warn $t->id . "\n";
1412 if( $t->xact_type ne 'circulation' ) {
1413 push @resp, {transaction => $t};
1417 my $circ = $apputils->simple_scalar_request(
1419 "open-ils.storage.direct.action.circulation.retrieve",
1424 my $title = $apputils->simple_scalar_request(
1426 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1427 $circ->target_copy );
1431 my $u = OpenILS::Utils::ModsParser->new();
1432 $u->start_mods_batch($title->marc());
1433 my $mods = $u->finish_mods_batch();
1435 push @resp, {transaction => $t, circ => $circ, record => $mods };
1443 __PACKAGE__->register_method(
1444 method => "user_transaction_retrieve",
1445 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1447 notes => <<" NOTES");
1448 Returns a fleshedtransaction record
1450 __PACKAGE__->register_method(
1451 method => "user_transaction_retrieve",
1452 api_name => "open-ils.actor.user.transaction.retrieve",
1454 notes => <<" NOTES");
1455 Returns a transaction record
1457 sub user_transaction_retrieve {
1458 my( $self, $client, $login_session, $bill_id ) = @_;
1460 my $trans = $apputils->simple_scalar_request(
1462 "open-ils.storage.direct.money.billable_transaction_summary.retrieve",
1466 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1467 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1468 return $evt if $evt;
1470 my $api = $self->api_name();
1471 if($api !~ /fleshed/o) { return $trans; }
1473 if( $trans->xact_type ne 'circulation' ) {
1474 $logger->debug("Returning non-circ transaction");
1475 return {transaction => $trans};
1478 my $circ = $apputils->simple_scalar_request(
1480 "open-ils.storage.direct.action.circulation.retrieve",
1483 return {transaction => $trans} unless $circ;
1484 $logger->debug("Found the circ transaction");
1486 my $title = $apputils->simple_scalar_request(
1488 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1489 $circ->target_copy );
1491 return {transaction => $trans, circ => $circ } unless $title;
1492 $logger->debug("Found the circ title");
1496 my $u = OpenILS::Utils::ModsParser->new();
1497 $u->start_mods_batch($title->marc());
1498 $mods = $u->finish_mods_batch();
1500 if ($title->id == -1) {
1501 my $copy = $apputils->simple_scalar_request(
1503 "open-ils.storage.direct.asset.copy.retrieve",
1504 $circ->target_copy );
1506 $mods = new Fieldmapper::metabib::virtual_record;
1508 $mods->title($copy->dummy_title);
1509 $mods->author($copy->dummy_author);
1513 $logger->debug("MODSized the circ title");
1515 return {transaction => $trans, circ => $circ, record => $mods };
1519 __PACKAGE__->register_method(
1520 method => "hold_request_count",
1521 api_name => "open-ils.actor.user.hold_requests.count",
1523 notes => <<" NOTES");
1524 Returns hold ready/total counts
1526 sub hold_request_count {
1527 my( $self, $client, $login_session, $userid ) = @_;
1529 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1530 $login_session, $userid, 'VIEW_HOLD' );
1531 return $evt if $evt;
1534 my $holds = $apputils->simple_scalar_request(
1536 "open-ils.storage.direct.action.hold_request.search_where.atomic",
1538 fulfillment_time => {"=" => undef } }
1542 for my $h (@$holds) {
1543 next unless $h->capture_time;
1545 my $copy = $apputils->simple_scalar_request(
1547 "open-ils.storage.direct.asset.copy.retrieve",
1551 if ($copy->status == 8) {
1556 return { total => scalar(@$holds), ready => scalar(@ready) };
1560 __PACKAGE__->register_method(
1561 method => "checkedout_count",
1562 api_name => "open-ils.actor.user.checked_out.count",
1564 notes => <<" NOTES");
1565 Returns a transaction record
1567 sub checkedout_count {
1568 my( $self, $client, $login_session, $userid ) = @_;
1570 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1571 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1572 return $evt if $evt;
1575 my $circs = $apputils->simple_scalar_request(
1577 "open-ils.storage.direct.action.circulation.search_where.atomic",
1579 checkin_time => {"=" => undef } }
1582 my $parser = DateTime::Format::ISO8601->new;
1585 for my $c (@$circs) {
1586 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1587 my $due = $due_dt->epoch;
1594 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1597 __PACKAGE__->register_method(
1598 method => "user_transaction_history",
1599 api_name => "open-ils.actor.user.transactions.history",
1601 notes => <<" NOTES");
1602 Returns a list of billable transaction ids for a user, optionally by type
1604 sub user_transaction_history {
1605 my( $self, $client, $login_session, $user_id, $type ) = @_;
1607 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1608 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1609 return $evt if $evt;
1611 my $api = $self->api_name();
1614 @xact = (xact_type => $type) if(defined($type));
1616 my $trans = $apputils->simple_scalar_request(
1618 "open-ils.storage.direct.money.billable_transaction_summary.search_where.atomic",
1619 { usr => $user_id, @xact }, { order_by => 'xact_start DESC' });
1621 return [ map { $_->id } @$trans ];
1625 __PACKAGE__->register_method(
1626 method => "user_perms",
1627 api_name => "open-ils.actor.permissions.user_perms.retrieve",
1629 notes => <<" NOTES");
1630 Returns a list of permissions
1633 my( $self, $client, $authtoken, $user ) = @_;
1635 my( $staff, $evt ) = $apputils->checkses($authtoken);
1636 return $evt if $evt;
1638 $user ||= $staff->id;
1640 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1644 return $apputils->simple_scalar_request(
1646 "open-ils.storage.permission.user_perms.atomic",
1650 __PACKAGE__->register_method(
1651 method => "retrieve_perms",
1652 api_name => "open-ils.actor.permissions.retrieve",
1653 notes => <<" NOTES");
1654 Returns a list of permissions
1656 sub retrieve_perms {
1657 my( $self, $client ) = @_;
1658 return $apputils->simple_scalar_request(
1660 "open-ils.storage.direct.permission.perm_list.retrieve.all.atomic");
1663 __PACKAGE__->register_method(
1664 method => "retrieve_groups",
1665 api_name => "open-ils.actor.groups.retrieve",
1666 notes => <<" NOTES");
1667 Returns a list of user groupss
1669 sub retrieve_groups {
1670 my( $self, $client ) = @_;
1671 return $apputils->simple_scalar_request(
1673 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1676 __PACKAGE__->register_method(
1677 method => "retrieve_groups_tree",
1678 api_name => "open-ils.actor.groups.tree.retrieve",
1679 notes => <<" NOTES");
1680 Returns a list of user groups
1682 sub retrieve_groups_tree {
1683 my( $self, $client ) = @_;
1684 my $groups = $apputils->simple_scalar_request(
1686 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1687 return $self->build_group_tree($groups);
1691 # turns an org list into an org tree
1692 sub build_group_tree {
1694 my( $self, $grplist) = @_;
1696 return $grplist unless (
1697 ref($grplist) and @$grplist > 1 );
1699 my @list = sort { $a->name cmp $b->name } @$grplist;
1702 for my $grp (@list) {
1704 if ($grp and !defined($grp->parent)) {
1708 my ($parent) = grep { $_->id == $grp->parent} @list;
1710 $parent->children([]) unless defined($parent->children);
1711 push( @{$parent->children}, $grp );
1719 __PACKAGE__->register_method(
1720 method => "add_user_to_groups",
1721 api_name => "open-ils.actor.user.set_groups",
1722 notes => <<" NOTES");
1723 Adds a user to one or more permission groups
1726 sub add_user_to_groups {
1727 my( $self, $client, $authtoken, $userid, $groups ) = @_;
1729 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1730 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1731 return $evt if $evt;
1733 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1734 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
1735 return $evt if $evt;
1737 $apputils->simplereq(
1739 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
1741 for my $group (@$groups) {
1742 my $link = Fieldmapper::permission::usr_grp_map->new;
1744 $link->usr($userid);
1746 my $id = $apputils->simplereq(
1748 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
1754 __PACKAGE__->register_method(
1755 method => "get_user_perm_groups",
1756 api_name => "open-ils.actor.user.get_groups",
1757 notes => <<" NOTES");
1758 Retrieve a user's permission groups.
1762 sub get_user_perm_groups {
1763 my( $self, $client, $authtoken, $userid ) = @_;
1765 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1766 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
1767 return $evt if $evt;
1769 return $apputils->simplereq(
1771 'open-ils.storage.direct.permission.usr_grp_map.search.usr.atomic', $userid );
1776 __PACKAGE__->register_method (
1777 method => 'register_workstation',
1778 api_name => 'open-ils.actor.workstation.register',
1780 Registers a new workstion in the system
1781 @param authtoken The login session key
1782 @param name The name of the workstation id
1783 @param owner The org unit that owns this workstation
1784 @return The workstation id on success, WORKSTATION_NAME_EXISTS
1785 if the name is already in use.
1788 sub register_workstation {
1789 my( $self, $connection, $authtoken, $name, $owner ) = @_;
1790 my( $requestor, $evt ) = $U->checkses($authtoken);
1791 return $evt if $evt;
1792 $evt = $U->check_perms($requestor->id, $owner, 'REGISTER_WORKSTATION');
1793 return $evt if $evt;
1795 my $ws = $U->storagereq(
1796 'open-ils.storage.direct.actor.workstation.search.name', $name );
1797 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS') if $ws;
1799 $ws = Fieldmapper::actor::workstation->new;
1800 $ws->owning_lib($owner);
1803 my $id = $U->storagereq(
1804 'open-ils.storage.direct.actor.workstation.create', $ws );
1805 return $U->DB_UPDATE_FAILED($ws) unless $id;