1 package OpenILS::Application::Actor;
2 use OpenILS::Application;
3 use base qw/OpenILS::Application/;
4 use strict; use warnings;
6 $Data::Dumper::Indent = 0;
9 use Digest::MD5 qw(md5_hex);
11 use OpenSRF::EX qw(:try);
14 use OpenILS::Application::AppUtils;
16 use OpenILS::Utils::Fieldmapper;
17 use OpenILS::Utils::ModsParser;
18 use OpenSRF::Utils::Logger qw/$logger/;
19 use OpenSRF::Utils qw/:datetime/;
20 use OpenSRF::Utils::SettingsClient;
22 use OpenSRF::Utils::Cache;
24 use OpenSRF::Utils::JSON;
26 use DateTime::Format::ISO8601;
27 use OpenILS::Const qw/:const/;
29 use OpenILS::Application::Actor::Container;
30 use OpenILS::Application::Actor::ClosedDates;
31 use OpenILS::Application::Actor::UserGroups;
32 use OpenILS::Application::Actor::Friends;
34 use OpenILS::Utils::CStoreEditor qw/:funcs/;
35 use OpenILS::Utils::Penalty;
38 OpenILS::Application::Actor::Container->initialize();
39 OpenILS::Application::Actor::UserGroups->initialize();
40 OpenILS::Application::Actor::ClosedDates->initialize();
43 my $apputils = "OpenILS::Application::AppUtils";
46 sub _d { warn "Patron:\n" . Dumper(shift()); }
49 my $set_user_settings;
53 #__PACKAGE__->register_method(
54 # method => "allowed_test",
55 # api_name => "open-ils.actor.allowed_test",
58 # my($self, $conn, $auth, $orgid, $permcode) = @_;
59 # my $e = new_editor(authtoken => $auth);
60 # return $e->die_event unless $e->checkauth;
64 # permcode => $permcode,
65 # result => $e->allowed($permcode, $orgid)
69 __PACKAGE__->register_method(
70 method => "update_user_setting",
71 api_name => "open-ils.actor.patron.settings.update",
73 sub update_user_setting {
74 my($self, $conn, $auth, $user_id, $settings) = @_;
75 my $e = new_editor(xact => 1, authtoken => $auth);
76 return $e->die_event unless $e->checkauth;
78 $user_id = $e->requestor->id unless defined $user_id;
80 unless($e->requestor->id == $user_id) {
81 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
82 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
85 for my $name (keys %$settings) {
86 my $val = $$settings{$name};
87 my $set = $e->search_actor_user_setting({usr => $user_id, name => $name})->[0];
90 $val = OpenSRF::Utils::JSON->perl2JSON($val);
93 $e->update_actor_user_setting($set) or return $e->die_event;
95 $set = Fieldmapper::actor::user_setting->new;
99 $e->create_actor_user_setting($set) or return $e->die_event;
102 $e->delete_actor_user_setting($set) or return $e->die_event;
111 __PACKAGE__->register_method(
112 method => "set_ou_settings",
113 api_name => "open-ils.actor.org_unit.settings.update",
116 Updates the value for a given org unit setting. The permission to update
117 an org unit setting is either the UPDATE_ORG_UNIT_SETTING_ALL, or a specific
118 permission specified in the update_perm column of the
119 config.org_unit_setting_type table's row corresponding to the setting being
122 {desc => 'authtoken', type => 'string'},
123 {desc => 'org unit id', type => 'number'},
124 {desc => q/Hash of setting name-value pairs/, type => 'hash'},
126 return => {desc => '1 on success, Event on error'}
130 sub set_ou_settings {
131 my( $self, $client, $auth, $org_id, $settings ) = @_;
133 my $e = new_editor(authtoken => $auth, xact => 1);
134 return $e->die_event unless $e->checkauth;
136 my $all_allowed = $e->allowed("UPDATE_ORG_UNIT_SETTING_ALL", $org_id);
138 for my $name (keys %$settings) {
139 my $val = $$settings{$name};
141 my $type = $e->retrieve_config_org_unit_setting_type([
143 {flesh => 1, flesh_fields => {'coust' => ['update_perm']}}
144 ]) or return $e->die_event;
145 my $set = $e->search_actor_org_unit_setting({org_unit => $org_id, name => $name})->[0];
147 # If there is no relevant permission, the default assumption will
148 # be, "no, the caller cannot change that value."
149 return $e->die_event unless ($all_allowed ||
150 ($type->update_perm && $e->allowed($type->update_perm->code, $org_id)));
153 $val = OpenSRF::Utils::JSON->perl2JSON($val);
156 $e->update_actor_org_unit_setting($set) or return $e->die_event;
158 $set = Fieldmapper::actor::org_unit_setting->new;
159 $set->org_unit($org_id);
162 $e->create_actor_org_unit_setting($set) or return $e->die_event;
165 $e->delete_actor_org_unit_setting($set) or return $e->die_event;
173 __PACKAGE__->register_method(
174 method => "user_settings",
175 api_name => "open-ils.actor.patron.settings.retrieve",
178 my( $self, $client, $auth, $user_id, $setting ) = @_;
180 my $e = new_editor(authtoken => $auth);
181 return $e->event unless $e->checkauth;
182 $user_id = $e->requestor->id unless defined $user_id;
184 my $patron = $e->retrieve_actor_user($user_id) or return $e->event;
185 if($e->requestor->id != $user_id) {
186 return $e->event unless $e->allowed('VIEW_USER', $patron->home_ou);
190 my($e, $user_id, $setting) = @_;
191 my $val = $e->search_actor_user_setting({usr => $user_id, name => $setting})->[0];
192 return '' unless $val; # XXX this should really return undef, but needs testing
193 return OpenSRF::Utils::JSON->JSON2perl($val->value);
197 if(ref $setting eq 'ARRAY') {
199 $settings{$_} = get_setting($e, $user_id, $_) for @$setting;
202 return get_setting($e, $user_id, $setting);
205 my $s = $e->search_actor_user_setting({usr => $user_id});
206 return { map { ( $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) ) } @$s };
212 __PACKAGE__->register_method(
213 method => "ranged_ou_settings",
214 api_name => "open-ils.actor.org_unit_setting.values.ranged.retrieve",
217 Retrieves all org unit settings for the given org_id, up to whatever limit
218 is implied for retrieving OU settings by the authenticated users' permissions./,
220 {desc => 'authtoken', type => 'string'},
221 {desc => 'org unit id', type => 'number'},
223 return => {desc => 'A hashref of "ranged" settings'}
226 sub ranged_ou_settings {
227 my( $self, $client, $auth, $org_id ) = @_;
229 my $e = new_editor(authtoken => $auth);
230 return $e->event unless $e->checkauth;
233 my $org_list = $U->get_org_ancestors($org_id);
234 my $settings = $e->search_actor_org_unit_setting({org_unit => $org_list});
235 $org_list = [ reverse @$org_list ];
237 # start at the context org and capture the setting value
238 # without clobbering settings we've already captured
239 for my $this_org_id (@$org_list) {
241 my @sets = grep { $_->org_unit == $this_org_id } @$settings;
243 for my $set (@sets) {
244 my $type = $e->retrieve_config_org_unit_setting_type([
246 {flesh => 1, flesh_fields => {coust => ['view_perm']}}
249 # If there is no relevant permission, the default assumption will
250 # be, "yes, the caller can have that value."
251 if ($type && $type->view_perm) {
252 next if not $e->allowed($type->view_perm->code, $org_id);
255 $ranged_settings{$set->name} = OpenSRF::Utils::JSON->JSON2perl($set->value)
256 unless defined $ranged_settings{$set->name};
260 return \%ranged_settings;
265 __PACKAGE__->register_method(
266 api_name => 'open-ils.actor.ou_setting.ancestor_default',
267 method => 'ou_ancestor_setting',
269 desc => q/Get an org unit setting value as seen from your org unit. IF AND ONLY IF
270 you provide an authentication token, this method will make sure that the given
271 user has permission to view that setting, if there is a permission associated
274 {desc => 'org unit id', type => 'number'},
275 {desc => 'setting name', type => 'string'},
276 {desc => '(optional) authtoken', type => 'string'},
278 return => {desc => 'A value for the org unit setting, or undef'}
282 # ------------------------------------------------------------------
283 # Attempts to find the org setting value for a given org. if not
284 # found at the requested org, searches up the org tree until it
285 # finds a parent that has the requested setting.
286 # when found, returns { org => $id, value => $value }
287 # otherwise, returns NULL
288 # ------------------------------------------------------------------
289 sub ou_ancestor_setting {
290 my( $self, $client, $orgid, $name, $auth ) = @_;
291 return $U->ou_ancestor_setting($orgid, $name, undef, $auth);
294 __PACKAGE__->register_method(
295 api_name => 'open-ils.actor.ou_setting.ancestor_default.batch',
296 method => 'ou_ancestor_setting_batch',
298 desc => q/Get org unit setting name => value pairs as seen from the specified org unit.
299 IF AND ONLY IF you provide an authentication token, this method will make sure
300 that the given user has permission to view that setting, if there is a
301 permission associated with the setting./,
303 {desc => 'org unit id', type => 'number'},
304 {desc => 'setting name list', type => 'array'},
305 {desc => '(optional) authtoken', type => 'string'},
307 return => {desc => 'A hash with name => value pairs for the org unit settings'}
310 sub ou_ancestor_setting_batch {
311 my( $self, $client, $orgid, $name_list, $auth ) = @_;
313 $values{$_} = $U->ou_ancestor_setting($orgid, $_, undef, $auth) for @$name_list;
321 __PACKAGE__->register_method(
322 method => "update_patron",
323 api_name => "open-ils.actor.patron.update",);
326 my( $self, $client, $user_session, $patron ) = @_;
328 my $session = $apputils->start_db_session();
331 $logger->info("Creating new patron...") if $patron->isnew;
332 $logger->info("Updating Patron: " . $patron->id) unless $patron->isnew;
334 my( $user_obj, $evt ) = $U->checkses($user_session);
337 $evt = check_group_perm($session, $user_obj, $patron);
341 # $new_patron is the patron in progress. $patron is the original patron
342 # passed in with the method. new_patron will change as the components
343 # of patron are added/updated.
347 # unflesh the real items on the patron
348 $patron->card( $patron->card->id ) if(ref($patron->card));
349 $patron->billing_address( $patron->billing_address->id )
350 if(ref($patron->billing_address));
351 $patron->mailing_address( $patron->mailing_address->id )
352 if(ref($patron->mailing_address));
354 # create/update the patron first so we can use his id
355 if($patron->isnew()) {
356 ( $new_patron, $evt ) = _add_patron($session, _clone_patron($patron), $user_obj);
358 } else { $new_patron = $patron; }
360 ( $new_patron, $evt ) = _add_update_addresses($session, $patron, $new_patron, $user_obj);
363 ( $new_patron, $evt ) = _add_update_cards($session, $patron, $new_patron, $user_obj);
366 ( $new_patron, $evt ) = _add_survey_responses($session, $patron, $new_patron, $user_obj);
369 # re-update the patron if anything has happened to him during this process
370 if($new_patron->ischanged()) {
371 ( $new_patron, $evt ) = _update_patron($session, $new_patron, $user_obj);
375 ($new_patron, $evt) = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
378 ($new_patron, $evt) = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
381 $apputils->commit_db_session($session);
383 $evt = apply_invalid_addr_penalty($patron);
386 my $tses = OpenSRF::AppSession->create('open-ils.trigger');
388 $tses->request('open-ils.trigger.event.autocreate', 'au.create', $new_patron, $new_patron->home_ou);
390 $tses->request('open-ils.trigger.event.autocreate', 'au.update', $new_patron, $new_patron->home_ou);
393 return flesh_user($new_patron->id(), new_editor(requestor => $user_obj));
396 sub apply_invalid_addr_penalty {
398 my $e = new_editor(xact => 1);
400 # grab the invalid address penalty if set
401 my $penalties = OpenILS::Utils::Penalty->retrieve_usr_penalties($e, $patron->id, $patron->home_ou);
403 my ($addr_penalty) = grep
404 { $_->standing_penalty->name eq 'INVALID_PATRON_ADDRESS' } @$penalties;
406 # do we enforce invalid address penalty
407 my $enforce = $U->ou_ancestor_setting_value(
408 $patron->home_ou, 'circ.patron_invalid_address_apply_penalty') || 0;
410 my $addrs = $e->search_actor_user_address(
411 {usr => $patron->id, valid => 'f', id => {'>' => 0}}, {idlist => 1});
412 my $addr_count = scalar(@$addrs);
414 if($addr_count == 0 and $addr_penalty) {
416 # regardless of any settings, remove the penalty when the user has no invalid addresses
417 $e->delete_actor_user_standing_penalty($addr_penalty) or return $e->die_event;
420 } elsif($enforce and $addr_count > 0 and !$addr_penalty) {
422 my $ptype = $e->retrieve_config_standing_penalty(29) or return $e->die_event;
423 my $depth = $ptype->org_depth;
424 my $ctx_org = $U->org_unit_ancestor_at_depth($patron->home_ou, $depth) if defined $depth;
425 $ctx_org = $patron->home_ou unless defined $ctx_org;
427 my $penalty = Fieldmapper::actor::user_standing_penalty->new;
428 $penalty->usr($patron->id);
429 $penalty->org_unit($ctx_org);
430 $penalty->standing_penalty(OILS_PENALTY_INVALID_PATRON_ADDRESS);
432 $e->create_actor_user_standing_penalty($penalty) or return $e->die_event;
446 return new_flesh_user($id, [
449 "standing_penalties",
453 "stat_cat_entries" ], $e );
461 # clone and clear stuff that would break the database
465 my $new_patron = $patron->clone;
467 $new_patron->clear_billing_address();
468 $new_patron->clear_mailing_address();
469 $new_patron->clear_addresses();
470 $new_patron->clear_card();
471 $new_patron->clear_cards();
472 $new_patron->clear_id();
473 $new_patron->clear_isnew();
474 $new_patron->clear_ischanged();
475 $new_patron->clear_isdeleted();
476 $new_patron->clear_stat_cat_entries();
477 $new_patron->clear_permissions();
478 $new_patron->clear_standing_penalties();
488 my $user_obj = shift;
490 my $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'CREATE_USER');
491 return (undef, $evt) if $evt;
493 my $ex = $session->request(
494 'open-ils.storage.direct.actor.user.search.usrname', $patron->usrname())->gather(1);
496 return (undef, OpenILS::Event->new('USERNAME_EXISTS'));
499 $logger->info("Creating new user in the DB with username: ".$patron->usrname());
501 my $id = $session->request(
502 "open-ils.storage.direct.actor.user.create", $patron)->gather(1);
503 return (undef, $U->DB_UPDATE_FAILED($patron)) unless $id;
505 $logger->info("Successfully created new user [$id] in DB");
507 return ( $session->request(
508 "open-ils.storage.direct.actor.user.retrieve", $id)->gather(1), undef );
512 sub check_group_perm {
513 my( $session, $requestor, $patron ) = @_;
516 # first let's see if the requestor has
517 # priveleges to update this user in any way
518 if( ! $patron->isnew ) {
519 my $p = $session->request(
520 'open-ils.storage.direct.actor.user.retrieve', $patron->id )->gather(1);
522 # If we are the requestor (trying to update our own account)
523 # and we are not trying to change our profile, we're good
524 if( $p->id == $requestor->id and
525 $p->profile == $patron->profile ) {
530 $evt = group_perm_failed($session, $requestor, $p);
534 # They are allowed to edit this patron.. can they put the
535 # patron into the group requested?
536 $evt = group_perm_failed($session, $requestor, $patron);
542 sub group_perm_failed {
543 my( $session, $requestor, $patron ) = @_;
547 my $grpid = $patron->profile;
551 $logger->debug("user update looking for group perm for group $grpid");
552 $grp = $session->request(
553 'open-ils.storage.direct.permission.grp_tree.retrieve', $grpid )->gather(1);
554 return OpenILS::Event->new('PERMISSION_GRP_TREE_NOT_FOUND') unless $grp;
556 } while( !($perm = $grp->application_perm) and ($grpid = $grp->parent) );
558 $logger->info("user update checking perm $perm on user ".
559 $requestor->id." for update/create on user username=".$patron->usrname);
561 my $evt = $U->check_perms($requestor->id, $patron->home_ou, $perm);
569 my( $session, $patron, $user_obj, $noperm) = @_;
571 $logger->info("Updating patron ".$patron->id." in DB");
576 $evt = $U->check_perms($user_obj->id, $patron->home_ou, 'UPDATE_USER');
577 return (undef, $evt) if $evt;
580 # update the password by itself to avoid the password protection magic
581 if( $patron->passwd ) {
582 my $s = $session->request(
583 'open-ils.storage.direct.actor.user.remote_update',
584 {id => $patron->id}, {passwd => $patron->passwd})->gather(1);
585 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($s);
586 $patron->clear_passwd;
589 if(!$patron->ident_type) {
590 $patron->clear_ident_type;
591 $patron->clear_ident_value;
594 $evt = verify_last_xact($session, $patron);
595 return (undef, $evt) if $evt;
597 my $stat = $session->request(
598 "open-ils.storage.direct.actor.user.update",$patron )->gather(1);
599 return (undef, $U->DB_UPDATE_FAILED($patron)) unless defined($stat);
604 sub verify_last_xact {
605 my( $session, $patron ) = @_;
606 return undef unless $patron->id and $patron->id > 0;
607 my $p = $session->request(
608 'open-ils.storage.direct.actor.user.retrieve', $patron->id)->gather(1);
609 my $xact = $p->last_xact_id;
610 return undef unless $xact;
611 $logger->info("user xact = $xact, saving with xact " . $patron->last_xact_id);
612 return OpenILS::Event->new('XACT_COLLISION')
613 if $xact != $patron->last_xact_id;
618 sub _check_dup_ident {
619 my( $session, $patron ) = @_;
621 return undef unless $patron->ident_value;
624 ident_type => $patron->ident_type,
625 ident_value => $patron->ident_value,
628 $logger->debug("patron update searching for dup ident values: " .
629 $patron->ident_type . ':' . $patron->ident_value);
631 $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
633 my $dups = $session->request(
634 'open-ils.storage.direct.actor.user.search_where.atomic', $search )->gather(1);
637 return OpenILS::Event->new('PATRON_DUP_IDENT1', payload => $patron )
644 sub _add_update_addresses {
648 my $new_patron = shift;
652 my $current_id; # id of the address before creation
654 for my $address (@{$patron->addresses()}) {
656 next unless ref $address;
657 $current_id = $address->id();
659 if( $patron->billing_address() and
660 $patron->billing_address() == $current_id ) {
661 $logger->info("setting billing addr to $current_id");
662 $new_patron->billing_address($address->id());
663 $new_patron->ischanged(1);
666 if( $patron->mailing_address() and
667 $patron->mailing_address() == $current_id ) {
668 $new_patron->mailing_address($address->id());
669 $logger->info("setting mailing addr to $current_id");
670 $new_patron->ischanged(1);
674 if($address->isnew()) {
676 $address->usr($new_patron->id());
678 ($address, $evt) = _add_address($session,$address);
679 return (undef, $evt) if $evt;
681 # we need to get the new id
682 if( $patron->billing_address() and
683 $patron->billing_address() == $current_id ) {
684 $new_patron->billing_address($address->id());
685 $logger->info("setting billing addr to $current_id");
686 $new_patron->ischanged(1);
689 if( $patron->mailing_address() and
690 $patron->mailing_address() == $current_id ) {
691 $new_patron->mailing_address($address->id());
692 $logger->info("setting mailing addr to $current_id");
693 $new_patron->ischanged(1);
696 } elsif($address->ischanged() ) {
698 ($address, $evt) = _update_address($session, $address);
699 return (undef, $evt) if $evt;
701 } elsif($address->isdeleted() ) {
703 if( $address->id() == $new_patron->mailing_address() ) {
704 $new_patron->clear_mailing_address();
705 ($new_patron, $evt) = _update_patron($session, $new_patron);
706 return (undef, $evt) if $evt;
709 if( $address->id() == $new_patron->billing_address() ) {
710 $new_patron->clear_billing_address();
711 ($new_patron, $evt) = _update_patron($session, $new_patron);
712 return (undef, $evt) if $evt;
715 $evt = _delete_address($session, $address);
716 return (undef, $evt) if $evt;
720 return ( $new_patron, undef );
724 # adds an address to the db and returns the address with new id
726 my($session, $address) = @_;
727 $address->clear_id();
729 $logger->info("Creating new address at street ".$address->street1);
731 # put the address into the database
732 my $id = $session->request(
733 "open-ils.storage.direct.actor.user_address.create", $address )->gather(1);
734 return (undef, $U->DB_UPDATE_FAILED($address)) unless $id;
737 return ($address, undef);
741 sub _update_address {
742 my( $session, $address ) = @_;
744 $logger->info("Updating address ".$address->id." in the DB");
746 my $stat = $session->request(
747 "open-ils.storage.direct.actor.user_address.update", $address )->gather(1);
749 return (undef, $U->DB_UPDATE_FAILED($address)) unless defined($stat);
750 return ($address, undef);
755 sub _add_update_cards {
759 my $new_patron = shift;
763 my $virtual_id; #id of the card before creation
764 for my $card (@{$patron->cards()}) {
766 $card->usr($new_patron->id());
768 if(ref($card) and $card->isnew()) {
770 $virtual_id = $card->id();
771 ( $card, $evt ) = _add_card($session,$card);
772 return (undef, $evt) if $evt;
774 #if(ref($patron->card)) { $patron->card($patron->card->id); }
775 if($patron->card() == $virtual_id) {
776 $new_patron->card($card->id());
777 $new_patron->ischanged(1);
780 } elsif( ref($card) and $card->ischanged() ) {
781 $evt = _update_card($session, $card);
782 return (undef, $evt) if $evt;
786 return ( $new_patron, undef );
790 # adds an card to the db and returns the card with new id
792 my( $session, $card ) = @_;
795 $logger->info("Adding new patron card ".$card->barcode);
797 my $id = $session->request(
798 "open-ils.storage.direct.actor.card.create", $card )->gather(1);
799 return (undef, $U->DB_UPDATE_FAILED($card)) unless $id;
800 $logger->info("Successfully created patron card $id");
803 return ( $card, undef );
807 # returns event on error. returns undef otherwise
809 my( $session, $card ) = @_;
810 $logger->info("Updating patron card ".$card->id);
812 my $stat = $session->request(
813 "open-ils.storage.direct.actor.card.update", $card )->gather(1);
814 return $U->DB_UPDATE_FAILED($card) unless defined($stat);
821 # returns event on error. returns undef otherwise
822 sub _delete_address {
823 my( $session, $address ) = @_;
825 $logger->info("Deleting address ".$address->id." from DB");
827 my $stat = $session->request(
828 "open-ils.storage.direct.actor.user_address.delete", $address )->gather(1);
830 return $U->DB_UPDATE_FAILED($address) unless defined($stat);
836 sub _add_survey_responses {
837 my ($session, $patron, $new_patron) = @_;
839 $logger->info( "Updating survey responses for patron ".$new_patron->id );
841 my $responses = $patron->survey_responses;
845 $_->usr($new_patron->id) for (@$responses);
847 my $evt = $U->simplereq( "open-ils.circ",
848 "open-ils.circ.survey.submit.user_id", $responses );
850 return (undef, $evt) if defined($U->event_code($evt));
854 return ( $new_patron, undef );
858 sub _create_stat_maps {
860 my($session, $user_session, $patron, $new_patron) = @_;
862 my $maps = $patron->stat_cat_entries();
864 for my $map (@$maps) {
866 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
868 if ($map->isdeleted()) {
869 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.delete";
871 } elsif ($map->isnew()) {
872 $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
877 $map->target_usr($new_patron->id);
880 $logger->info("Updating stat entry with method $method and map $map");
882 my $stat = $session->request($method, $map)->gather(1);
883 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
887 return ($new_patron, undef);
890 sub _create_perm_maps {
892 my($session, $user_session, $patron, $new_patron) = @_;
894 my $maps = $patron->permissions;
896 for my $map (@$maps) {
898 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
899 if ($map->isdeleted()) {
900 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
901 } elsif ($map->isnew()) {
902 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
907 $map->usr($new_patron->id);
909 #warn( "Updating permissions with method $method and session $user_session and map $map" );
910 $logger->info( "Updating permissions with method $method and map $map" );
912 my $stat = $session->request($method, $map)->gather(1);
913 return (undef, $U->DB_UPDATE_FAILED($map)) unless defined($stat);
917 return ($new_patron, undef);
921 __PACKAGE__->register_method(
922 method => "set_user_work_ous",
923 api_name => "open-ils.actor.user.work_ous.update",
926 sub set_user_work_ous {
932 my( $requestor, $evt ) = $apputils->checksesperm( $ses, 'ASSIGN_WORK_ORG_UNIT' );
935 my $session = $apputils->start_db_session();
937 for my $map (@$maps) {
939 my $method = "open-ils.storage.direct.permission.usr_work_ou_map.update";
940 if ($map->isdeleted()) {
941 $method = "open-ils.storage.direct.permission.usr_work_ou_map.delete";
942 } elsif ($map->isnew()) {
943 $method = "open-ils.storage.direct.permission.usr_work_ou_map.create";
947 #warn( "Updating permissions with method $method and session $ses and map $map" );
948 $logger->info( "Updating work_ou map with method $method and map $map" );
950 my $stat = $session->request($method, $map)->gather(1);
951 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
955 $apputils->commit_db_session($session);
957 return scalar(@$maps);
961 __PACKAGE__->register_method(
962 method => "set_user_perms",
963 api_name => "open-ils.actor.user.permissions.update",
972 my $session = $apputils->start_db_session();
974 my( $user_obj, $evt ) = $U->checkses($ses);
977 my $perms = $session->request('open-ils.storage.permission.user_perms.atomic', $user_obj->id)->gather(1);
980 $all = 1 if ($U->is_true($user_obj->super_user()));
981 $all = 1 unless ($U->check_perms($user_obj->id, $user_obj->home_ou, 'EVERYTHING'));
983 for my $map (@$maps) {
985 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
986 if ($map->isdeleted()) {
987 $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
988 } elsif ($map->isnew()) {
989 $method = "open-ils.storage.direct.permission.usr_perm_map.create";
993 next if (!$all and !grep { $_->perm eq $map->perm and $U->is_true($_->grantable) and $_->depth <= $map->depth } @$perms);
994 #warn( "Updating permissions with method $method and session $ses and map $map" );
995 $logger->info( "Updating permissions with method $method and map $map" );
997 my $stat = $session->request($method, $map)->gather(1);
998 $logger->warn( "update failed: ".$U->DB_UPDATE_FAILED($map) ) unless defined($stat);
1002 $apputils->commit_db_session($session);
1004 return scalar(@$maps);
1008 __PACKAGE__->register_method(
1009 method => "user_retrieve_by_barcode",
1011 api_name => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
1013 sub user_retrieve_by_barcode {
1014 my($self, $client, $user_session, $barcode) = @_;
1016 $logger->debug("Searching for user with barcode $barcode");
1017 my ($user_obj, $evt) = $apputils->checkses($user_session);
1018 return $evt if $evt;
1020 my $card = OpenILS::Application::AppUtils->simple_scalar_request(
1022 "open-ils.cstore.direct.actor.card.search.atomic",
1023 { barcode => $barcode }
1026 if(!$card || !$card->[0]) {
1027 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' );
1031 my $user = flesh_user($card->usr(), new_editor(requestor => $user_obj));
1033 $evt = $U->check_perms($user_obj->id, $user->home_ou, 'VIEW_USER');
1034 return $evt if $evt;
1036 if(!$user) { return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ); }
1043 __PACKAGE__->register_method(
1044 method => "get_user_by_id",
1046 api_name => "open-ils.actor.user.retrieve",);
1048 sub get_user_by_id {
1049 my ($self, $client, $auth, $id) = @_;
1050 my $e = new_editor(authtoken=>$auth);
1051 return $e->event unless $e->checkauth;
1052 my $user = $e->retrieve_actor_user($id)
1053 or return $e->event;
1054 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
1060 __PACKAGE__->register_method(
1061 method => "get_org_types",
1062 api_name => "open-ils.actor.org_types.retrieve",);
1065 return $U->get_org_types();
1070 __PACKAGE__->register_method(
1071 method => "get_user_ident_types",
1072 api_name => "open-ils.actor.user.ident_types.retrieve",
1075 sub get_user_ident_types {
1076 return $ident_types if $ident_types;
1077 return $ident_types =
1078 new_editor()->retrieve_all_config_identification_type();
1084 __PACKAGE__->register_method(
1085 method => "get_org_unit",
1086 api_name => "open-ils.actor.org_unit.retrieve",
1090 my( $self, $client, $user_session, $org_id ) = @_;
1091 my $e = new_editor(authtoken => $user_session);
1093 return $e->event unless $e->checkauth;
1094 $org_id = $e->requestor->ws_ou;
1096 my $o = $e->retrieve_actor_org_unit($org_id)
1097 or return $e->event;
1101 __PACKAGE__->register_method(
1102 method => "search_org_unit",
1103 api_name => "open-ils.actor.org_unit_list.search",
1106 sub search_org_unit {
1108 my( $self, $client, $field, $value ) = @_;
1110 my $list = OpenILS::Application::AppUtils->simple_scalar_request(
1112 "open-ils.cstore.direct.actor.org_unit.search.atomic",
1113 { $field => $value } );
1119 # build the org tree
1121 __PACKAGE__->register_method(
1122 method => "get_org_tree",
1123 api_name => "open-ils.actor.org_tree.retrieve",
1125 note => "Returns the entire org tree structure",
1131 return $U->get_org_tree($client->session->session_locale);
1135 __PACKAGE__->register_method(
1136 method => "get_org_descendants",
1137 api_name => "open-ils.actor.org_tree.descendants.retrieve"
1140 # depth is optional. org_unit is the id
1141 sub get_org_descendants {
1142 my( $self, $client, $org_unit, $depth ) = @_;
1144 if(ref $org_unit eq 'ARRAY') {
1147 for my $i (0..scalar(@$org_unit)-1) {
1148 my $list = $U->simple_scalar_request(
1150 "open-ils.storage.actor.org_unit.descendants.atomic",
1151 $org_unit->[$i], $depth->[$i] );
1152 push(@trees, $U->build_org_tree($list));
1157 my $orglist = $apputils->simple_scalar_request(
1159 "open-ils.storage.actor.org_unit.descendants.atomic",
1160 $org_unit, $depth );
1161 return $U->build_org_tree($orglist);
1166 __PACKAGE__->register_method(
1167 method => "get_org_ancestors",
1168 api_name => "open-ils.actor.org_tree.ancestors.retrieve"
1171 # depth is optional. org_unit is the id
1172 sub get_org_ancestors {
1173 my( $self, $client, $org_unit, $depth ) = @_;
1174 my $orglist = $apputils->simple_scalar_request(
1176 "open-ils.storage.actor.org_unit.ancestors.atomic",
1177 $org_unit, $depth );
1178 return $U->build_org_tree($orglist);
1182 __PACKAGE__->register_method(
1183 method => "get_standings",
1184 api_name => "open-ils.actor.standings.retrieve"
1189 return $user_standings if $user_standings;
1190 return $user_standings =
1191 $apputils->simple_scalar_request(
1193 "open-ils.cstore.direct.config.standing.search.atomic",
1194 { id => { "!=" => undef } }
1200 __PACKAGE__->register_method(
1201 method => "get_my_org_path",
1202 api_name => "open-ils.actor.org_unit.full_path.retrieve"
1205 sub get_my_org_path {
1206 my( $self, $client, $auth, $org_id ) = @_;
1207 my $e = new_editor(authtoken=>$auth);
1208 return $e->event unless $e->checkauth;
1209 $org_id = $e->requestor->ws_ou unless defined $org_id;
1211 return $apputils->simple_scalar_request(
1213 "open-ils.storage.actor.org_unit.full_path.atomic",
1218 __PACKAGE__->register_method(
1219 method => "patron_adv_search",
1220 api_name => "open-ils.actor.patron.search.advanced" );
1221 sub patron_adv_search {
1222 my( $self, $client, $auth, $search_hash,
1223 $search_limit, $search_sort, $include_inactive, $search_depth ) = @_;
1225 my $e = new_editor(authtoken=>$auth);
1226 return $e->event unless $e->checkauth;
1227 return $e->event unless $e->allowed('VIEW_USER');
1228 return $U->storagereq(
1229 "open-ils.storage.actor.user.crazy_search", $search_hash,
1230 $search_limit, $search_sort, $include_inactive, $e->requestor->ws_ou, $search_depth);
1234 __PACKAGE__->register_method(
1235 method => "update_passwd",
1237 api_name => "open-ils.actor.user.password.update");
1239 __PACKAGE__->register_method(
1240 method => "update_passwd",
1241 api_name => "open-ils.actor.user.username.update");
1243 __PACKAGE__->register_method(
1244 method => "update_passwd",
1245 api_name => "open-ils.actor.user.email.update");
1248 my( $self, $conn, $auth, $new_val, $orig_pw ) = @_;
1249 my $e = new_editor(xact=>1, authtoken=>$auth);
1250 return $e->die_event unless $e->checkauth;
1252 my $db_user = $e->retrieve_actor_user($e->requestor->id)
1253 or return $e->die_event;
1254 my $api = $self->api_name;
1256 if( $api =~ /password/o ) {
1258 # make sure the original password matches the in-database password
1259 return OpenILS::Event->new('INCORRECT_PASSWORD')
1260 if md5_hex($orig_pw) ne $db_user->passwd;
1261 $db_user->passwd($new_val);
1265 # if we don't clear the password, the user will be updated with
1266 # a hashed version of the hashed version of their password
1267 $db_user->clear_passwd;
1269 if( $api =~ /username/o ) {
1271 # make sure no one else has this username
1272 my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
1273 return OpenILS::Event->new('USERNAME_EXISTS') if @$exist;
1274 $db_user->usrname($new_val);
1276 } elsif( $api =~ /email/o ) {
1277 $db_user->email($new_val);
1281 $e->update_actor_user($db_user) or return $e->die_event;
1289 __PACKAGE__->register_method(
1290 method => "check_user_perms",
1291 api_name => "open-ils.actor.user.perm.check",
1292 notes => <<" NOTES");
1293 Takes a login session, user id, an org id, and an array of perm type strings. For each
1294 perm type, if the user does *not* have the given permission it is added
1295 to a list which is returned from the method. If all permissions
1296 are allowed, an empty list is returned
1297 if the logged in user does not match 'user_id', then the logged in user must
1298 have VIEW_PERMISSION priveleges.
1301 sub check_user_perms {
1302 my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1304 my( $staff, $evt ) = $apputils->checkses($login_session);
1305 return $evt if $evt;
1307 if($staff->id ne $user_id) {
1308 if( $evt = $apputils->check_perms(
1309 $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1315 for my $perm (@$perm_types) {
1316 if($apputils->check_perms($user_id, $org_id, $perm)) {
1317 push @not_allowed, $perm;
1321 return \@not_allowed
1324 __PACKAGE__->register_method(
1325 method => "check_user_perms2",
1326 api_name => "open-ils.actor.user.perm.check.multi_org",
1328 Checks the permissions on a list of perms and orgs for a user
1329 @param authtoken The login session key
1330 @param user_id The id of the user to check
1331 @param orgs The array of org ids
1332 @param perms The array of permission names
1333 @return An array of [ orgId, permissionName ] arrays that FAILED the check
1334 if the logged in user does not match 'user_id', then the logged in user must
1335 have VIEW_PERMISSION priveleges.
1338 sub check_user_perms2 {
1339 my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1341 my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1342 $authtoken, $user_id, 'VIEW_PERMISSION' );
1343 return $evt if $evt;
1346 for my $org (@$orgs) {
1347 for my $perm (@$perms) {
1348 if($apputils->check_perms($user_id, $org, $perm)) {
1349 push @not_allowed, [ $org, $perm ];
1354 return \@not_allowed
1358 __PACKAGE__->register_method(
1359 method => 'check_user_perms3',
1360 api_name => 'open-ils.actor.user.perm.highest_org',
1362 Returns the highest org unit id at which a user has a given permission
1363 If the requestor does not match the target user, the requestor must have
1364 'VIEW_PERMISSION' rights at the home org unit of the target user
1365 @param authtoken The login session key
1366 @param userid The id of the user in question
1367 @param perm The permission to check
1368 @return The org unit highest in the org tree within which the user has
1369 the requested permission
1372 sub check_user_perms3 {
1373 my($self, $client, $authtoken, $user_id, $perm) = @_;
1374 my $e = new_editor(authtoken=>$authtoken);
1375 return $e->event unless $e->checkauth;
1377 my $tree = $U->get_org_tree();
1379 unless($e->requestor->id == $user_id) {
1380 my $user = $e->retrieve_actor_user($user_id)
1381 or return $e->event;
1382 return $e->event unless $e->allowed('VIEW_PERMISSION', $user->home_ou);
1383 return $U->find_highest_perm_org($perm, $user_id, $user->home_ou, $tree );
1386 return $U->find_highest_perm_org($perm, $user_id, $e->requestor->ws_ou, $tree);
1389 __PACKAGE__->register_method(
1390 method => 'user_has_work_perm_at',
1391 api_name => 'open-ils.actor.user.has_work_perm_at',
1395 Returns a set of org unit IDs which represent the highest orgs in
1396 the org tree where the user has the requested permission. The
1397 purpose of this method is to return the smallest set of org units
1398 which represent the full expanse of the user's ability to perform
1399 the requested action. The user whose perms this method should
1400 check is implied by the authtoken. /,
1402 {desc => 'authtoken', type => 'string'},
1403 {desc => 'permission name', type => 'string'},
1404 {desc => q/user id, optional. If present, check perms for
1405 this user instead of the logged in user/, type => 'number'},
1407 return => {desc => 'An array of org IDs'}
1411 sub user_has_work_perm_at {
1412 my($self, $conn, $auth, $perm, $user_id) = @_;
1413 my $e = new_editor(authtoken=>$auth);
1414 return $e->event unless $e->checkauth;
1415 if(defined $user_id) {
1416 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
1417 return $e->event unless $e->allowed('VIEW_PERMISSION', $user->home_ou);
1419 return $U->user_has_work_perm_at($e, $perm, undef, $user_id);
1422 __PACKAGE__->register_method(
1423 method => 'user_has_work_perm_at_batch',
1424 api_name => 'open-ils.actor.user.has_work_perm_at.batch',
1428 sub user_has_work_perm_at_batch {
1429 my($self, $conn, $auth, $perms, $user_id) = @_;
1430 my $e = new_editor(authtoken=>$auth);
1431 return $e->event unless $e->checkauth;
1432 if(defined $user_id) {
1433 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
1434 return $e->event unless $e->allowed('VIEW_PERMISSION', $user->home_ou);
1437 $map->{$_} = $U->user_has_work_perm_at($e, $_) for @$perms;
1443 __PACKAGE__->register_method(
1444 method => 'check_user_perms4',
1445 api_name => 'open-ils.actor.user.perm.highest_org.batch',
1447 Returns the highest org unit id at which a user has a given permission
1448 If the requestor does not match the target user, the requestor must have
1449 'VIEW_PERMISSION' rights at the home org unit of the target user
1450 @param authtoken The login session key
1451 @param userid The id of the user in question
1452 @param perms An array of perm names to check
1453 @return An array of orgId's representing the org unit
1454 highest in the org tree within which the user has the requested permission
1455 The arrah of orgId's has matches the order of the perms array
1458 sub check_user_perms4 {
1459 my( $self, $client, $authtoken, $userid, $perms ) = @_;
1461 my( $staff, $target, $org, $evt );
1463 ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1464 $authtoken, $userid, 'VIEW_PERMISSION' );
1465 return $evt if $evt;
1468 return [] unless ref($perms);
1469 my $tree = $U->get_org_tree();
1471 for my $p (@$perms) {
1472 push( @arr, $U->find_highest_perm_org( $p, $userid, $target->home_ou, $tree ) );
1480 __PACKAGE__->register_method(
1481 method => "user_fines_summary",
1482 api_name => "open-ils.actor.user.fines.summary",
1484 notes => <<" NOTES");
1485 Returns a short summary of the users total open fines, excluding voided fines
1486 Params are login_session, user_id
1487 Returns a 'mous' object.
1490 sub user_fines_summary {
1491 my( $self, $client, $auth, $user_id ) = @_;
1492 my $e = new_editor(authtoken=>$auth);
1493 return $e->event unless $e->checkauth;
1494 my $user = $e->retrieve_actor_user($user_id)
1495 or return $e->event;
1497 if( $user_id ne $e->requestor->id ) {
1498 return $e->event unless
1499 $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
1502 # run this inside a transaction to prevent replication delay errors
1503 my $ses = $U->start_db_session();
1504 my $s = $ses->request(
1505 'open-ils.storage.money.open_user_summary.search', $user_id )->gather(1);
1506 $U->rollback_db_session($ses);
1513 __PACKAGE__->register_method(
1514 method => "user_transactions",
1515 api_name => "open-ils.actor.user.transactions",
1516 notes => <<" NOTES");
1517 Returns a list of open user transactions (mbts objects);
1518 Params are login_session, user_id
1519 Optional third parameter is the transactions type. defaults to all
1522 __PACKAGE__->register_method(
1523 method => "user_transactions",
1524 api_name => "open-ils.actor.user.transactions.have_charge",
1525 notes => <<" NOTES");
1526 Returns a list of all open user transactions (mbts objects) that have an initial charge
1527 Params are login_session, user_id
1528 Optional third parameter is the transactions type. defaults to all
1531 __PACKAGE__->register_method(
1532 method => "user_transactions",
1533 api_name => "open-ils.actor.user.transactions.have_balance",
1535 notes => <<" NOTES");
1536 Returns a list of all open user transactions (mbts objects) that have a balance
1537 Params are login_session, user_id
1538 Optional third parameter is the transactions type. defaults to all
1541 __PACKAGE__->register_method(
1542 method => "user_transactions",
1543 api_name => "open-ils.actor.user.transactions.fleshed",
1544 notes => <<" NOTES");
1545 Returns an object/hash of transaction, circ, title where transaction = an open
1546 user transactions (mbts objects), circ is the attached circluation, and title
1547 is the title the circ points to
1548 Params are login_session, user_id
1549 Optional third parameter is the transactions type. defaults to all
1552 __PACKAGE__->register_method(
1553 method => "user_transactions",
1554 api_name => "open-ils.actor.user.transactions.have_charge.fleshed",
1555 notes => <<" NOTES");
1556 Returns an object/hash of transaction, circ, title where transaction = an open
1557 user transactions that has an initial charge (mbts objects), circ is the
1558 attached circluation, and title is the title the circ points to
1559 Params are login_session, user_id
1560 Optional third parameter is the transactions type. defaults to all
1563 __PACKAGE__->register_method(
1564 method => "user_transactions",
1565 api_name => "open-ils.actor.user.transactions.have_balance.fleshed",
1567 notes => <<" NOTES");
1568 Returns an object/hash of transaction, circ, title where transaction = an open
1569 user transaction that has a balance (mbts objects), circ is the attached
1570 circluation, and title is the title the circ points to
1571 Params are login_session, user_id
1572 Optional third parameter is the transaction type. defaults to all
1575 __PACKAGE__->register_method(
1576 method => "user_transactions",
1577 api_name => "open-ils.actor.user.transactions.count",
1578 notes => <<" NOTES");
1579 Returns an object/hash of transaction, circ, title where transaction = an open
1580 user transactions (mbts objects), circ is the attached circluation, and title
1581 is the title the circ points to
1582 Params are login_session, user_id
1583 Optional third parameter is the transactions type. defaults to all
1586 __PACKAGE__->register_method(
1587 method => "user_transactions",
1588 api_name => "open-ils.actor.user.transactions.have_charge.count",
1589 notes => <<" NOTES");
1590 Returns an object/hash of transaction, circ, title where transaction = an open
1591 user transactions that has an initial charge (mbts objects), circ is the
1592 attached circluation, and title is the title the circ points to
1593 Params are login_session, user_id
1594 Optional third parameter is the transactions type. defaults to all
1597 __PACKAGE__->register_method(
1598 method => "user_transactions",
1599 api_name => "open-ils.actor.user.transactions.have_balance.count",
1601 notes => <<" NOTES");
1602 Returns an object/hash of transaction, circ, title where transaction = an open
1603 user transaction that has a balance (mbts objects), circ is the attached
1604 circluation, and title is the title the circ points to
1605 Params are login_session, user_id
1606 Optional third parameter is the transaction type. defaults to all
1609 __PACKAGE__->register_method(
1610 method => "user_transactions",
1611 api_name => "open-ils.actor.user.transactions.have_balance.total",
1613 notes => <<" NOTES");
1614 Returns an object/hash of transaction, circ, title where transaction = an open
1615 user transaction that has a balance (mbts objects), circ is the attached
1616 circluation, and title is the title the circ points to
1617 Params are login_session, user_id
1618 Optional third parameter is the transaction type. defaults to all
1623 sub user_transactions {
1624 my( $self, $client, $login_session, $user_id, $type ) = @_;
1626 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1627 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1628 return $evt if $evt;
1630 my $api = $self->api_name();
1634 if(defined($type)) { @xact = (xact_type => $type);
1636 } else { @xact = (); }
1639 ->method_lookup('open-ils.actor.user.transactions.history.still_open')
1640 ->run($login_session => $user_id => $type);
1643 if($api =~ /have_charge/o) {
1645 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1647 } elsif($api =~ /have_balance/o) {
1649 $trans = [ grep { int($_->balance_owed * 100) != 0 } @$trans ];
1652 $trans = [ grep { int($_->total_owed * 100) > 0 } @$trans ];
1656 if($api =~ /total/o) {
1658 for my $t (@$trans) {
1659 $total += $t->balance_owed;
1662 $logger->debug("Total balance owed by user $user_id: $total");
1666 if($api =~ /count/o) { return scalar @$trans; }
1667 if($api !~ /fleshed/o) { return $trans; }
1670 for my $t (@$trans) {
1672 if( $t->xact_type ne 'circulation' ) {
1673 push @resp, {transaction => $t};
1677 my $circ = $apputils->simple_scalar_request(
1679 "open-ils.cstore.direct.action.circulation.retrieve",
1684 my $title = $apputils->simple_scalar_request(
1686 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1687 $circ->target_copy );
1691 my $u = OpenILS::Utils::ModsParser->new();
1692 $u->start_mods_batch($title->marc());
1693 my $mods = $u->finish_mods_batch();
1694 $mods->doc_id($title->id) if $mods;
1696 push @resp, {transaction => $t, circ => $circ, record => $mods };
1704 __PACKAGE__->register_method(
1705 method => "user_transaction_retrieve",
1706 api_name => "open-ils.actor.user.transaction.fleshed.retrieve",
1708 notes => <<" NOTES");
1709 Returns a fleshed transaction record
1711 __PACKAGE__->register_method(
1712 method => "user_transaction_retrieve",
1713 api_name => "open-ils.actor.user.transaction.retrieve",
1715 notes => <<" NOTES");
1716 Returns a transaction record
1718 sub user_transaction_retrieve {
1719 my( $self, $client, $login_session, $bill_id ) = @_;
1721 # I think I'm deprecated... make sure. phasefx says, "No, I'll use you :)
1723 my $trans = $apputils->simple_scalar_request(
1725 "open-ils.cstore.direct.money.billable_transaction_summary.retrieve",
1729 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1730 $login_session, $trans->usr, 'VIEW_USER_TRANSACTIONS' );
1731 return $evt if $evt;
1733 my $api = $self->api_name();
1734 if($api !~ /fleshed/o) { return $trans; }
1736 if( $trans->xact_type ne 'circulation' ) {
1737 $logger->debug("Returning non-circ transaction");
1738 return {transaction => $trans};
1741 my $circ = $apputils->simple_scalar_request(
1743 "open-ils.cstore.direct.action.circulation.retrieve",
1746 return {transaction => $trans} unless $circ;
1747 $logger->debug("Found the circ transaction");
1749 my $title = $apputils->simple_scalar_request(
1751 "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1752 $circ->target_copy );
1754 return {transaction => $trans, circ => $circ } unless $title;
1755 $logger->debug("Found the circ title");
1758 my $copy = $apputils->simple_scalar_request(
1760 "open-ils.cstore.direct.asset.copy.retrieve",
1761 $circ->target_copy );
1764 my $u = OpenILS::Utils::ModsParser->new();
1765 $u->start_mods_batch($title->marc());
1766 $mods = $u->finish_mods_batch();
1768 if ($title->id == OILS_PRECAT_RECORD) {
1769 $mods = new Fieldmapper::metabib::virtual_record;
1770 $mods->doc_id(OILS_PRECAT_RECORD);
1771 $mods->title($copy->dummy_title);
1772 $mods->author($copy->dummy_author);
1776 $logger->debug("MODSized the circ title");
1778 return {transaction => $trans, circ => $circ, record => $mods, copy => $copy };
1782 __PACKAGE__->register_method(
1783 method => "hold_request_count",
1784 api_name => "open-ils.actor.user.hold_requests.count",
1787 notes => <<" NOTES");
1788 Returns hold ready/total counts
1790 sub hold_request_count {
1791 my( $self, $client, $login_session, $userid ) = @_;
1793 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1794 $login_session, $userid, 'VIEW_HOLD' );
1795 return $evt if $evt;
1798 my $holds = $apputils->simple_scalar_request(
1800 "open-ils.cstore.direct.action.hold_request.search.atomic",
1803 fulfillment_time => {"=" => undef },
1804 cancel_time => undef,
1809 for my $h (@$holds) {
1810 next unless $h->capture_time and $h->current_copy;
1812 my $copy = $apputils->simple_scalar_request(
1814 "open-ils.cstore.direct.asset.copy.retrieve",
1818 if ($copy and $copy->status == 8) {
1823 return { total => scalar(@$holds), ready => scalar(@ready) };
1827 __PACKAGE__->register_method(
1828 method => "checkedout_count",
1829 api_name => "open-ils.actor.user.checked_out.count__",
1831 notes => <<" NOTES");
1832 Returns a transaction record
1836 sub checkedout_count {
1837 my( $self, $client, $login_session, $userid ) = @_;
1839 my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1840 $login_session, $userid, 'VIEW_CIRCULATIONS' );
1841 return $evt if $evt;
1843 my $circs = $apputils->simple_scalar_request(
1845 "open-ils.cstore.direct.action.circulation.search.atomic",
1846 { usr => $userid, stop_fines => undef }
1847 #{ usr => $userid, checkin_time => {"=" => undef } }
1850 my $parser = DateTime::Format::ISO8601->new;
1853 for my $c (@$circs) {
1854 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1855 my $due = $due_dt->epoch;
1857 if ($due < DateTime->today->epoch) {
1862 return { total => scalar(@$circs), overdue => scalar(@overdue) };
1866 __PACKAGE__->register_method(
1867 method => "checked_out",
1868 api_name => "open-ils.actor.user.checked_out",
1872 Returns a structure of circulations objects sorted by
1873 out, overdue, lost, claims_returned, long_overdue.
1874 A list of IDs are returned of each type.
1875 lost, long_overdue, and claims_returned circ will not
1876 be "finished" (there is an outstanding balance or some
1877 other pending action on the circ).
1879 The .count method also includes a 'total' field which
1880 sums all "open" circs
1884 __PACKAGE__->register_method(
1885 method => "checked_out",
1886 api_name => "open-ils.actor.user.checked_out.count",
1889 signature => q/@see open-ils.actor.user.checked_out/
1893 my( $self, $conn, $auth, $userid ) = @_;
1895 my $e = new_editor(authtoken=>$auth);
1896 return $e->event unless $e->checkauth;
1898 if( $userid ne $e->requestor->id ) {
1899 my $user = $e->retrieve_actor_user($userid) or return $e->event;
1900 unless($e->allowed('VIEW_CIRCULATIONS', $user->home_ou)) {
1902 # see if there is a friend link allowing circ.view perms
1903 my $allowed = OpenILS::Application::Actor::Friends->friend_perm_allowed(
1904 $e, $userid, $e->requestor->id, 'circ.view');
1905 return $e->event unless $allowed;
1909 my $count = $self->api_name =~ /count/;
1910 return _checked_out( $count, $e, $userid );
1914 my( $iscount, $e, $userid ) = @_;
1915 my $meth = 'open-ils.storage.actor.user.checked_out';
1916 $meth = "$meth.count" if $iscount;
1917 return $U->storagereq($meth, $userid);
1921 sub _checked_out_WHAT {
1922 my( $iscount, $e, $userid ) = @_;
1924 my $circs = $e->search_action_circulation(
1925 { usr => $userid, stop_fines => undef });
1927 my $mcircs = $e->search_action_circulation(
1930 checkin_time => undef,
1931 xact_finish => undef,
1935 push( @$circs, @$mcircs );
1937 my $parser = DateTime::Format::ISO8601->new;
1939 # split the circs up into overdue and not-overdue circs
1941 for my $c (@$circs) {
1942 if( $c->due_date ) {
1943 my $due_dt = $parser->parse_datetime( clense_ISO8601( $c->due_date ) );
1944 my $due = $due_dt->epoch;
1945 if ($due < DateTime->today->epoch) {
1946 push @overdue, $c->id;
1955 # grab all of the lost, claims-returned, and longoverdue circs
1956 #my $open = $e->search_action_circulation(
1957 # {usr => $userid, stop_fines => { '!=' => undef }, xact_finish => undef });
1960 # these items have stop_fines, but no xact_finish, so money
1961 # is owed on them and they have not been checked in
1962 my $open = $e->search_action_circulation(
1965 stop_fines => { in => [ qw/LOST CLAIMSRETURNED LONGOVERDUE/ ] },
1966 xact_finish => undef,
1967 checkin_time => undef,
1972 my( @lost, @cr, @lo );
1973 for my $c (@$open) {
1974 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
1975 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
1976 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
1982 total => @$circs + @lost + @cr + @lo,
1983 out => scalar(@out),
1984 overdue => scalar(@overdue),
1985 lost => scalar(@lost),
1986 claims_returned => scalar(@cr),
1987 long_overdue => scalar(@lo)
1993 overdue => \@overdue,
1995 claims_returned => \@cr,
1996 long_overdue => \@lo
2002 __PACKAGE__->register_method(
2003 method => "checked_in_with_fines",
2004 api_name => "open-ils.actor.user.checked_in_with_fines",
2007 signature => q/@see open-ils.actor.user.checked_out/
2009 sub checked_in_with_fines {
2010 my( $self, $conn, $auth, $userid ) = @_;
2012 my $e = new_editor(authtoken=>$auth);
2013 return $e->event unless $e->checkauth;
2015 if( $userid ne $e->requestor->id ) {
2016 return $e->event unless $e->allowed('VIEW_CIRCULATIONS');
2019 # money is owed on these items and they are checked in
2020 my $open = $e->search_action_circulation(
2023 xact_finish => undef,
2024 checkin_time => { "!=" => undef },
2029 my( @lost, @cr, @lo );
2030 for my $c (@$open) {
2031 push( @lost, $c->id ) if $c->stop_fines eq 'LOST';
2032 push( @cr, $c->id ) if $c->stop_fines eq 'CLAIMSRETURNED';
2033 push( @lo, $c->id ) if $c->stop_fines eq 'LONGOVERDUE';
2038 claims_returned => \@cr,
2039 long_overdue => \@lo
2051 __PACKAGE__->register_method(
2052 method => "user_transaction_history",
2053 api_name => "open-ils.actor.user.transactions.history",
2055 notes => <<" NOTES");
2056 Returns a list of billable transactions for a user, optionally by type
2058 __PACKAGE__->register_method(
2059 method => "user_transaction_history",
2060 api_name => "open-ils.actor.user.transactions.history.have_charge",
2062 notes => <<" NOTES");
2063 Returns a list of billable transactions for a user that have an initial charge, optionally by type
2065 __PACKAGE__->register_method(
2066 method => "user_transaction_history",
2067 api_name => "open-ils.actor.user.transactions.history.have_balance",
2070 notes => <<" NOTES");
2071 Returns a list of billable transactions for a user that have a balance, optionally by type
2073 __PACKAGE__->register_method(
2074 method => "user_transaction_history",
2075 api_name => "open-ils.actor.user.transactions.history.still_open",
2077 notes => <<" NOTES");
2078 Returns a list of billable transactions for a user that are not finished
2080 __PACKAGE__->register_method(
2081 method => "user_transaction_history",
2082 api_name => "open-ils.actor.user.transactions.history.have_bill",
2085 notes => <<" NOTES");
2086 Returns a list of billable transactions for a user that has billings
2088 __PACKAGE__->register_method(
2089 method => "user_transaction_history",
2090 api_name => "open-ils.actor.user.transactions.history.ids",
2092 notes => <<" NOTES");
2093 Returns a list of billable transaction ids for a user, optionally by type
2095 __PACKAGE__->register_method(
2096 method => "user_transaction_history",
2097 api_name => "open-ils.actor.user.transactions.history.have_charge.ids",
2099 notes => <<" NOTES");
2100 Returns a list of billable transaction ids for a user that have an initial charge, optionally by type
2102 __PACKAGE__->register_method(
2103 method => "user_transaction_history",
2104 api_name => "open-ils.actor.user.transactions.history.have_balance.ids",
2107 notes => <<" NOTES");
2108 Returns a list of billable transaction ids for a user that have a balance, optionally by type
2110 __PACKAGE__->register_method(
2111 method => "user_transaction_history",
2112 api_name => "open-ils.actor.user.transactions.history.still_open.ids",
2114 notes => <<" NOTES");
2115 Returns a list of billable transaction ids for a user that are not finished
2117 __PACKAGE__->register_method(
2118 method => "user_transaction_history",
2119 api_name => "open-ils.actor.user.transactions.history.have_bill.ids",
2122 notes => <<" NOTES");
2123 Returns a list of billable transaction ids for a user that has billings
2127 sub user_transaction_history {
2128 my( $self, $conn, $auth, $userid, $type ) = @_;
2130 # run inside of a transaction to prevent replication delays
2131 my $e = new_editor(authtoken=>$auth);
2132 return $e->die_event unless $e->checkauth;
2134 if( $e->requestor->id ne $userid ) {
2135 return $e->die_event
2136 unless $e->allowed('VIEW_USER_TRANSACTIONS');
2139 my $api = $self->api_name;
2140 my @xact_finish = (xact_finish => undef ) if ($api =~ /history.still_open$/);
2142 my $mbts = $e->search_money_billable_transaction_summary(
2144 { usr => $userid, @xact_finish },
2145 { order_by => { mbt => 'xact_start DESC' } }
2149 if(defined($type)) {
2150 @$mbts = grep { $_->xact_type eq $type } @$mbts;
2153 if($api =~ /have_balance/o) {
2154 @$mbts = grep { int($_->balance_owed * 100) != 0 } @$mbts;
2157 if($api =~ /have_charge/o) {
2158 @$mbts = grep { defined($_->last_billing_ts) } @$mbts;
2161 if($api =~ /have_bill/o) {
2162 @$mbts = grep { int($_->total_owed * 100) != 0 } @$mbts;
2165 if ($api =~ /\.ids/) {
2166 return [map {$_->id} @$mbts];
2174 __PACKAGE__->register_method(
2175 method => "user_perms",
2176 api_name => "open-ils.actor.permissions.user_perms.retrieve",
2178 notes => <<" NOTES");
2179 Returns a list of permissions
2182 my( $self, $client, $authtoken, $user ) = @_;
2184 my( $staff, $evt ) = $apputils->checkses($authtoken);
2185 return $evt if $evt;
2187 $user ||= $staff->id;
2189 if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
2193 return $apputils->simple_scalar_request(
2195 "open-ils.storage.permission.user_perms.atomic",
2199 __PACKAGE__->register_method(
2200 method => "retrieve_perms",
2201 api_name => "open-ils.actor.permissions.retrieve",
2202 notes => <<" NOTES");
2203 Returns a list of permissions
2205 sub retrieve_perms {
2206 my( $self, $client ) = @_;
2207 return $apputils->simple_scalar_request(
2209 "open-ils.cstore.direct.permission.perm_list.search.atomic",
2210 { id => { '!=' => undef } }
2214 __PACKAGE__->register_method(
2215 method => "retrieve_groups",
2216 api_name => "open-ils.actor.groups.retrieve",
2217 notes => <<" NOTES");
2218 Returns a list of user groupss
2220 sub retrieve_groups {
2221 my( $self, $client ) = @_;
2222 return new_editor()->retrieve_all_permission_grp_tree();
2225 __PACKAGE__->register_method(
2226 method => "retrieve_org_address",
2227 api_name => "open-ils.actor.org_unit.address.retrieve",
2228 notes => <<' NOTES');
2229 Returns an org_unit address by ID
2230 @param An org_address ID
2232 sub retrieve_org_address {
2233 my( $self, $client, $id ) = @_;
2234 return $apputils->simple_scalar_request(
2236 "open-ils.cstore.direct.actor.org_address.retrieve",
2241 __PACKAGE__->register_method(
2242 method => "retrieve_groups_tree",
2243 api_name => "open-ils.actor.groups.tree.retrieve",
2244 notes => <<" NOTES");
2245 Returns a list of user groups
2247 sub retrieve_groups_tree {
2248 my( $self, $client ) = @_;
2249 return new_editor()->search_permission_grp_tree(
2254 flesh_fields => { pgt => ["children"] },
2255 order_by => { pgt => 'name'}
2262 __PACKAGE__->register_method(
2263 method => "add_user_to_groups",
2264 api_name => "open-ils.actor.user.set_groups",
2265 notes => <<" NOTES");
2266 Adds a user to one or more permission groups
2269 sub add_user_to_groups {
2270 my( $self, $client, $authtoken, $userid, $groups ) = @_;
2272 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2273 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
2274 return $evt if $evt;
2276 ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2277 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
2278 return $evt if $evt;
2280 $apputils->simplereq(
2282 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
2284 for my $group (@$groups) {
2285 my $link = Fieldmapper::permission::usr_grp_map->new;
2287 $link->usr($userid);
2289 my $id = $apputils->simplereq(
2291 'open-ils.storage.direct.permission.usr_grp_map.create', $link );
2297 __PACKAGE__->register_method(
2298 method => "get_user_perm_groups",
2299 api_name => "open-ils.actor.user.get_groups",
2300 notes => <<" NOTES");
2301 Retrieve a user's permission groups.
2305 sub get_user_perm_groups {
2306 my( $self, $client, $authtoken, $userid ) = @_;
2308 my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
2309 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
2310 return $evt if $evt;
2312 return $apputils->simplereq(
2314 'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
2318 __PACKAGE__->register_method(
2319 method => "get_user_work_ous",
2320 api_name => "open-ils.actor.user.get_work_ous",
2321 notes => <<" NOTES");
2322 Retrieve a user's work org units.
2324 __PACKAGE__->register_method(
2325 method => "get_user_work_ous",
2326 api_name => "open-ils.actor.user.get_work_ous.ids",
2327 notes => <<" NOTES");
2328 Retrieve a user's work org units.
2332 sub get_user_work_ous {
2333 my( $self, $client, $auth, $userid ) = @_;
2334 my $e = new_editor(authtoken=>$auth);
2335 return $e->event unless $e->checkauth;
2336 $userid ||= $e->requestor->id;
2338 if($e->requestor->id != $userid) {
2339 my $user = $e->retrieve_actor_user($userid)
2340 or return $e->event;
2341 return $e->event unless $e->allowed('ASSIGN_WORK_ORG_UNIT', $user->home_ou);
2344 return $e->search_permission_usr_work_ou_map({usr => $userid})
2345 unless $self->api_name =~ /.ids$/;
2347 # client just wants a list of org IDs
2348 return $U->get_user_work_ou_ids($e, $userid);
2354 __PACKAGE__->register_method (
2355 method => 'register_workstation',
2356 api_name => 'open-ils.actor.workstation.register.override',
2357 signature => q/@see open-ils.actor.workstation.register/);
2359 __PACKAGE__->register_method (
2360 method => 'register_workstation',
2361 api_name => 'open-ils.actor.workstation.register',
2363 Registers a new workstion in the system
2364 @param authtoken The login session key
2365 @param name The name of the workstation id
2366 @param owner The org unit that owns this workstation
2367 @return The workstation id on success, WORKSTATION_NAME_EXISTS
2368 if the name is already in use.
2371 sub register_workstation {
2372 my( $self, $conn, $authtoken, $name, $owner ) = @_;
2374 my $e = new_editor(authtoken=>$authtoken, xact=>1);
2375 return $e->die_event unless $e->checkauth;
2376 return $e->die_event unless $e->allowed('REGISTER_WORKSTATION', $owner);
2377 my $existing = $e->search_actor_workstation({name => $name})->[0];
2381 if( $self->api_name =~ /override/o ) {
2382 # workstation with the given name exists.
2384 if($owner ne $existing->owning_lib) {
2385 # if necessary, update the owning_lib of the workstation
2387 $logger->info("changing owning lib of workstation ".$existing->id.
2388 " from ".$existing->owning_lib." to $owner");
2389 return $e->die_event unless
2390 $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
2392 return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
2394 $existing->owning_lib($owner);
2395 return $e->die_event unless $e->update_actor_workstation($existing);
2401 "attempt to register an existing workstation. returning existing ID");
2404 return $existing->id;
2407 return OpenILS::Event->new('WORKSTATION_NAME_EXISTS')
2411 my $ws = Fieldmapper::actor::workstation->new;
2412 $ws->owning_lib($owner);
2414 $e->create_actor_workstation($ws) or return $e->die_event;
2416 return $ws->id; # note: editor sets the id on the new object for us
2419 __PACKAGE__->register_method (
2420 method => 'workstation_list',
2421 api_name => 'open-ils.actor.workstation.list',
2423 Returns a list of workstations registered at the given location
2424 @param authtoken The login session key
2425 @param ids A list of org_unit.id's for the workstation owners
2428 sub workstation_list {
2429 my( $self, $conn, $authtoken, @orgs ) = @_;
2431 my $e = new_editor(authtoken=>$authtoken);
2432 return $e->event unless $e->checkauth;
2437 unless $e->allowed('REGISTER_WORKSTATION', $o);
2438 $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
2449 __PACKAGE__->register_method (
2450 method => 'fetch_patron_note',
2451 api_name => 'open-ils.actor.note.retrieve.all',
2454 Returns a list of notes for a given user
2455 Requestor must have VIEW_USER permission if pub==false and
2456 @param authtoken The login session key
2457 @param args Hash of params including
2458 patronid : the patron's id
2459 pub : true if retrieving only public notes
2463 sub fetch_patron_note {
2464 my( $self, $conn, $authtoken, $args ) = @_;
2465 my $patronid = $$args{patronid};
2467 my($reqr, $evt) = $U->checkses($authtoken);
2468 return $evt if $evt;
2471 ($patron, $evt) = $U->fetch_user($patronid);
2472 return $evt if $evt;
2475 if( $patronid ne $reqr->id ) {
2476 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2477 return $evt if $evt;
2479 return $U->cstorereq(
2480 'open-ils.cstore.direct.actor.usr_note.search.atomic',
2481 { usr => $patronid, pub => 't' } );
2484 $evt = $U->check_perms($reqr->id, $patron->home_ou, 'VIEW_USER');
2485 return $evt if $evt;
2487 return $U->cstorereq(
2488 'open-ils.cstore.direct.actor.usr_note.search.atomic', { usr => $patronid } );
2491 __PACKAGE__->register_method (
2492 method => 'create_user_note',
2493 api_name => 'open-ils.actor.note.create',
2495 Creates a new note for the given user
2496 @param authtoken The login session key
2497 @param note The note object
2500 sub create_user_note {
2501 my( $self, $conn, $authtoken, $note ) = @_;
2502 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2503 return $e->die_event unless $e->checkauth;
2505 my $user = $e->retrieve_actor_user($note->usr)
2506 or return $e->die_event;
2508 return $e->die_event unless
2509 $e->allowed('UPDATE_USER',$user->home_ou);
2511 $note->creator($e->requestor->id);
2512 $e->create_actor_usr_note($note) or return $e->die_event;
2518 __PACKAGE__->register_method (
2519 method => 'delete_user_note',
2520 api_name => 'open-ils.actor.note.delete',
2522 Deletes a note for the given user
2523 @param authtoken The login session key
2524 @param noteid The note id
2527 sub delete_user_note {
2528 my( $self, $conn, $authtoken, $noteid ) = @_;
2530 my $e = new_editor(xact=>1, authtoken=>$authtoken);
2531 return $e->die_event unless $e->checkauth;
2532 my $note = $e->retrieve_actor_usr_note($noteid)
2533 or return $e->die_event;
2534 my $user = $e->retrieve_actor_user($note->usr)
2535 or return $e->die_event;
2536 return $e->die_event unless
2537 $e->allowed('UPDATE_USER', $user->home_ou);
2539 $e->delete_actor_usr_note($note) or return $e->die_event;
2545 __PACKAGE__->register_method (
2546 method => 'update_user_note',
2547 api_name => 'open-ils.actor.note.update',
2549 @param authtoken The login session key
2550 @param note The note
2554 sub update_user_note {
2555 my( $self, $conn, $auth, $note ) = @_;
2556 my $e = new_editor(authtoken=>$auth, xact=>1);
2557 return $e->event unless $e->checkauth;
2558 my $patron = $e->retrieve_actor_user($note->usr)
2559 or return $e->event;
2560 return $e->event unless
2561 $e->allowed('UPDATE_USER', $patron->home_ou);
2562 $e->update_actor_user_note($note)
2563 or return $e->event;
2571 __PACKAGE__->register_method (
2572 method => 'create_closed_date',
2573 api_name => 'open-ils.actor.org_unit.closed_date.create',
2575 Creates a new closing entry for the given org_unit
2576 @param authtoken The login session key
2577 @param note The closed_date object
2580 sub create_closed_date {
2581 my( $self, $conn, $authtoken, $cd ) = @_;
2583 my( $user, $evt ) = $U->checkses($authtoken);
2584 return $evt if $evt;
2586 $evt = $U->check_perms($user->id, $cd->org_unit, 'CREATE_CLOSEING');
2587 return $evt if $evt;
2589 $logger->activity("user ".$user->id." creating library closing for ".$cd->org_unit);
2591 my $id = $U->storagereq(
2592 'open-ils.storage.direct.actor.org_unit.closed_date.create', $cd );
2593 return $U->DB_UPDATE_FAILED($cd) unless $id;
2598 __PACKAGE__->register_method (
2599 method => 'delete_closed_date',
2600 api_name => 'open-ils.actor.org_unit.closed_date.delete',
2602 Deletes a closing entry for the given org_unit
2603 @param authtoken The login session key
2604 @param noteid The close_date id
2607 sub delete_closed_date {
2608 my( $self, $conn, $authtoken, $cd ) = @_;
2610 my( $user, $evt ) = $U->checkses($authtoken);
2611 return $evt if $evt;
2614 ($cd_obj, $evt) = fetch_closed_date($cd);
2615 return $evt if $evt;
2617 $evt = $U->check_perms($user->id, $cd->org_unit, 'DELETE_CLOSEING');
2618 return $evt if $evt;
2620 $logger->activity("user ".$user->id." deleting library closing for ".$cd->org_unit);
2622 my $stat = $U->storagereq(
2623 'open-ils.storage.direct.actor.org_unit.closed_date.delete', $cd );
2624 return $U->DB_UPDATE_FAILED($cd) unless $stat;
2629 __PACKAGE__->register_method(
2630 method => 'usrname_exists',
2631 api_name => 'open-ils.actor.username.exists',
2633 Returns 1 if the requested username exists, returns 0 otherwise
2637 sub usrname_exists {
2638 my( $self, $conn, $auth, $usrname ) = @_;
2639 my $e = new_editor(authtoken=>$auth);
2640 return $e->event unless $e->checkauth;
2641 my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1});
2642 return $$a[0] if $a and @$a;
2646 __PACKAGE__->register_method(
2647 method => 'barcode_exists',
2648 api_name => 'open-ils.actor.barcode.exists',
2651 Returns 1 if the requested barcode exists, returns 0 otherwise
2655 sub barcode_exists {
2656 my( $self, $conn, $auth, $barcode ) = @_;
2657 my $e = new_editor(authtoken=>$auth);
2658 return $e->event unless $e->checkauth;
2659 my $card = $e->search_actor_card({barcode => $barcode});
2665 #return undef unless @$card;
2666 #return $card->[0]->usr;
2670 __PACKAGE__->register_method(
2671 method => 'retrieve_net_levels',
2672 api_name => 'open-ils.actor.net_access_level.retrieve.all',
2675 sub retrieve_net_levels {
2676 my( $self, $conn, $auth ) = @_;
2677 my $e = new_editor(authtoken=>$auth);
2678 return $e->event unless $e->checkauth;
2679 return $e->retrieve_all_config_net_access_level();
2683 __PACKAGE__->register_method(
2684 method => 'fetch_org_by_shortname',
2685 api_name => 'open-ils.actor.org_unit.retrieve_by_shorname',
2687 sub fetch_org_by_shortname {
2688 my( $self, $conn, $sname ) = @_;
2689 my $e = new_editor();
2690 my $org = $e->search_actor_org_unit({ shortname => uc($sname)})->[0];
2691 return $e->event unless $org;
2696 __PACKAGE__->register_method(
2697 method => 'session_home_lib',
2698 api_name => 'open-ils.actor.session.home_lib',
2701 sub session_home_lib {
2702 my( $self, $conn, $auth ) = @_;
2703 my $e = new_editor(authtoken=>$auth);
2704 return undef unless $e->checkauth;
2705 my $org = $e->retrieve_actor_org_unit($e->requestor->home_ou);
2706 return $org->shortname;
2709 __PACKAGE__->register_method(
2710 method => 'session_safe_token',
2711 api_name => 'open-ils.actor.session.safe_token',
2713 Returns a hashed session ID that is safe for export to the world.
2714 This safe token will expire after 1 hour of non-use.
2715 @param auth Active authentication token
2719 sub session_safe_token {
2720 my( $self, $conn, $auth ) = @_;
2721 my $e = new_editor(authtoken=>$auth);
2722 return undef unless $e->checkauth;
2724 my $safe_token = md5_hex($auth);
2726 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2728 # Add more like the following if needed...
2730 "safe-token-home_lib-shortname-$safe_token",
2731 $e->retrieve_actor_org_unit(
2732 $e->requestor->home_ou
2741 __PACKAGE__->register_method(
2742 method => 'safe_token_home_lib',
2743 api_name => 'open-ils.actor.safe_token.home_lib.shortname',
2745 Returns the home library shortname from the session
2746 asscociated with a safe token from generated by
2747 open-ils.actor.session.safe_token.
2748 @param safe_token Active safe token
2752 sub safe_token_home_lib {
2753 my( $self, $conn, $safe_token ) = @_;
2755 $cache ||= OpenSRF::Utils::Cache->new("global", 0);
2756 return $cache->get_cache( 'safe-token-home_lib-shortname-'. $safe_token );
2761 __PACKAGE__->register_method(
2762 method => 'slim_tree',
2763 api_name => "open-ils.actor.org_tree.slim_hash.retrieve",
2766 my $tree = new_editor()->search_actor_org_unit(
2768 {"parent_ou" => undef },
2771 flesh_fields => { aou => ['children'] },
2772 order_by => { aou => 'name'},
2773 select => { aou => ["id","shortname", "name"]},
2778 return trim_tree($tree);
2784 return undef unless $tree;
2786 code => $tree->shortname,
2787 name => $tree->name,
2789 if( $tree->children and @{$tree->children} ) {
2790 $htree->{children} = [];
2791 for my $c (@{$tree->children}) {
2792 push( @{$htree->{children}}, trim_tree($c) );
2800 __PACKAGE__->register_method(
2801 method => "update_penalties",
2802 api_name => "open-ils.actor.user.penalties.update");
2804 sub update_penalties {
2805 my($self, $conn, $auth, $user_id) = @_;
2806 my $e = new_editor(authtoken=>$auth, xact => 1);
2807 return $e->die_event unless $e->checkauth;
2808 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
2809 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2810 my $evt = OpenILS::Utils::Penalty->calculate_penalties($e, $user_id, $e->requestor->ws_ou);
2811 return $evt if $evt;
2817 __PACKAGE__->register_method(
2818 method => "apply_penalty",
2819 api_name => "open-ils.actor.user.penalty.apply");
2822 my($self, $conn, $auth, $penalty) = @_;
2824 my $e = new_editor(authtoken=>$auth, xact => 1);
2825 return $e->die_event unless $e->checkauth;
2827 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2828 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2830 my $ptype = $e->retrieve_config_standing_penalty($penalty->standing_penalty) or return $e->die_event;
2833 (defined $ptype->org_depth) ?
2834 $U->org_unit_ancestor_at_depth($penalty->org_unit, $ptype->org_depth) :
2837 $penalty->org_unit($ctx_org);
2838 $penalty->staff($e->requestor->id);
2839 $e->create_actor_user_standing_penalty($penalty) or return $e->die_event;
2842 return $penalty->id;
2845 __PACKAGE__->register_method(
2846 method => "remove_penalty",
2847 api_name => "open-ils.actor.user.penalty.remove");
2849 sub remove_penalty {
2850 my($self, $conn, $auth, $penalty) = @_;
2851 my $e = new_editor(authtoken=>$auth, xact => 1);
2852 return $e->die_event unless $e->checkauth;
2853 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2854 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2856 $e->delete_actor_user_standing_penalty($penalty) or return $e->die_event;
2861 __PACKAGE__->register_method(
2862 method => "update_penalty_note",
2863 api_name => "open-ils.actor.user.penalty.note.update");
2865 sub update_penalty_note {
2866 my($self, $conn, $auth, $penalty_ids, $note) = @_;
2867 my $e = new_editor(authtoken=>$auth, xact => 1);
2868 return $e->die_event unless $e->checkauth;
2869 for my $penalty_id (@$penalty_ids) {
2870 my $penalty = $e->search_actor_user_standing_penalty( { id => $penalty_id } )->[0];
2871 if (! $penalty ) { return $e->die_event; }
2872 my $user = $e->retrieve_actor_user($penalty->usr) or return $e->die_event;
2873 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
2875 $penalty->note( $note ); $penalty->ischanged( 1 );
2877 $e->update_actor_user_standing_penalty($penalty) or return $e->die_event;
2883 __PACKAGE__->register_method(
2884 method => "ranged_penalty_thresholds",
2885 api_name => "open-ils.actor.grp_penalty_threshold.ranged.retrieve",
2889 sub ranged_penalty_thresholds {
2890 my($self, $conn, $auth, $context_org) = @_;
2891 my $e = new_editor(authtoken=>$auth);
2892 return $e->event unless $e->checkauth;
2893 return $e->event unless $e->allowed('VIEW_GROUP_PENALTY_THRESHOLD', $context_org);
2894 my $list = $e->search_permission_grp_penalty_threshold([
2895 {org_unit => $U->get_org_ancestors($context_org)},
2896 {order_by => {pgpt => 'id'}}
2898 $conn->respond($_) for @$list;
2904 __PACKAGE__->register_method(
2905 method => "user_retrieve_fleshed_by_id",
2907 api_name => "open-ils.actor.user.fleshed.retrieve",);
2909 sub user_retrieve_fleshed_by_id {
2910 my( $self, $client, $auth, $user_id, $fields ) = @_;
2911 my $e = new_editor(authtoken => $auth);
2912 return $e->event unless $e->checkauth;
2914 if( $e->requestor->id != $user_id ) {
2915 return $e->event unless $e->allowed('VIEW_USER');
2921 "standing_penalties",
2925 "stat_cat_entries" ];
2926 return new_flesh_user($user_id, $fields, $e);
2930 sub new_flesh_user {
2933 my $fields = shift || [];
2936 my $fetch_penalties = 0;
2937 if(grep {$_ eq 'standing_penalties'} @$fields) {
2938 $fields = [grep {$_ ne 'standing_penalties'} @$fields];
2939 $fetch_penalties = 1;
2942 my $user = $e->retrieve_actor_user(
2947 "flesh_fields" => { "au" => $fields }
2950 ) or return $e->event;
2953 if( grep { $_ eq 'addresses' } @$fields ) {
2955 $user->addresses([]) unless @{$user->addresses};
2956 # don't expose "replaced" addresses by default
2957 $user->addresses([grep {$_->id >= 0} @{$user->addresses}]);
2959 if( ref $user->billing_address ) {
2960 unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
2961 push( @{$user->addresses}, $user->billing_address );
2965 if( ref $user->mailing_address ) {
2966 unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
2967 push( @{$user->addresses}, $user->mailing_address );
2972 if($fetch_penalties) {
2973 # grab the user penalties ranged for this location
2974 $user->standing_penalties(
2975 $e->search_actor_user_standing_penalty([
2978 {stop_date => undef},
2979 {stop_date => {'>' => 'now'}}
2981 org_unit => $U->get_org_ancestors($e->requestor->ws_ou)
2984 flesh_fields => {ausp => ['standing_penalty']}
2991 $user->clear_passwd();
2998 __PACKAGE__->register_method(
2999 method => "user_retrieve_parts",
3000 api_name => "open-ils.actor.user.retrieve.parts",);
3002 sub user_retrieve_parts {
3003 my( $self, $client, $auth, $user_id, $fields ) = @_;
3004 my $e = new_editor(authtoken => $auth);
3005 return $e->event unless $e->checkauth;
3006 if( $e->requestor->id != $user_id ) {
3007 return $e->event unless $e->allowed('VIEW_USER');
3010 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3011 push(@resp, $user->$_()) for(@$fields);
3017 __PACKAGE__->register_method(
3018 method => 'user_opt_in_enabled',
3019 api_name => 'open-ils.actor.user.org_unit_opt_in.enabled',
3021 @return 1 if user opt-in is globally enabled, 0 otherwise.
3024 sub user_opt_in_enabled {
3025 my($self, $conn) = @_;
3026 my $sc = OpenSRF::Utils::SettingsClient->new;
3027 return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
3032 __PACKAGE__->register_method(
3033 method => 'user_opt_in_at_org',
3034 api_name => 'open-ils.actor.user.org_unit_opt_in.check',
3036 @param $auth The auth token
3037 @param user_id The ID of the user to test
3038 @return 1 if the user has opted in at the specified org,
3039 event on error, and 0 otherwise. /);
3040 sub user_opt_in_at_org {
3041 my($self, $conn, $auth, $user_id) = @_;
3043 # see if we even need to enforce the opt-in value
3044 return 1 unless user_opt_in_enabled($self);
3046 my $e = new_editor(authtoken => $auth);
3047 return $e->event unless $e->checkauth;
3048 my $org_id = $e->requestor->ws_ou;
3050 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3051 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3053 # user is automatically opted-in at the home org
3054 return 1 if $user->home_ou eq $org_id;
3056 my $vals = $e->search_actor_usr_org_unit_opt_in(
3057 {org_unit=>$org_id, usr=>$user_id},{idlist=>1});
3063 __PACKAGE__->register_method(
3064 method => 'create_user_opt_in_at_org',
3065 api_name => 'open-ils.actor.user.org_unit_opt_in.create',
3067 @param $auth The auth token
3068 @param user_id The ID of the user to test
3069 @return The ID of the newly created object, event on error./);
3071 sub create_user_opt_in_at_org {
3072 my($self, $conn, $auth, $user_id) = @_;
3074 my $e = new_editor(authtoken => $auth, xact=>1);
3075 return $e->die_event unless $e->checkauth;
3076 my $org_id = $e->requestor->ws_ou;
3078 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3079 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3081 my $opt_in = Fieldmapper::actor::usr_org_unit_opt_in->new;
3083 $opt_in->org_unit($org_id);
3084 $opt_in->usr($user_id);
3085 $opt_in->staff($e->requestor->id);
3086 $opt_in->opt_in_ts('now');
3087 $opt_in->opt_in_ws($e->requestor->wsid);
3089 $opt_in = $e->create_actor_usr_org_unit_opt_in($opt_in)
3090 or return $e->die_event;
3098 __PACKAGE__->register_method (
3099 method => 'retrieve_org_hours',
3100 api_name => 'open-ils.actor.org_unit.hours_of_operation.retrieve',
3102 Returns the hours of operation for a specified org unit
3103 @param authtoken The login session key
3104 @param org_id The org_unit ID
3108 sub retrieve_org_hours {
3109 my($self, $conn, $auth, $org_id) = @_;
3110 my $e = new_editor(authtoken => $auth);
3111 return $e->die_event unless $e->checkauth;
3112 $org_id ||= $e->requestor->ws_ou;
3113 return $e->retrieve_actor_org_unit_hours_of_operation($org_id);
3117 __PACKAGE__->register_method (
3118 method => 'verify_user_password',
3119 api_name => 'open-ils.actor.verify_user_password',
3121 Given a barcode or username and the MD5 encoded password,
3122 returns 1 if the password is correct. Returns 0 otherwise.
3126 sub verify_user_password {
3127 my($self, $conn, $auth, $barcode, $username, $password) = @_;
3128 my $e = new_editor(authtoken => $auth);
3129 return $e->die_event unless $e->checkauth;
3131 my $user_by_barcode;
3132 my $user_by_username;
3134 my $card = $e->search_actor_card([
3135 {barcode => $barcode},
3136 {flesh => 1, flesh_fields => {ac => ['usr']}}])->[0] or return 0;
3137 $user_by_barcode = $card->usr;
3138 $user = $user_by_barcode;
3141 $user_by_username = $e->search_actor_user({usrname => $username})->[0] or return 0;
3142 $user = $user_by_username;
3144 return 0 if (!$user);
3145 return 0 if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
3146 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3147 return 1 if $user->passwd eq $password;
3151 __PACKAGE__->register_method (
3152 method => 'retrieve_usr_id_via_barcode_or_usrname',
3153 api_name => "open-ils.actor.user.retrieve_id_by_barcode_or_username",
3155 Given a barcode or username returns the id for the user or
3160 sub retrieve_usr_id_via_barcode_or_usrname {
3161 my($self, $conn, $auth, $barcode, $username) = @_;
3162 my $e = new_editor(authtoken => $auth);
3163 return $e->die_event unless $e->checkauth;
3164 my $id_as_barcode= OpenSRF::Utils::SettingsClient->new->config_value(apps => 'open-ils.actor' => app_settings => 'id_as_barcode');
3166 my $user_by_barcode;
3167 my $user_by_username;
3168 $logger->info("$id_as_barcode is the ID as BARCODE");
3170 my $card = $e->search_actor_card([
3171 {barcode => $barcode},
3172 {flesh => 1, flesh_fields => {ac => ['usr']}}])->[0];
3173 if ($id_as_barcode =~ /^t/i) {
3175 $user = $e->retrieve_actor_user($barcode);
3176 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if(!$user);
3178 $user_by_barcode = $card->usr;
3179 $user = $user_by_barcode;
3182 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if(!$card);
3183 $user_by_barcode = $card->usr;
3184 $user = $user_by_barcode;
3189 $user_by_username = $e->search_actor_user({usrname => $username})->[0] or return OpenILS::Event->new( 'ACTOR_USR_NOT_FOUND' );
3191 $user = $user_by_username;
3193 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if (!$user);
3194 return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
3195 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3200 __PACKAGE__->register_method (
3201 method => 'merge_users',
3202 api_name => 'open-ils.actor.user.merge',
3205 Given a list of source users and destination user, transfer all data from the source
3206 to the dest user and delete the source user. All user related data is
3207 transferred, including circulations, holds, bookbags, etc.
3213 my($self, $conn, $auth, $master_id, $user_ids, $options) = @_;
3214 my $e = new_editor(xact => 1, authtoken => $auth);
3215 return $e->die_event unless $e->checkauth;
3217 # disallow the merge if any subordinate accounts are in collections
3218 my $colls = $e->search_money_collections_tracker({usr => $user_ids}, {idlist => 1});
3219 return OpenILS::Event->new('MERGED_USER_IN_COLLECTIONS', payload => $user_ids) if @$colls;
3221 my $master_user = $e->retrieve_actor_user($master_id) or return $e->die_event;
3222 my $del_addrs = ($U->ou_ancestor_setting_value(
3223 $master_user->home_ou, 'circ.user_merge.delete_addresses', $e)) ? 't' : 'f';
3224 my $del_cards = ($U->ou_ancestor_setting_value(
3225 $master_user->home_ou, 'circ.user_merge.delete_cards', $e)) ? 't' : 'f';
3226 my $deactivate_cards = ($U->ou_ancestor_setting_value(
3227 $master_user->home_ou, 'circ.user_merge.deactivate_cards', $e)) ? 't' : 'f';
3229 for my $src_id (@$user_ids) {
3230 my $src_user = $e->retrieve_actor_user($src_id) or return $e->die_event;
3232 return $e->die_event unless $e->allowed('MERGE_USERS', $src_user->home_ou);
3233 if($src_user->home_ou ne $master_user->home_ou) {
3234 return $e->die_event unless $e->allowed('MERGE_USERS', $master_user->home_ou);
3237 return $e->die_event unless
3238 $e->json_query({from => [
3253 __PACKAGE__->register_method (
3254 method => 'approve_user_address',
3255 api_name => 'open-ils.actor.user.pending_address.approve',
3262 sub approve_user_address {
3263 my($self, $conn, $auth, $addr) = @_;
3264 my $e = new_editor(xact => 1, authtoken => $auth);
3265 return $e->die_event unless $e->checkauth;
3267 # if the caller passes an address object, assume they want to
3268 # update it first before approving it
3269 $e->update_actor_user_address($addr) or return $e->die_event;
3271 $addr = $e->retrieve_actor_user_address($addr) or return $e->die_event;
3273 my $user = $e->retrieve_actor_user($addr->usr);
3274 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3275 my $result = $e->json_query({from => ['actor.approve_pending_address', $addr->id]})->[0]
3276 or return $e->die_event;
3278 return [values %$result]->[0];
3282 __PACKAGE__->register_method (
3283 method => 'retrieve_friends',
3284 api_name => 'open-ils.actor.friends.retrieve',
3287 returns { confirmed: [], pending_out: [], pending_in: []}
3288 pending_out are users I'm requesting friendship with
3289 pending_in are users requesting friendship with me
3294 sub retrieve_friends {
3295 my($self, $conn, $auth, $user_id, $options) = @_;
3296 my $e = new_editor(authtoken => $auth);
3297 return $e->event unless $e->checkauth;
3298 $user_id ||= $e->requestor->id;
3300 if($user_id != $e->requestor->id) {
3301 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3302 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3305 return OpenILS::Application::Actor::Friends->retrieve_friends(
3306 $e, $user_id, $options);
3311 __PACKAGE__->register_method (
3312 method => 'apply_friend_perms',
3313 api_name => 'open-ils.actor.friends.perms.apply',
3319 sub apply_friend_perms {
3320 my($self, $conn, $auth, $user_id, $delegate_id, @perms) = @_;
3321 my $e = new_editor(authtoken => $auth, xact => 1);
3322 return $e->event unless $e->checkauth;
3324 if($user_id != $e->requestor->id) {
3325 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3326 return $e->die_event unless $e->allowed('VIEW_USER', $user->home_ou);
3329 for my $perm (@perms) {
3331 OpenILS::Application::Actor::Friends->apply_friend_perm(
3332 $e, $user_id, $delegate_id, $perm);
3333 return $evt if $evt;
3341 __PACKAGE__->register_method (
3342 method => 'update_user_pending_address',
3343 api_name => 'open-ils.actor.user.address.pending.cud'
3346 sub update_user_pending_address {
3347 my($self, $conn, $auth, $addr) = @_;
3348 my $e = new_editor(authtoken => $auth, xact => 1);
3349 return $e->event unless $e->checkauth;
3351 if($addr->usr != $e->requestor->id) {
3352 my $user = $e->retrieve_actor_user($addr->usr) or return $e->die_event;
3353 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3357 $e->create_actor_user_address($addr) or return $e->die_event;
3358 } elsif($addr->isdeleted) {
3359 $e->delete_actor_user_address($addr) or return $e->die_event;
3361 $e->update_actor_user_address($addr) or return $e->die_event;
3369 __PACKAGE__->register_method (
3370 method => 'user_events',
3371 api_name => 'open-ils.actor.user.events.circ',
3374 __PACKAGE__->register_method (
3375 method => 'user_events',
3376 api_name => 'open-ils.actor.user.events.ahr',
3381 my($self, $conn, $auth, $user_id, $filters) = @_;
3382 my $e = new_editor(authtoken => $auth);
3383 return $e->event unless $e->checkauth;
3385 (my $obj_type = $self->api_name) =~ s/.*\.([a-z]+)$/$1/;
3386 my $user_field = 'usr';
3389 $filters->{target} = {
3390 select => { $obj_type => ['id'] },
3392 where => {usr => $user_id}
3395 my $user = $e->retrieve_actor_user($user_id) or return $e->event;
3396 if($e->requestor->id != $user_id) {
3397 return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
3400 my $ses = OpenSRF::AppSession->create('open-ils.trigger');
3401 my $req = $ses->request('open-ils.trigger.events_by_target',
3402 $obj_type, $filters, {atevdef => ['reactor', 'validator']}, 2);
3404 while(my $resp = $req->recv) {
3405 my $val = $resp->content;
3406 my $tgt = $val->target;
3408 if($obj_type eq 'circ') {
3409 $tgt->target_copy($e->retrieve_asset_copy($tgt->target_copy));
3411 } elsif($obj_type eq 'ahr') {
3412 $tgt->current_copy($e->retrieve_asset_copy($tgt->current_copy))
3413 if $tgt->current_copy;
3416 $conn->respond($val) if $val;
3423 __PACKAGE__->register_method (
3424 method => 'update_events',
3425 api_name => 'open-ils.actor.user.event.cancel.batch',
3428 __PACKAGE__->register_method (
3429 method => 'update_events',
3430 api_name => 'open-ils.actor.user.event.reset.batch',
3435 my($self, $conn, $auth, $event_ids) = @_;
3436 my $e = new_editor(xact => 1, authtoken => $auth);
3437 return $e->die_event unless $e->checkauth;
3440 for my $id (@$event_ids) {
3442 # do a little dance to determine what user we are ultimately affecting
3443 my $event = $e->retrieve_action_trigger_event([
3446 flesh_fields => {atev => ['event_def'], atevdef => ['hook']}
3448 ]) or return $e->die_event;
3451 if($event->event_def->hook->core_type eq 'circ') {
3452 $user_id = $e->retrieve_action_circulation($event->target)->usr;
3453 } elsif($event->event_def->hook->core_type eq 'ahr') {
3454 $user_id = $e->retrieve_action_hold_request($event->target)->usr;
3459 my $user = $e->retrieve_actor_user($user_id);
3460 return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
3462 if($self->api_name =~ /cancel/) {
3463 $event->state('invalid');
3464 } elsif($self->api_name =~ /reset/) {
3465 $event->clear_start_time;
3466 $event->clear_update_time;
3467 $event->state('pending');
3470 $e->update_action_trigger_event($event) or return $e->die_event;
3471 $conn->respond({maximum => scalar(@$event_ids), progress => $x++});
3475 return {complete => 1};
3479 __PACKAGE__->register_method (
3480 method => 'really_delete_user',
3481 api_name => 'open-ils.actor.user.delete',
3483 It anonymizes all personally identifiable information in actor.usr. By calling actor.usr_purge_data()
3484 it also purges related data from other tables, sometimes by transferring it to a designated destination user.
3485 The usrname field (along with first_given_name and family_name) is updated to id '-PURGED-' now().
3486 dest_usr_id is only required when deleting a user that performs staff functions.
3490 sub really_delete_user {
3491 my($self, $conn, $auth, $user_id, $dest_user_id) = @_;
3492 my $e = new_editor(authtoken => $auth, xact => 1);
3493 return $e->die_event unless $e->checkauth;
3494 my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
3495 return $e->die_event unless $e->allowed('DELETE_USER', $user->home_ou);
3496 my $stat = $e->json_query(
3497 {from => ['actor.usr_delete', $user_id, $dest_user_id]})->[0]
3498 or return $e->die_event;