1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC
6 # <jesse@bestpractical.com>
8 # (Except where explicitly superseded by other copyright notices)
13 # This work is made available to you under the terms of Version 2 of
14 # the GNU General Public License. A copy of that license should have
15 # been provided with this software, but in any event can be snarfed
18 # This work is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 # General Public License for more details.
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 # CONTRIBUTION SUBMISSION POLICY:
30 # (The following paragraph is not intended to limit the rights granted
31 # to you to modify and distribute this software under the terms of
32 # the GNU General Public License and is only of importance to you if
33 # you choose to contribute your changes and enhancements to the
34 # community by submitting them to Best Practical Solutions, LLC.)
36 # By intentionally submitting any modifications, corrections or
37 # derivatives to this work, or any other work intended for use with
38 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
39 # you are the copyright holder for those contributions and you grant
40 # Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
41 # royalty-free, perpetual, license to use, copy, create derivative
42 # works based on those contributions, and sublicense and distribute
43 # those contributions and any derivatives thereof.
45 # END BPS TAGGED BLOCK }}}
49 RT::Scrip - an RT Scrip object
62 ok (require RT::Scrip);
65 my $q = RT::Queue->new($RT::SystemUser);
66 $q->Create(Name => 'ScripTest');
67 ok($q->Id, "Created a scriptest queue");
69 my $s1 = RT::Scrip->new($RT::SystemUser);
70 my ($val, $msg) =$s1->Create( Queue => $q->Id,
71 ScripAction => 'User Defined',
72 ScripCondition => 'User Defined',
73 CustomIsApplicableCode => 'if ($self->TicketObj->Subject =~ /fire/) { return (1);} else { return(0)}',
74 CustomPrepareCode => 'return 1',
75 CustomCommitCode => '$self->TicketObj->SetPriority("87");',
80 my $ticket = RT::Ticket->new($RT::SystemUser);
81 my ($tv,$ttv,$tm) = $ticket->Create(Queue => $q->Id,
82 Subject => "hair on fire",
86 ok ($ticket->Priority == '87', "Ticket priority is set right");
89 my $ticket2 = RT::Ticket->new($RT::SystemUser);
90 my ($t2v,$t2tv,$t2m) = $ticket2->Create(Queue => $q->Id,
91 Subject => "hair in water",
95 ok ($ticket2->Priority != '87', "Ticket priority is set right");
106 no warnings qw(redefine);
112 Creates a new entry in the Scrips table. Takes a paramhash with:
115 Description => undef,
117 ScripAction => undef,
118 ScripCondition => undef,
119 CustomPrepareCode => undef,
120 CustomCommitCode => undef,
121 CustomIsApplicableCode => undef,
126 Returns (retval, msg);
127 retval is 0 for failure or scrip id. msg is a textual description of what happened.
135 Template => 0, # name or id
136 ScripAction => 0, # name or id
137 ScripCondition => 0, # name or id
138 Stage => 'TransactionCreate',
139 Description => undef,
140 CustomPrepareCode => undef,
141 CustomCommitCode => undef,
142 CustomIsApplicableCode => undef,
146 if ( !$args{'Queue'} ) {
147 unless ( $self->CurrentUser->HasRight( Object => $RT::System,
148 Right => 'ModifyScrips' )
150 return ( 0, $self->loc('Permission Denied') );
152 $args{'Queue'} = 0; # avoid undef sneaking in
155 my $QueueObj = new RT::Queue( $self->CurrentUser );
156 $QueueObj->Load( $args{'Queue'} );
157 unless ( $QueueObj->id() ) {
158 return ( 0, $self->loc('Invalid queue') );
160 unless ( $QueueObj->CurrentUserHasRight('ModifyScrips') ) {
161 return ( 0, $self->loc('Permission Denied') );
163 $args{'Queue'} = $QueueObj->id();
166 #TODO +++ validate input
168 require RT::ScripAction;
169 my $action = new RT::ScripAction( $self->CurrentUser );
170 if ( $args{'ScripAction'} ) {
171 $action->Load( $args{'ScripAction'} );
173 return ( 0, $self->loc( "Action [_1] not found", $args{'ScripAction'} ) )
176 require RT::Template;
177 my $template = new RT::Template( $self->CurrentUser );
178 if ( $args{'Template'} ) {
179 $template->Load( $args{'Template'} );
181 return ( 0, $self->loc('Template not found') ) unless $template->Id;
183 require RT::ScripCondition;
184 my $condition = new RT::ScripCondition( $self->CurrentUser );
185 if ( $args{'ScripCondition'} ) {
186 $condition->Load( $args{'ScripCondition'} );
188 unless ( $condition->Id ) {
189 return ( 0, $self->loc('Condition not found') );
192 my ( $id, $msg ) = $self->SUPER::Create(
193 Queue => $args{'Queue'},
194 Template => $template->Id,
195 ScripCondition => $condition->id,
196 Stage => $args{'Stage'},
197 ScripAction => $action->Id,
198 Description => $args{'Description'},
199 CustomPrepareCode => $args{'CustomPrepareCode'},
200 CustomCommitCode => $args{'CustomCommitCode'},
201 CustomIsApplicableCode => $args{'CustomIsApplicableCode'},
205 return ( $id, $self->loc('Scrip Created') );
208 return ( $id, $msg );
225 unless ( $self->CurrentUserHasRight('ModifyScrips') ) {
226 return ( 0, $self->loc('Permission Denied') );
229 return ( $self->SUPER::Delete(@_) );
238 Retuns an RT::Queue object with this Scrip\'s queue
245 if ( !$self->{'QueueObj'} ) {
247 $self->{'QueueObj'} = RT::Queue->new( $self->CurrentUser );
248 $self->{'QueueObj'}->Load( $self->__Value('Queue') );
250 return ( $self->{'QueueObj'} );
259 Retuns an RT::Action object with this Scrip\'s Action
266 unless ( defined $self->{'ScripActionObj'} ) {
267 require RT::ScripAction;
269 $self->{'ScripActionObj'} = RT::ScripAction->new( $self->CurrentUser );
271 #TODO: why are we loading Actions with templates like this.
272 # two separate methods might make more sense
273 $self->{'ScripActionObj'}->Load( $self->ScripAction, $self->Template );
275 return ( $self->{'ScripActionObj'} );
280 # {{{ sub ConditionObj
284 Retuns an RT::ScripCondition object with this Scrip's IsApplicable
291 unless ( defined $self->{'ScripConditionObj'} ) {
292 require RT::ScripCondition;
293 $self->{'ScripConditionObj'} =
294 RT::ScripCondition->new( $self->CurrentUser );
295 if ( $self->ScripCondition ) {
296 $self->{'ScripConditionObj'}->Load( $self->ScripCondition );
299 return ( $self->{'ScripConditionObj'} );
304 # {{{ sub TemplateObj
308 Retuns an RT::Template object with this Scrip\'s Template
315 unless ( defined $self->{'TemplateObj'} ) {
316 require RT::Template;
317 $self->{'TemplateObj'} = RT::Template->new( $self->CurrentUser );
318 $self->{'TemplateObj'}->Load( $self->Template );
320 return ( $self->{'TemplateObj'} );
325 # {{{ Dealing with this instance of a scrip
329 =head2 Apply { TicketObj => undef, TransactionObj => undef}
331 This method instantiates the ScripCondition and ScripAction objects for a
332 single execution of this scrip. it then calls the IsApplicable method of the
334 If that succeeds, it calls the Prepare method of the
335 ScripAction. If that succeeds, it calls the Commit method of the ScripAction.
337 Usually, the ticket and transaction objects passed to this method
338 should be loaded by the SuperUser role
343 # XXX TODO : This code appears to be obsoleted in favor of similar code in Scrips->Apply.
344 # Why is this here? Is it still called?
348 my %args = ( TicketObj => undef,
349 TransactionObj => undef,
352 $RT::Logger->debug("Now applying scrip ".$self->Id . " for transaction ".$args{'TransactionObj'}->id);
354 my $ApplicableTransactionObj = $self->IsApplicable( TicketObj => $args{'TicketObj'},
355 TransactionObj => $args{'TransactionObj'} );
356 unless ( $ApplicableTransactionObj ) {
360 if ( $ApplicableTransactionObj->id != $args{'TransactionObj'}->id ) {
361 $RT::Logger->debug("Found an applicable transaction ".$ApplicableTransactionObj->Id . " in the same batch with transaction ".$args{'TransactionObj'}->id);
364 #If it's applicable, prepare and commit it
365 $RT::Logger->debug("Now preparing scrip ".$self->Id . " for transaction ".$ApplicableTransactionObj->id);
366 unless ( $self->Prepare( TicketObj => $args{'TicketObj'},
367 TransactionObj => $ApplicableTransactionObj )
372 $RT::Logger->debug("Now commiting scrip ".$self->Id . " for transaction ".$ApplicableTransactionObj->id);
373 unless ( $self->Commit( TicketObj => $args{'TicketObj'},
374 TransactionObj => $ApplicableTransactionObj)
379 $RT::Logger->debug("We actually finished scrip ".$self->Id . " for transaction ".$ApplicableTransactionObj->id);
386 # {{{ sub IsApplicable
390 Calls the Condition object\'s IsApplicable method
392 Upon success, returns the applicable Transaction object.
393 Otherwise, undef is returned.
395 If the Scrip is in the TransactionCreate Stage (the usual case), only test
396 the associated Transaction object to see if it is applicable.
398 For Scrips in the TransactionBatch Stage, test all Transaction objects
399 created during the Ticket object's lifetime, and returns the first one
406 my %args = ( TicketObj => undef,
407 TransactionObj => undef,
415 if ( $self->Stage eq 'TransactionCreate') {
416 # Only look at our current Transaction
417 @Transactions = ( $args{'TransactionObj'} );
419 elsif ( $self->Stage eq 'TransactionBatch') {
420 # Look at all Transactions in this Batch
421 @Transactions = @{ $args{'TicketObj'}->TransactionBatch || [] };
424 $RT::Logger->error( "Unknown Scrip stage:" . $self->Stage );
427 my $ConditionObj = $self->ConditionObj;
428 foreach my $TransactionObj ( @Transactions ) {
429 # in TxnBatch stage we can select scrips that are not applicable to all txns
430 my $txn_type = $TransactionObj->Type;
431 next unless( $ConditionObj->ApplicableTransTypes =~ /(?:^|,)(?:Any|\Q$txn_type\E)(?:,|$)/i );
432 # Load the scrip's Condition object
433 $ConditionObj->LoadCondition(
435 TicketObj => $args{'TicketObj'},
436 TransactionObj => $TransactionObj,
439 if ( $ConditionObj->IsApplicable() ) {
440 # We found an application Transaction -- return it
441 $return = $TransactionObj;
447 $RT::Logger->error( "Scrip IsApplicable " . $self->Id . " died. - " . $@ );
461 Calls the action object's prepare method
467 my %args = ( TicketObj => undef,
468 TransactionObj => undef,
473 $self->ActionObj->LoadAction( ScripObj => $self,
474 TicketObj => $args{'TicketObj'},
475 TransactionObj => $args{'TransactionObj'},
478 $return = $self->ActionObj->Prepare();
481 $RT::Logger->error( "Scrip Prepare " . $self->Id . " died. - " . $@ );
495 Calls the action object's commit method
501 my %args = ( TicketObj => undef,
502 TransactionObj => undef,
507 $return = $self->ActionObj->Commit();
510 #Searchbuilder caching isn't perfectly coherent. got to reload the ticket object, since it
512 $args{'TicketObj'}->Load( $args{'TicketObj'}->Id );
515 $RT::Logger->error( "Scrip Commit " . $self->Id . " died. - " . $@ );
519 # Not destroying or weakening hte Action and Condition here could cause a
529 # {{{ ACL related methods
533 # does an acl check and then passes off the call
537 unless ( $self->CurrentUserHasRight('ModifyScrips') ) {
539 "CurrentUser can't modify Scrips for " . $self->Queue . "\n" );
540 return ( 0, $self->loc('Permission Denied') );
542 return $self->__Set(@_);
548 # does an acl check and then passes off the call
552 unless ( $self->CurrentUserHasRight('ShowScrips') ) {
553 $RT::Logger->debug( "CurrentUser can't modify Scrips for "
554 . $self->__Value('Queue')
559 return $self->__Value(@_);
564 # {{{ sub CurrentUserHasRight
566 =head2 CurrentUserHasRight
568 Helper menthod for HasRight. Presets Principal to CurrentUser then
573 sub CurrentUserHasRight {
576 return ( $self->HasRight( Principal => $self->CurrentUser->UserObj,
587 Takes a param-hash consisting of "Right" and "Principal" Principal is
588 an RT::User object or an RT::CurrentUser object. "Right" is a textual
589 Right string that applies to Scrips.
595 my %args = ( Right => undef,
599 if ( ( defined $self->SUPER::_Value('Queue') )
600 and ( $self->SUPER::_Value('Queue') != 0 ) ) {
601 return ( $args{'Principal'}->HasRight( Right => $args{'Right'},
602 Object => $self->QueueObj ) );
606 return ( $args{'Principal'}
607 ->HasRight( Object => $RT::System, Right => $args{'Right'} ) );