1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA
26 # 02110-1301 or visit their web page on the internet at
27 # http://www.gnu.org/copyleft/gpl.html.
30 # CONTRIBUTION SUBMISSION POLICY:
32 # (The following paragraph is not intended to limit the rights granted
33 # to you to modify and distribute this software under the terms of
34 # the GNU General Public License and is only of importance to you if
35 # you choose to contribute your changes and enhancements to the
36 # community by submitting them to Best Practical Solutions, LLC.)
38 # By intentionally submitting any modifications, corrections or
39 # derivatives to this work, or any other work intended for use with
40 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 # you are the copyright holder for those contributions and you grant
42 # Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
43 # royalty-free, perpetual, license to use, copy, create derivative
44 # works based on those contributions, and sublicense and distribute
45 # those contributions and any derivatives thereof.
47 # END BPS TAGGED BLOCK }}}
50 RT::Scrip - an RT Scrip object
63 ok (require RT::Scrip);
66 my $q = RT::Queue->new($RT::SystemUser);
67 $q->Create(Name => 'ScripTest');
68 ok($q->Id, "Created a scriptest queue");
70 my $s1 = RT::Scrip->new($RT::SystemUser);
71 my ($val, $msg) =$s1->Create( Queue => $q->Id,
72 ScripAction => 'User Defined',
73 ScripCondition => 'User Defined',
74 CustomIsApplicableCode => 'if ($self->TicketObj->Subject =~ /fire/) { return (1);} else { return(0)}',
75 CustomPrepareCode => 'return 1',
76 CustomCommitCode => '$self->TicketObj->SetPriority("87");',
81 my $ticket = RT::Ticket->new($RT::SystemUser);
82 my ($tv,$ttv,$tm) = $ticket->Create(Queue => $q->Id,
83 Subject => "hair on fire",
87 ok ($ticket->Priority == '87', "Ticket priority is set right");
90 my $ticket2 = RT::Ticket->new($RT::SystemUser);
91 my ($t2v,$t2tv,$t2m) = $ticket2->Create(Queue => $q->Id,
92 Subject => "hair in water",
96 ok ($ticket2->Priority != '87', "Ticket priority is set right");
107 no warnings qw(redefine);
113 Creates a new entry in the Scrips table. Takes a paramhash with:
116 Description => undef,
118 ScripAction => undef,
119 ScripCondition => undef,
120 CustomPrepareCode => undef,
121 CustomCommitCode => undef,
122 CustomIsApplicableCode => undef,
127 Returns (retval, msg);
128 retval is 0 for failure or scrip id. msg is a textual description of what happened.
136 Template => 0, # name or id
137 ScripAction => 0, # name or id
138 ScripCondition => 0, # name or id
139 Stage => 'TransactionCreate',
140 Description => undef,
141 CustomPrepareCode => undef,
142 CustomCommitCode => undef,
143 CustomIsApplicableCode => undef,
147 unless ( $args{'Queue'} ) {
148 unless ( $self->CurrentUser->HasRight( Object => $RT::System,
149 Right => 'ModifyScrips' )
151 return ( 0, $self->loc('Permission Denied') );
153 $args{'Queue'} = 0; # avoid undef sneaking in
156 my $QueueObj = RT::Queue->new( $self->CurrentUser );
157 $QueueObj->Load( $args{'Queue'} );
158 unless ( $QueueObj->id ) {
159 return ( 0, $self->loc('Invalid queue') );
161 unless ( $QueueObj->CurrentUserHasRight('ModifyScrips') ) {
162 return ( 0, $self->loc('Permission Denied') );
164 $args{'Queue'} = $QueueObj->id();
167 #TODO +++ validate input
169 require RT::ScripAction;
170 return ( 0, $self->loc("Action is mandatory argument") )
171 unless $args{'ScripAction'};
172 my $action = RT::ScripAction->new( $self->CurrentUser );
173 $action->Load( $args{'ScripAction'} );
174 return ( 0, $self->loc( "Action [_1] not found", $args{'ScripAction'} ) )
177 require RT::Template;
178 return ( 0, $self->loc("Template is mandatory argument") )
179 unless $args{'Template'};
180 my $template = RT::Template->new( $self->CurrentUser );
181 $template->Load( $args{'Template'} );
182 return ( 0, $self->loc('Template not found') )
183 unless $template->Id;
185 require RT::ScripCondition;
186 return ( 0, $self->loc("Condition is mandatory argument") )
187 unless $args{'ScripCondition'};
188 my $condition = RT::ScripCondition->new( $self->CurrentUser );
189 $condition->Load( $args{'ScripCondition'} );
190 return ( 0, $self->loc('Condition not found') )
191 unless $condition->Id;
193 my ( $id, $msg ) = $self->SUPER::Create(
194 Queue => $args{'Queue'},
195 Template => $template->Id,
196 ScripCondition => $condition->id,
197 Stage => $args{'Stage'},
198 ScripAction => $action->Id,
199 Description => $args{'Description'},
200 CustomPrepareCode => $args{'CustomPrepareCode'},
201 CustomCommitCode => $args{'CustomCommitCode'},
202 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 ( $self->SUPER::_Value('Queue') ) {
600 return $args{'Principal'}->HasRight(
601 Right => $args{'Right'},
602 Object => $self->QueueObj
606 return $args{'Principal'}->HasRight(
607 Object => $RT::System,
608 Right => $args{'Right'},