]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Actor.pm
updates for the perm editor -- FM dance required
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Actor.pm
1 package OpenILS::Application::Actor;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
4 use Data::Dumper;
5 use OpenILS::Event;
6
7 use Digest::MD5 qw(md5_hex);
8
9 use OpenSRF::EX qw(:try);
10 use OpenILS::EX;
11 use OpenILS::Perm;
12
13 use OpenILS::Application::AppUtils;
14 use OpenILS::Utils::Fieldmapper;
15 use OpenILS::Application::Search::Actor;
16 use OpenILS::Utils::ModsParser;
17 use OpenSRF::Utils::Logger;
18 my $logger = "OpenSRF::Utils::Logger";
19
20 use OpenSRF::Utils::Cache;
21
22
23 use OpenILS::Application::Actor::Container;
24 sub initialize {
25         OpenILS::Application::Actor::Container->initialize();
26 }
27
28 my $apputils = "OpenILS::Application::AppUtils";
29
30 sub _d { warn "Patron:\n" . Dumper(shift()); }
31
32 my $cache_client;
33
34
35 my $set_user_settings;
36 my $set_ou_settings;
37
38 __PACKAGE__->register_method(
39         method  => "set_user_settings",
40         api_name        => "open-ils.actor.patron.settings.update",
41 );
42 sub set_user_settings {
43         my( $self, $client, $user_session, $uid, $settings ) = @_;
44         
45         $logger->debug("Setting user settings: $user_session, $uid, " . Dumper($settings));
46
47         my( $staff, $user, $evt ) = 
48                 $apputils->checkses_requestor( $user_session, $uid, 'UPDATE_USER' );    
49         return $evt if $evt;
50         
51
52         my ($params) = map { 
53                 [{ usr => $user->id, name => $_}, {value => $$settings{$_}}] } keys %$settings;
54
55         $logger->activity("User " . $staff->id . " updating user $uid settings with: " . Dumper($params));
56
57         return $apputils->simplereq(
58                 'open-ils.storage',
59                 'open-ils.storage.direct.actor.user_setting.batch.merge', $params );
60                 
61 }
62
63
64
65 __PACKAGE__->register_method(
66         method  => "set_ou_settings",
67         api_name        => "open-ils.actor.org_unit.settings.update",
68 );
69 sub set_ou_settings {
70         my( $self, $client, $user_session, $ouid, $settings ) = @_;
71         
72         my( $staff, $evt ) = $apputils->checkses( $user_session );
73         return $evt if $evt;
74         $evt = $apputils->check_perms( $staff->id, $ouid, 'UPDATE_ORG_UNIT' );
75         return $evt if $evt;
76
77
78         my ($params) = 
79                 map { [{ org_unit => $ouid, name => $_}, {value => $$settings{$_}}] } keys %$settings;
80
81         $logger->activity("Updating org unit [$ouid] settings with: " . Dumper($params));
82
83         return $apputils->simplereq(
84                 'open-ils.storage',
85                 'open-ils.storage.direct.actor.org_unit_setting.merge', @$params );
86 }
87
88
89 my $fetch_user_settings;
90 my $fetch_ou_settings;
91
92 __PACKAGE__->register_method(
93         method  => "user_settings",
94         api_name        => "open-ils.actor.patron.settings.retrieve",
95 );
96 sub user_settings {
97         my( $self, $client, $user_session, $uid ) = @_;
98         
99         my( $staff, $user, $evt ) = 
100                 $apputils->checkses_requestor( $user_session, $uid, 'VIEW_USER' );
101         return $evt if $evt;
102
103         $logger->debug("User " . $staff->id . " fetching user $uid\n");
104         my $s = $apputils->simplereq(
105                 'open-ils.storage',
106                 'open-ils.storage.direct.actor.user_setting.search.usr.atomic',$uid );
107
108         return { map { ($_->name,$_->value) } @$s };
109 }
110
111
112
113 __PACKAGE__->register_method(
114         method  => "ou_settings",
115         api_name        => "open-ils.actor.org_unit.settings.retrieve",
116 );
117 sub ou_settings {
118         my( $self, $client, $ouid ) = @_;
119         
120         my $s = $apputils->simplereq(
121                 'open-ils.storage',
122                 'open-ils.storage.direct.actor.org_unit_setting.search.org_unit.atomic', $ouid);
123
124         return { map { ($_->name,$_->value) } @$s };
125 }
126
127
128
129 __PACKAGE__->register_method(
130         method  => "update_patron",
131         api_name        => "open-ils.actor.patron.update",);
132
133 sub update_patron {
134         my( $self, $client, $user_session, $patron ) = @_;
135
136         my $session = $apputils->start_db_session();
137         my $err = undef;
138
139         warn $user_session . " " . $patron . "\n";
140         _d($patron);
141
142         my $user_obj = 
143                 OpenILS::Application::AppUtils->check_user_session( 
144                                 $user_session ); #throws EX on error
145
146         # XXX does this user have permission to add/create users.  Granularity?
147         # $new_patron is the patron in progress.  $patron is the original patron
148         # passed in with the method.  new_patron will change as the components
149         # of patron are added/updated.
150
151         my $new_patron;
152
153         if(ref($patron->card)) { $patron->card( $patron->card->id ); }
154         if(ref($patron->billing_address)) { $patron->billing_address( $patron->billing_address->id ); }
155         if(ref($patron->mailing_address)) { $patron->mailing_address( $patron->mailing_address->id ); }
156
157         # create/update the patron first so we can use his id
158         if($patron->isnew()) {
159
160                 $new_patron = _add_patron($session, _clone_patron($patron), $user_obj);
161
162                 if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
163                         UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
164                         $client->respond_complete($new_patron->ex);
165                         return undef;
166                 }
167
168         } else { $new_patron = $patron; }
169
170         $new_patron = _add_update_addresses($session, $patron, $new_patron, $user_obj);
171
172         if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
173                 UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
174                 $client->respond_complete($new_patron->ex);
175                 return undef;
176         }
177
178         $new_patron = _add_update_cards($session, $patron, $new_patron, $user_obj);
179
180         if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
181                 UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
182                 $client->respond_complete($new_patron->ex);
183                 return undef;
184         }
185
186         $new_patron = _add_survey_responses($session, $patron, $new_patron, $user_obj);
187         if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
188                 UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
189                 $client->respond_complete($new_patron->ex);
190                 return undef;
191         }
192
193
194         # re-update the patron if anything has happened to him during this process
195         if($new_patron->ischanged()) {
196                 $new_patron = _update_patron($session, $new_patron, $user_obj);
197
198                 if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
199                         UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
200                         $client->respond_complete($new_patron->ex);
201                         return undef;
202                 }
203         }
204
205         $session = OpenSRF::AppSession->create("open-ils.storage");
206         $new_patron     = _create_stat_maps($session, $user_session, $patron, $new_patron, $user_obj);
207         if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
208                 UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
209                 $client->respond_complete($new_patron->ex);
210                 return undef;
211         }
212
213         $new_patron     = _create_perm_maps($session, $user_session, $patron, $new_patron, $user_obj);
214         if(UNIVERSAL::isa($new_patron, "OpenILS::EX") || 
215                 UNIVERSAL::isa($new_patron, "OpenILS::Perm")) {
216                 $client->respond_complete($new_patron->ex);
217                 return undef;
218         }
219
220         $apputils->commit_db_session($session);
221
222         warn "Patron Update/Create complete\n";
223         return flesh_user($new_patron->id());
224 }
225
226
227
228
229 __PACKAGE__->register_method(
230         method  => "user_retrieve_fleshed_by_id",
231         api_name        => "open-ils.actor.user.fleshed.retrieve",);
232
233 sub user_retrieve_fleshed_by_id {
234         my( $self, $client, $user_session, $user_id ) = @_;
235
236         my( $requestor, $target, $evt ) = $apputils->
237                 checkses_requestor( $user_session, $user_id, 'VIEW_USER' );
238         return $evt if $evt;
239
240         return flesh_user($user_id);
241 }
242
243
244 sub flesh_user {
245         my $id = shift;
246         my $session = shift;
247
248         my $kill = 0;
249
250         if(!$session) {
251                 $session = OpenSRF::AppSession->create("open-ils.storage");
252                 $kill = 1;
253         }
254
255         # grab the user with the given id 
256         my $ureq = $session->request(
257                         "open-ils.storage.direct.actor.user.retrieve", $id);
258         my $user = $ureq->gather(1);
259
260         if(!$user) { return undef; }
261
262         # grab the cards
263         my $cards_req = $session->request(
264                         "open-ils.storage.direct.actor.card.search.usr.atomic",
265                         $user->id() );
266         $user->cards( $cards_req->gather(1) );
267
268         for my $c(@{$user->cards}) {
269                 if($c->id == $user->card || $c->id eq $user->card ) {
270                         warn "Setting my card to " . $c->id . "\n";
271                         $user->card($c);
272                 }
273         }
274
275         my $add_req = $session->request(
276                         "open-ils.storage.direct.actor.user_address.search.usr.atomic",
277                         $user->id() );
278         $user->addresses( $add_req->gather(1) );
279
280         for my $c(@{$user->addresses}) {
281                 if($c->id eq $user->billing_address ) { $user->billing_address($c); }
282                 if($c->id eq $user->mailing_address ) { $user->mailing_address($c); }
283         }
284
285         my $stat_req = $session->request(
286                 "open-ils.storage.direct.actor.stat_cat_entry_user_map.search.target_usr.atomic",
287                 $user->id() );
288         $user->stat_cat_entries($stat_req->gather(1));
289
290         if($kill) { $session->disconnect(); }
291         $user->clear_passwd();
292
293         return $user;
294 }
295
296
297 # clone and clear stuff that would break the database
298 sub _clone_patron {
299         my $patron = shift;
300
301         my $new_patron = $patron->clone;
302
303         # Using the Fieldmapper clone method
304         #my $new_patron = Fieldmapper::actor::user->new();
305
306         #my $fmap = $Fieldmapper::fieldmap;
307         #no strict; # shallow clone, may be useful in the fieldmapper
308         #for my $field 
309         #       (keys %{$fmap->{"Fieldmapper::actor::user"}->{'fields'}}) {
310         #               $new_patron->$field( $patron->$field() );
311         #}
312         #use strict;
313
314         # clear these
315         $new_patron->clear_billing_address();
316         $new_patron->clear_mailing_address();
317         $new_patron->clear_addresses();
318         $new_patron->clear_card();
319         $new_patron->clear_cards();
320         $new_patron->clear_id();
321         $new_patron->clear_isnew();
322         $new_patron->clear_ischanged();
323         $new_patron->clear_isdeleted();
324         $new_patron->clear_stat_cat_entries();
325
326         return $new_patron;
327 }
328
329
330 sub _add_patron {
331         my $session             = shift;
332         my $patron              = shift;
333         my $user_obj    = shift;
334
335
336         if($apputils->check_user_perms(
337                                 $user_obj->id, $user_obj->home_ou, "CREATE_USER")) {
338                 return OpenILS::Perm->new("CREATE_USER");
339         }
340
341         warn "Creating new patron\n";
342         _d($patron);
343
344         my $req = $session->request(
345                 "open-ils.storage.direct.actor.user.create",$patron);
346         my $id = $req->gather(1);
347         if(!$id) { 
348                 return OpenILS::EX->new("DUPLICATE_USER_USERNAME");
349         }
350
351         # retrieve the patron from the db to collect defaults
352         my $ureq = $session->request(
353                         "open-ils.storage.direct.actor.user.retrieve",
354                         $id);
355
356         warn "Created new patron with id $id\n";
357
358         return $ureq->gather(1);
359 }
360
361
362 sub _update_patron {
363         my( $session, $patron, $user_obj) = @_;
364
365
366         if($patron->id ne $user_obj->id) {
367                 if($apputils->check_user_perms(
368                                         $user_obj->id, $user_obj->home_ou, "UPDATE_USER")) {
369                         return OpenILS::Perm->new("UPDATE_USER");
370                 }
371         }
372
373         warn "updating patron " . Dumper($patron) . "\n";
374
375         my $req = $session->request(
376                 "open-ils.storage.direct.actor.user.update",$patron );
377         my $status = $req->gather(1);
378         if(!defined($status)) { 
379                 throw OpenSRF::EX::ERROR 
380                         ("Unknown error updating patron"); 
381         }
382         return $patron;
383 }
384
385
386 sub _add_update_addresses {
387         my $session = shift;
388         my $patron = shift;
389         my $new_patron = shift;
390
391         my $current_id; # id of the address before creation
392
393         for my $address (@{$patron->addresses()}) {
394
395                 $address->usr($new_patron->id());
396
397                 if(ref($address) and $address->isnew()) {
398                         warn "Adding new address at street " . $address->street1() . "\n";
399
400                         $current_id = $address->id();
401                         $address = _add_address($session,$address);
402
403                         if( $patron->billing_address() and 
404                                         $patron->billing_address() == $current_id ) {
405                                 $new_patron->billing_address($address->id());
406                                 $new_patron->ischanged(1);
407                         }
408
409                         if( $patron->mailing_address() and
410                                         $patron->mailing_address() == $current_id ) {
411                                 $new_patron->mailing_address($address->id());
412                                 $new_patron->ischanged(1);
413                         }
414
415                 } elsif( ref($address) and $address->ischanged() ) {
416                         warn "Updating address at street " . $address->street1();
417                         $address->usr($new_patron->id());
418                         _update_address($session,$address);
419
420                 } elsif( ref($address) and $address->isdeleted() ) {
421                         warn "Deleting address at street " . $address->street1();
422
423                         if( $address->id() == $new_patron->mailing_address() ) {
424                                 $new_patron->clear_mailing_address();
425                                 _update_patron($session, $new_patron);
426                         }
427
428                         if( $address->id() == $new_patron->billing_address() ) {
429                                 $new_patron->clear_billing_address();
430                                 _update_patron($session, $new_patron);
431                         }
432
433                         _delete_address($session,$address);
434                 }
435         }
436
437         return $new_patron;
438 }
439
440
441 # adds an address to the db and returns the address with new id
442 sub _add_address {
443         my($session, $address) = @_;
444         $address->clear_id();
445
446         use Data::Dumper;
447         warn "Adding Address:\n";
448         warn Dumper($address);
449
450         # put the address into the database
451         my $req = $session->request(
452                 "open-ils.storage.direct.actor.user_address.create",
453                 $address );
454
455         #update the id
456         my $id = $req->gather(1);
457         if(!$id) { 
458                 throw OpenSRF::EX::ERROR 
459                         ("Unable to create new user address"); 
460         }
461
462         warn "Created address with id $id\n";
463
464         # update all the necessary id's
465         $address->id( $id );
466         return $address;
467 }
468
469
470 sub _update_address {
471         my( $session, $address ) = @_;
472         my $req = $session->request(
473                 "open-ils.storage.direct.actor.user_address.update",
474                 $address );
475         my $status = $req->gather(1);
476         if(!defined($status)) { 
477                 throw OpenSRF::EX::ERROR 
478                         ("Unknown error updating address"); 
479         }
480         return $address;
481 }
482
483
484
485 sub _add_update_cards {
486
487         my $session = shift;
488         my $patron = shift;
489         my $new_patron = shift;
490
491         my $virtual_id; #id of the card before creation
492         for my $card (@{$patron->cards()}) {
493
494                 $card->usr($new_patron->id());
495
496                 if(ref($card) and $card->isnew()) {
497
498                         $virtual_id = $card->id();
499                         $card = _add_card($session,$card);
500                         if(UNIVERSAL::isa($card,"OpenILS::EX")) {
501                                 return $card;
502                         }
503
504                         #if(ref($patron->card)) { $patron->card($patron->card->id); }
505                         if($patron->card() == $virtual_id) {
506                                 $new_patron->card($card->id());
507                                 $new_patron->ischanged(1);
508                         }
509
510                 } elsif( ref($card) and $card->ischanged() ) {
511                         $card->usr($new_patron->id());
512                         _update_card($session, $card);
513                 }
514         }
515         return $new_patron;
516 }
517
518
519 # adds an card to the db and returns the card with new id
520 sub _add_card {
521         my( $session, $card ) = @_;
522         $card->clear_id();
523
524         warn "Adding card with barcode " . $card->barcode() . "\n";
525         my $req = $session->request(
526                 "open-ils.storage.direct.actor.card.create",
527                 $card );
528
529         my $id = $req->gather(1);
530         if(!$id) { 
531                 return OpenILS::EX->new("DUPLICATE_INVALID_USER_BARCODE");
532         }
533
534         $card->id($id);
535         warn "Created patron card with id $id\n";
536         return $card;
537 }
538
539
540 sub _update_card {
541         my( $session, $card ) = @_;
542         warn Dumper $card;
543
544         my $req = $session->request(
545                 "open-ils.storage.direct.actor.card.update",
546                 $card );
547         my $status = $req->gather(1);
548         if(!defined($status)) { 
549                 throw OpenSRF::EX::ERROR 
550                         ("Unknown error updating card"); 
551         }
552         return $card;
553 }
554
555
556
557
558 sub _delete_address {
559         my( $session, $address ) = @_;
560
561         warn "Deleting address " . $address->street1() . "\n";
562
563         my $req = $session->request(
564                 "open-ils.storage.direct.actor.user_address.delete",
565                 $address );
566         my $status = $req->gather(1);
567         if(!defined($status)) { 
568                 throw OpenSRF::EX::ERROR 
569                         ("Unknown error updating address"); 
570         }
571         warn "Delete address status is $status\n";
572 }
573
574
575
576 sub _add_survey_responses {
577         my ($session, $patron, $new_patron) = @_;
578
579         warn "updating responses for user " . $new_patron->id . "\n";
580
581         my $responses = $patron->survey_responses;
582
583         if($responses) {
584
585                 for my $resp( @$responses ) {
586                         $resp->usr($new_patron->id);
587                 }
588
589                 my $status = $apputils->simple_scalar_request(
590                         "open-ils.circ", 
591                         "open-ils.circ.survey.submit.user_id",
592                         $responses );
593
594         }
595
596         return $new_patron;
597 }
598
599
600 sub _create_stat_maps {
601
602         my($session, $user_session, $patron, $new_patron) = @_;
603
604         my $maps = $patron->stat_cat_entries();
605
606         for my $map (@$maps) {
607
608                 next unless($map->isnew() || $map->ischanged());
609
610                 my $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.update";
611                 if($map->isnew()) {
612                         $method = "open-ils.storage.direct.actor.stat_cat_entry_user_map.create";
613                         $map->clear_id;
614                 }
615
616                 $map->target_usr($new_patron->id);
617
618                 warn "Updating stat entry with method $method and session $user_session and map $map\n";
619
620                 my $req = $session->request($method, $map);
621                 my $status = $req->gather(1);
622
623                 warn "Updated\n";
624
625                 if(!$status) {
626                         throw OpenSRF::EX::ERROR 
627                                 ("Error updating stat map with method $method");        
628                 }
629
630         }
631
632         return $new_patron;
633 }
634
635 sub _create_perm_maps {
636
637         my($session, $user_session, $patron, $new_patron) = @_;
638
639         my $maps = $patron->permissions;
640
641         for my $map (@$maps) {
642
643                 my $method = "open-ils.storage.direct.permission.usr_perm_map.update";
644                 if ($map->isdeleted()) {
645                         $method = "open-ils.storage.direct.permission.usr_perm_map.delete";
646                 } elsif ($map->isnew()) {
647                         $method = "open-ils.storage.direct.permission.usr_perm_map.create";
648                         $map->clear_id;
649                 }
650
651
652                 $map->usr($new_patron->id);
653
654                 warn( "Updating permissions with method $method and session $user_session and map $map" );
655                 $logger->debug( "Updating permissions with method $method and session $user_session and map $map" );
656
657                 my $req = $session->request($method, $map);
658                 my $status = $req->gather(1);
659
660                 warn "Updated\n";
661
662                 if(!$status) {
663                         throw OpenSRF::EX::ERROR 
664                                 ("Error updating permission map with method $method");  
665                 }
666
667         }
668
669         return $new_patron;
670 }
671
672
673
674 __PACKAGE__->register_method(
675         method  => "search_username",
676         api_name        => "open-ils.actor.user.search.username",
677 );
678
679 sub search_username {
680         my($self, $client, $username) = @_;
681         my $users = OpenILS::Application::AppUtils->simple_scalar_request(
682                         "open-ils.storage", 
683                         "open-ils.storage.direct.actor.user.search.usrname.atomic",
684                         $username );
685         return $users;
686 }
687
688
689
690
691 __PACKAGE__->register_method(
692         method  => "user_retrieve_by_barcode",
693         api_name        => "open-ils.actor.user.fleshed.retrieve_by_barcode",);
694
695 sub user_retrieve_by_barcode {
696         my($self, $client, $user_session, $barcode) = @_;
697
698         $logger->debug("Searching for user with barcode $barcode");
699         #my $user_obj = $apputils->check_user_session( $user_session ); 
700         my ($user_obj, $evt) = $apputils->check_ses($user_session);
701         return $evt if $evt;
702
703         my $session = OpenSRF::AppSession->create("open-ils.storage");
704
705         # find the card with the given barcode
706         my $creq        = $session->request(
707                         "open-ils.storage.direct.actor.card.search.barcode.atomic",
708                         $barcode );
709         my $card = $creq->gather(1);
710
711         if(!$card || !$card->[0]) {
712                 $session->disconnect();
713                 return OpenILS::Event->new( 'USER_NOT_FOUND' );
714         }
715
716         $card = $card->[0];
717         my $user = flesh_user($card->usr(), $session);
718         $session->disconnect();
719         if(!$user) { return OpenILS::Event->new( 'USER_NOT_FOUND' ); }
720         return $user;
721
722 }
723
724
725
726 __PACKAGE__->register_method(
727         method  => "get_user_by_id",
728         api_name        => "open-ils.actor.user.retrieve",);
729
730 sub get_user_by_id {
731         my ($self, $client, $user_session, $id) = @_;
732
733         my $user_obj = $apputils->check_user_session( $user_session ); 
734
735         return $apputils->simple_scalar_request(
736                 "open-ils.storage",
737                 "open-ils.storage.direct.actor.user.retrieve",
738                 $id );
739 }
740
741
742
743 __PACKAGE__->register_method(
744         method  => "get_org_types",
745         api_name        => "open-ils.actor.org_types.retrieve",);
746
747 my $org_types;
748 sub get_org_types {
749         my($self, $client) = @_;
750
751         return $org_types if $org_types;
752          return $org_types = 
753                  $apputils->simple_scalar_request(
754                         "open-ils.storage",
755                         "open-ils.storage.direct.actor.org_unit_type.retrieve.all.atomic" );
756 }
757
758
759
760 __PACKAGE__->register_method(
761         method  => "get_user_profiles",
762         api_name        => "open-ils.actor.user.profiles.retrieve",
763 );
764
765 my $user_profiles;
766 sub get_user_profiles {
767         return $user_profiles if $user_profiles;
768
769         return $user_profiles = 
770                 $apputils->simple_scalar_request(
771                         "open-ils.storage",
772                         "open-ils.storage.direct.actor.profile.retrieve.all.atomic");
773 }
774
775
776
777 __PACKAGE__->register_method(
778         method  => "get_user_ident_types",
779         api_name        => "open-ils.actor.user.ident_types.retrieve",
780 );
781 my $ident_types;
782 sub get_user_ident_types {
783         return $ident_types if $ident_types;
784         return $ident_types = 
785                 $apputils->simple_scalar_request(
786                 "open-ils.storage",
787                 "open-ils.storage.direct.config.identification_type.retrieve.all.atomic" );
788 }
789
790
791
792
793 __PACKAGE__->register_method(
794         method  => "get_org_unit",
795         api_name        => "open-ils.actor.org_unit.retrieve",
796 );
797
798 sub get_org_unit {
799
800         my( $self, $client, $user_session, $org_id ) = @_;
801
802         if(defined($user_session) && !defined($org_id)) {
803                 my $user_obj = 
804                         OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
805                 if(!defined($org_id)) {
806                         $org_id = $user_obj->home_ou;
807                 }
808         }
809
810
811         my $home_ou = OpenILS::Application::AppUtils->simple_scalar_request(
812                 "open-ils.storage",
813                 "open-ils.storage.direct.actor.org_unit.retrieve", 
814                 $org_id );
815
816         return $home_ou;
817 }
818
819
820 # build the org tree
821
822 __PACKAGE__->register_method(
823         method  => "get_org_tree",
824         api_name        => "open-ils.actor.org_tree.retrieve",
825         argc            => 0, 
826         note            => "Returns the entire org tree structure",
827 );
828
829 sub get_org_tree {
830         my( $self, $client) = @_;
831
832         if(!$cache_client) {
833                 $cache_client = OpenSRF::Utils::Cache->new("global", 0);
834         }
835         # see if it's in the cache
836         warn "Getting ORG Tree\n";
837         my $tree = $cache_client->get_cache('orgtree');
838         if($tree) { 
839                 warn "Found orgtree in cache. returning...\n";
840                 return $tree; 
841         }
842
843         my $orglist = $apputils->simple_scalar_request( 
844                 "open-ils.storage", 
845                 "open-ils.storage.direct.actor.org_unit.retrieve.all.atomic" );
846
847         if($orglist) {
848                 warn "found org list\n";
849         }
850
851         $tree = $self->build_org_tree($orglist);
852         $cache_client->put_cache('orgtree', $tree);
853
854         return $tree;
855
856 }
857
858 # turns an org list into an org tree
859 sub build_org_tree {
860
861         my( $self, $orglist) = @_;
862
863         return $orglist unless ( 
864                         ref($orglist) and @$orglist > 1 );
865
866         my @list = sort { 
867                 $a->ou_type <=> $b->ou_type ||
868                 $a->name cmp $b->name } @$orglist;
869
870         for my $org (@list) {
871
872                 next unless ($org and defined($org->parent_ou));
873                 my ($parent) = grep { $_->id == $org->parent_ou } @list;
874                 next unless $parent;
875
876                 $parent->children([]) unless defined($parent->children); 
877                 push( @{$parent->children}, $org );
878         }
879
880         return $list[0];
881
882 }
883
884
885 __PACKAGE__->register_method(
886         method  => "get_org_descendants",
887         api_name        => "open-ils.actor.org_tree.descendants.retrieve"
888 );
889
890 # depth is optional.  org_unit is the id
891 sub get_org_descendants {
892         my( $self, $client, $org_unit, $depth ) = @_;
893         my $orglist = $apputils->simple_scalar_request(
894                         "open-ils.storage", 
895                         "open-ils.storage.actor.org_unit.descendants.atomic",
896                         $org_unit, $depth );
897         return $self->build_org_tree($orglist);
898 }
899
900
901 __PACKAGE__->register_method(
902         method  => "get_org_ancestors",
903         api_name        => "open-ils.actor.org_tree.ancestors.retrieve"
904 );
905
906 # depth is optional.  org_unit is the id
907 sub get_org_ancestors {
908         my( $self, $client, $org_unit, $depth ) = @_;
909         my $orglist = $apputils->simple_scalar_request(
910                         "open-ils.storage", 
911                         "open-ils.storage.actor.org_unit.ancestors.atomic",
912                         $org_unit, $depth );
913         return $self->build_org_tree($orglist);
914 }
915
916
917 __PACKAGE__->register_method(
918         method  => "get_standings",
919         api_name        => "open-ils.actor.standings.retrieve"
920 );
921
922 my $user_standings;
923 sub get_standings {
924         return $user_standings if $user_standings;
925         return $user_standings = 
926                 $apputils->simple_scalar_request(
927                         "open-ils.storage",
928                         "open-ils.storage.direct.config.standing.retrieve.all.atomic" );
929 }
930
931
932
933 __PACKAGE__->register_method(
934         method  => "get_my_org_path",
935         api_name        => "open-ils.actor.org_unit.full_path.retrieve"
936 );
937
938 sub get_my_org_path {
939         my( $self, $client, $user_session, $org_id ) = @_;
940         my $user_obj = $apputils->check_user_session($user_session); 
941         if(!defined($org_id)) { $org_id = $user_obj->home_ou; }
942
943         return $apputils->simple_scalar_request(
944                 "open-ils.storage",
945                 "open-ils.storage.actor.org_unit.full_path.atomic",
946                 $org_id );
947 }
948
949
950 __PACKAGE__->register_method(
951         method  => "patron_adv_search",
952         api_name        => "open-ils.actor.patron.search.advanced" );
953
954 sub patron_adv_search {
955         my( $self, $client, $staff_login, $search_hash ) = @_;
956
957         use Data::Dumper;
958         warn "patron adv with $staff_login and search " . 
959                 Dumper($search_hash) . "\n";
960
961         my $session = OpenSRF::AppSession->create("open-ils.storage");
962         my $req = $session->request(
963                 "open-ils.storage.actor.user.crazy_search", $search_hash);
964
965         my $ans = $req->gather(1);
966
967         my %hash = map { ($_ =>1) } @$ans;
968         $ans = [ keys %hash ];
969
970         warn "Returning @$ans\n";
971
972         $session->disconnect();
973         return $ans;
974
975 }
976
977
978
979 sub _verify_password {
980         my($user_session, $password) = @_;
981         my $user_obj = $apputils->check_user_session($user_session); 
982
983         #grab the user with password
984         $user_obj = $apputils->simple_scalar_request(
985                 "open-ils.storage", 
986                 "open-ils.storage.direct.actor.user.retrieve",
987                 $user_obj->id );
988
989         if($user_obj->passwd eq $password) {
990                 return 1;
991         }
992
993         return 0;
994 }
995
996
997 __PACKAGE__->register_method(
998         method  => "update_password",
999         api_name        => "open-ils.actor.user.password.update");
1000
1001 __PACKAGE__->register_method(
1002         method  => "update_password",
1003         api_name        => "open-ils.actor.user.username.update");
1004
1005 __PACKAGE__->register_method(
1006         method  => "update_password",
1007         api_name        => "open-ils.actor.user.email.update");
1008
1009 sub update_password {
1010         my( $self, $client, $user_session, $new_value, $current_password ) = @_;
1011
1012         warn "Updating user with method " .$self->api_name . "\n";
1013         my $user_obj = $apputils->check_user_session($user_session); 
1014
1015         if($self->api_name =~ /password/) {
1016
1017                 #make sure they know the current password
1018                 if(!_verify_password($user_session, md5_hex($current_password))) {
1019                         return OpenILS::EX->new("USER_WRONG_PASSWORD")->ex;
1020                 }
1021
1022                 $user_obj->passwd($new_value);
1023         } 
1024         elsif($self->api_name =~ /username/) {
1025                 my $users = search_username(undef, undef, $new_value); 
1026                 if( $users and $users->[0] ) {
1027                         return OpenILS::Event->new('USERNAME_EXISTS');
1028                 }
1029                 $user_obj->usrname($new_value);
1030         }
1031
1032         elsif($self->api_name =~ /email/) {
1033                 warn "Updating email to $new_value\n";
1034                 $user_obj->email($new_value);
1035         }
1036
1037         my $session = $apputils->start_db_session();
1038         $user_obj = _update_patron($session, $user_obj, $user_obj);
1039         $apputils->commit_db_session($session);
1040
1041         if($user_obj) { return 1; }
1042         return undef;
1043 }
1044
1045
1046 __PACKAGE__->register_method(
1047         method  => "check_user_perms",
1048         api_name        => "open-ils.actor.user.perm.check",
1049         notes           => <<"  NOTES");
1050         Takes a login session, user id, an org id, and an array of perm type strings.  For each
1051         perm type, if the user does *not* have the given permission it is added
1052         to a list which is returned from the method.  If all permissions
1053         are allowed, an empty list is returned
1054         if the logged in user does not match 'user_id', then the logged in user must
1055         have VIEW_PERMISSION priveleges.
1056         NOTES
1057
1058 sub check_user_perms {
1059         my( $self, $client, $login_session, $user_id, $org_id, $perm_types ) = @_;
1060
1061         my( $staff, $evt ) = $apputils->checkses($login_session);
1062         return $evt if $evt;
1063
1064         if($staff->id ne $user_id) {
1065                 if( my $evt = $apputils->check_perms(
1066                         $staff->id, $org_id, 'VIEW_PERMISSION') ) {
1067                         return $evt;
1068                 }
1069         }
1070
1071         my @not_allowed;
1072         for my $perm (@$perm_types) {
1073                 if($apputils->check_perms($user_id, $org_id, $perm)) {
1074                         push @not_allowed, $perm;
1075                 }
1076         }
1077
1078         return \@not_allowed
1079 }
1080
1081 __PACKAGE__->register_method(
1082         method  => "check_user_perms2",
1083         api_name        => "open-ils.actor.user.perm.check.multi_org",
1084         notes           => q/
1085                 Checks the permissions on a list of perms and orgs for a user
1086                 @param authtoken The login session key
1087                 @param user_id The id of the user to check
1088                 @param orgs The array of org ids
1089                 @param perms The array of permission names
1090                 @return An array of  [ orgId, permissionName ] arrays that FAILED the check
1091                 if the logged in user does not match 'user_id', then the logged in user must
1092                 have VIEW_PERMISSION priveleges.
1093         /);
1094
1095 sub check_user_perms2 {
1096         my( $self, $client, $authtoken, $user_id, $orgs, $perms ) = @_;
1097
1098         my( $staff, $target, $evt ) = $apputils->checkses_requestor(
1099                 $authtoken, $user_id, 'VIEW_PERMISSION' );
1100         return $evt if $evt;
1101
1102         my @not_allowed;
1103         for my $org (@$orgs) {
1104                 for my $perm (@$perms) {
1105                         if($apputils->check_perms($user_id, $org, $perm)) {
1106                                 push @not_allowed, [ $org, $perm ];
1107                         }
1108                 }
1109         }
1110
1111         return \@not_allowed
1112 }
1113
1114
1115 __PACKAGE__->register_method(
1116         method => 'check_user_perms3',
1117         api_name        => 'open-ils.actor.user.perm.highest_org',
1118         notes           => q/
1119                 Returns the highest org unit object at which a user has a given permission
1120                 If the requestor does not match the target user, the requestor must have
1121                 'VIEW_PERMISSION' rights at the home org unit of the target user
1122                 @param authtoken The login session key
1123                 @param userid The id of the user in question
1124                 @param perm The permission to check
1125                 @return The org unit highest in the org tree within which the user has
1126                 the requested permission
1127         /);
1128
1129 sub check_user_perms3 {
1130         my( $self, $client, $authtoken, $userid, $perm ) = @_;
1131
1132         my( $staff, $target, $org, $evt );
1133
1134         ( $staff, $target, $evt ) = $apputils->checkses_requestor(
1135                 $authtoken, $userid, 'VIEW_PERMISSION' );
1136         return $evt if $evt;
1137
1138         my $tree = get_org_tree();
1139         $org = $apputils->find_org($tree, $target->home_ou );
1140
1141         my $lastid = undef;
1142         while( $org ) {
1143                 last if ($apputils->check_perms( $userid, $org->id, $perm )); # perm failed
1144                 $lastid = $org->id;
1145                 $org = $apputils->find_org( $tree, $org->parent_ou() );
1146         }
1147
1148         return $lastid;
1149 }
1150
1151
1152
1153
1154 __PACKAGE__->register_method(
1155         method  => "user_fines_summary",
1156         api_name        => "open-ils.actor.user.fines.summary",
1157         notes           => <<"  NOTES");
1158         Returns a short summary of the users total open fines, excluding voided fines
1159         Params are login_session, user_id
1160         Returns a 'mous' object.
1161         NOTES
1162
1163 sub user_fines_summary {
1164         my( $self, $client, $login_session, $user_id ) = @_;
1165
1166         my $user_obj = $apputils->check_user_session($login_session); 
1167         if($user_obj->id ne $user_id) {
1168                 if($apputils->check_user_perms($user_obj->id, $user_obj->home_ou, "VIEW_USER_FINES_SUMMARY")) {
1169                         return OpenILS::Perm->new("VIEW_USER_FINES_SUMMARY"); 
1170                 }
1171         }
1172
1173         return $apputils->simple_scalar_request( 
1174                 "open-ils.storage",
1175                 "open-ils.storage.direct.money.open_user_summary.search.usr",
1176                 $user_id );
1177
1178 }
1179
1180
1181
1182
1183 __PACKAGE__->register_method(
1184         method  => "user_transactions",
1185         api_name        => "open-ils.actor.user.transactions",
1186         notes           => <<"  NOTES");
1187         Returns a list of open user transactions (mbts objects);
1188         Params are login_session, user_id
1189         Optional third parameter is the transactions type.  defaults to all
1190         NOTES
1191
1192 __PACKAGE__->register_method(
1193         method  => "user_transactions",
1194         api_name        => "open-ils.actor.user.transactions.have_charge",
1195         notes           => <<"  NOTES");
1196         Returns a list of all open user transactions (mbts objects) that have an initial charge
1197         Params are login_session, user_id
1198         Optional third parameter is the transactions type.  defaults to all
1199         NOTES
1200
1201 __PACKAGE__->register_method(
1202         method  => "user_transactions",
1203         api_name        => "open-ils.actor.user.transactions.have_balance",
1204         notes           => <<"  NOTES");
1205         Returns a list of all open user transactions (mbts objects) that have a balance
1206         Params are login_session, user_id
1207         Optional third parameter is the transactions type.  defaults to all
1208         NOTES
1209
1210 __PACKAGE__->register_method(
1211         method  => "user_transactions",
1212         api_name        => "open-ils.actor.user.transactions.fleshed",
1213         notes           => <<"  NOTES");
1214         Returns an object/hash of transaction, circ, title where transaction = an open 
1215         user transactions (mbts objects), circ is the attached circluation, and title
1216         is the title the circ points to
1217         Params are login_session, user_id
1218         Optional third parameter is the transactions type.  defaults to all
1219         NOTES
1220
1221 __PACKAGE__->register_method(
1222         method  => "user_transactions",
1223         api_name        => "open-ils.actor.user.transactions.have_charge.fleshed",
1224         notes           => <<"  NOTES");
1225         Returns an object/hash of transaction, circ, title where transaction = an open 
1226         user transactions that has an initial charge (mbts objects), circ is the 
1227         attached circluation, and title is the title the circ points to
1228         Params are login_session, user_id
1229         Optional third parameter is the transactions type.  defaults to all
1230         NOTES
1231
1232 __PACKAGE__->register_method(
1233         method  => "user_transactions",
1234         api_name        => "open-ils.actor.user.transactions.have_balance.fleshed",
1235         notes           => <<"  NOTES");
1236         Returns an object/hash of transaction, circ, title where transaction = an open 
1237         user transaction that has a balance (mbts objects), circ is the attached 
1238         circluation, and title is the title the circ points to
1239         Params are login_session, user_id
1240         Optional third parameter is the transaction type.  defaults to all
1241         NOTES
1242
1243
1244
1245 sub user_transactions {
1246         my( $self, $client, $login_session, $user_id, $type ) = @_;
1247
1248         my( $user_obj, $target, $evt ) = $apputils->checkses_requestor(
1249                 $login_session, $user_id, 'VIEW_USER_TRANSACTIONS' );
1250         return $evt if $evt;
1251         
1252         my $api = $self->api_name();
1253         my $trans;
1254         my @xact;
1255
1256         if(defined($type)) { @xact = (xact_type =>  $type); 
1257
1258         } else { @xact = (); }
1259
1260         if($api =~ /have_charge/) {
1261
1262                 $trans = $apputils->simple_scalar_request( 
1263                         "open-ils.storage",
1264                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1265                         { usr => $user_id, total_owed => { ">" => 0 }, @xact });
1266
1267         } elsif($api =~ /have_balance/) {
1268
1269                 $trans =  $apputils->simple_scalar_request( 
1270                         "open-ils.storage",
1271                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1272                         { usr => $user_id, balance_owed => { ">" => 0 }, @xact });
1273
1274         } else {
1275
1276                 $trans =  $apputils->simple_scalar_request( 
1277                         "open-ils.storage",
1278                         "open-ils.storage.direct.money.open_billable_transaction_summary.search_where.atomic",
1279                         { usr => $user_id, @xact });
1280         }
1281
1282         if($api !~ /fleshed/) { return $trans; }
1283
1284         warn "API: $api\n";
1285
1286         my @resp;
1287         for my $t (@$trans) {
1288                         
1289                 warn $t->id . "\n";
1290
1291                 my $circ = $apputils->simple_scalar_request(
1292                                 "open-ils.storage",
1293                                 "open-ils.storage.direct.action.circulation.retrieve",
1294                                 $t->id );
1295
1296                 next unless $circ;
1297
1298                 my $title = $apputils->simple_scalar_request(
1299                         "open-ils.storage", 
1300                         "open-ils.storage.fleshed.biblio.record_entry.retrieve_by_copy",
1301                         $circ->target_copy );
1302
1303                 next unless $title;
1304
1305                 my $u = OpenILS::Utils::ModsParser->new();
1306                 $u->start_mods_batch($title->marc());
1307                 my $mods = $u->finish_mods_batch();
1308
1309                 push @resp, {transaction => $t, circ => $circ, record => $mods };
1310
1311         }
1312
1313         return \@resp; 
1314
1315
1316
1317
1318
1319 __PACKAGE__->register_method(
1320         method  => "user_perms",
1321         api_name        => "open-ils.actor.permissions.user_perms.retrieve",
1322         argc            => 1,
1323         notes           => <<"  NOTES");
1324         Returns a list of permissions
1325         NOTES
1326 sub user_perms {
1327         my( $self, $client, $authtoken, $user ) = @_;
1328
1329         my( $staff, $evt ) = $apputils->checkses($authtoken);
1330         return $evt if $evt;
1331
1332         $user ||= $staff->id;
1333
1334         if( $user != $staff->id and $evt = $apputils->check_perms( $staff->id, $staff->home_ou, 'VIEW_PERMISSION') ) {
1335                 return $evt;
1336         }
1337
1338         return $apputils->simple_scalar_request(
1339                 "open-ils.storage",
1340                 "open-ils.storage.permission.user_perms.atomic",
1341                 $user);
1342 }
1343
1344 __PACKAGE__->register_method(
1345         method  => "retrieve_perms",
1346         api_name        => "open-ils.actor.permissions.retrieve",
1347         notes           => <<"  NOTES");
1348         Returns a list of permissions
1349         NOTES
1350 sub retrieve_perms {
1351         my( $self, $client ) = @_;
1352         return $apputils->simple_scalar_request(
1353                 "open-ils.storage",
1354                 "open-ils.storage.direct.permission.perm_list.retrieve.all.atomic");
1355 }
1356
1357 __PACKAGE__->register_method(
1358         method  => "retrieve_groups",
1359         api_name        => "open-ils.actor.groups.retrieve",
1360         notes           => <<"  NOTES");
1361         Returns a list of user groupss
1362         NOTES
1363 sub retrieve_groups {
1364         my( $self, $client ) = @_;
1365         return $apputils->simple_scalar_request(
1366                 "open-ils.storage",
1367                 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1368 }
1369
1370 __PACKAGE__->register_method(
1371         method  => "retrieve_groups_tree",
1372         api_name        => "open-ils.actor.groups.tree.retrieve",
1373         notes           => <<"  NOTES");
1374         Returns a list of user groups
1375         NOTES
1376 sub retrieve_groups_tree {
1377         my( $self, $client ) = @_;
1378         my $groups = $apputils->simple_scalar_request(
1379                 "open-ils.storage",
1380                 "open-ils.storage.direct.permission.grp_tree.retrieve.all.atomic");
1381         return $self->build_group_tree($groups);        
1382 }
1383
1384
1385 # turns an org list into an org tree
1386 sub build_group_tree {
1387
1388         my( $self, $grplist) = @_;
1389
1390         return $grplist unless ( 
1391                         ref($grplist) and @$grplist > 1 );
1392
1393         my @list = sort { $a->name cmp $b->name } @$grplist;
1394
1395         my $root;
1396         for my $grp (@list) {
1397
1398                 if ($grp and !defined($grp->parent)) {
1399                         $root = $grp;
1400                         next;
1401                 }
1402                 my ($parent) = grep { $_->id == $grp->parent} @list;
1403
1404                 $parent->children([]) unless defined($parent->children); 
1405                 push( @{$parent->children}, $grp );
1406         }
1407
1408         return $root;
1409
1410 }
1411
1412
1413 __PACKAGE__->register_method(
1414         method  => "add_user_to_groups",
1415         api_name        => "open-ils.actor.user.set_groups",
1416         notes           => <<"  NOTES");
1417         Adds a user to one or more permission groups
1418         NOTES
1419
1420 sub add_user_to_groups {
1421         my( $self, $client, $authtoken, $userid, $groups ) = @_;
1422
1423         my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1424                 $authtoken, $userid, 'CREATE_USER_GROUP_LINK' );
1425         return $evt if $evt;
1426
1427         ( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1428                 $authtoken, $userid, 'REMOVE_USER_GROUP_LINK' );
1429         return $evt if $evt;
1430
1431         $apputils->simplereq(
1432                 'open-ils.storage',
1433                 'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
1434                 
1435         for my $group (@$groups) {
1436                 my $link = Fieldmapper::permission::usr_grp_map->new;
1437                 $link->grp($group);
1438                 $link->usr($userid);
1439
1440                 my $id = $apputils->simplereq(
1441                         'open-ils.storage',
1442                         'open-ils.storage.direct.permission.usr_grp_map.create', $link );
1443         }
1444
1445         return 1;
1446 }
1447
1448 __PACKAGE__->register_method(
1449         method  => "get_user_perm_groups",
1450         api_name        => "open-ils.actor.user.get_groups",
1451         notes           => <<"  NOTES");
1452         Retrieve a user's permission groups.
1453         NOTES
1454
1455
1456 sub get_user_perm_groups {
1457         my( $self, $client, $authtoken, $userid ) = @_;
1458
1459         my( $requestor, $target, $evt ) = $apputils->checkses_requestor(
1460                 $authtoken, $userid, 'VIEW_PERM_GROUPS' );
1461         return $evt if $evt;
1462
1463         return $apputils->simplereq(
1464                 'open-ils.storage',
1465                 'open-ils.storage.direct.permission.usr_grp_map.search.usr.atomic', $userid );
1466 }       
1467
1468
1469
1470
1471 1;
1472