From 44426876fdb458b7045310073df9c7abd74d8422 Mon Sep 17 00:00:00 2001 From: Lebbeous Fogle-Weekley Date: Tue, 12 Feb 2013 14:40:27 -0500 Subject: [PATCH] Acq: batch update api - target perm checks Signed-off-by: Lebbeous Fogle-Weekley --- .../lib/OpenILS/Application/Acq/Lineitem.pm | 144 +++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm index 9fe3ae639b..e96f30e47c 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm @@ -954,4 +954,148 @@ sub retrieve_lineitem_by_copy_id { return $li; } +# lineitem_batch_update_perm_test() +# +# Returns undef on success, event on perm failure. +# Responsible for calling $e->die_event. +# Also sanitizes values in $target. +# +sub lineitem_batch_update_perm_test { + my ($e, $target) = @_; + + return $e->die_event(new OpenILS::Event("BAD_PARAMS", note => "target")) + unless ref $target eq "HASH"; + + my $perm_for = { + ordering_agency => "CREATE_PURCHASE_ORDER", + org_unit => "UPDATE_PICKLIST" + }; + + if (ref $target->{lineitems} eq "ARRAY") { + # Sanitization + $target->{lineitems} = [ map { int $_ } @{$target->{lineitems}} ]; + + return $e->die_event( + new OpenILS::Event( + "BAD_PARAMS", note => "target (lineitems list empty)" + ) + ) unless @{$target->{lineitems}}; + + # Get all PO & picklist linkings from lineitems in question. + my $li_rows = $e->json_query({ + select => { + jub => ["id"], + acqpo => ["ordering_agency"], + acqpl => ["org_unit"] + }, + from => { + jub => {acqpl => {type => "left"}, acqpo => {type => "left"}} + }, + where => { + "+jub" => {id => $target->{lineitems}} + } + }) or return $e->die_event; + + # Fail loudly rather than giving user any surprises if they asked to + # update lineitems that don't exist. This is an asymmetric difference + # calculation. + my %present = map { $_->{id} => 1 } @$li_rows; + my @missing = grep { not exists $present{$_} } @{$target->{lineitems}}; + return $e->die_event( + new OpenILS::Event( + "ACQ_LINEITEM_NOT_FOUND", payload => \@missing + ) + ) if @missing; + + # To avoid repetition of perm tests, track them here. + my $already_done = { + ordering_agency => {}, + org_unit => {} + }; + + # Test all lineitems based on the context OU of all linked POs AND PLs. + foreach my $row (@$li_rows) { + foreach my $field (keys %$already_done) { + if ($row->{$field}) { + if (not $already_done->{$row}{$field}) { + my $perm = $perm_for->{$field}; + my $context = $row->{$field}; + + if (not $e->allowed($perm, $context)) { + my $evt = $e->die_event; + + # Take the PERM_FAILURE event and annotate it with + # a list of the targeted lineitems that would fail + # the same permission check (i.e. that have the + # same context). + $evt->{payload} = [ + map { $_->{id} } ( + grep { $_->{$field} == $context } @$li_rows + ) + ]; + return $evt; + } else { + $already_done->{$row}{$field} = 1; + } + } + } + } + } + } elsif ($target->{purchase_order}) { + $target->{purchase_order} = int($target->{purchase_order}); + + my $po = $e->retrieve_acq_purchase_order($target->{purchase_order}) or + return $e->die_event; + + return $e->die_event unless + $e->allowed($perm_for->{ordering_agency}, $po->ordering_agency); + } elsif ($target->{picklist}) { + $target->{picklist} = int($target->{picklist}); + + my $pl = $e->retrieve_acq_picklist($target->{picklist}) or + return $e->die_event; + + return $e->die_event unless + $e->allowed($perm_for->{org_unit}, $pl->org_unit); + } else { + return $e->die_event( + new OpenILS::Event("BAD_PARAMS", note => "target") + ); + } + + return; # perm check pass +} + +__PACKAGE__->register_method( + method => "lineitem_batch_update_api", + api_name => "open-ils.acq.lineitem.batch_update", + signature => { + desc => "Apply changes to lineitems in batch", + params => [ + {desc => "Authentication token", type => "string"}, + {desc => "Target. Object key must be one of lineitems, purchase_order or picklist. The value for 'lineitems' must be an array of IDs, and the values for either of the other two must be single IDs.", type => "object"}, + {desc => "Changes (optional). If these changes conflict with distribution formula, these changes win.", type => "object"}, + {desc => "Distribution formula ID (optional)", type => "number"} + ], + return => { + # XXX TODO + } + } +); + +sub lineitem_batch_update_api { + my ($self, $conn, $auth, $target, $changes, $dist_formula) = @_; + + my $e = new_editor("authtoken" => $auth, xact => 1); + return $e->die_event unless $e->checkauth; + + # lineitem_batch_update_perm_test() will call die_event() for us if needed. + my $evt = lineitem_batch_update_perm_test($e, $target); + return $evt if $U->event_code($evt); + + $e->rollback; + + return 1; +} + 1; -- 2.11.0