1 # {{{ BEGIN BPS TAGGED BLOCK
5 # This software is Copyright (c) 1996-2004 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
48 RT::Scrip - an RT Scrip object
61 ok (require RT::Scrip);
64 my $q = RT::Queue->new($RT::SystemUser);
65 $q->Create(Name => 'ScripTest');
66 ok($q->Id, "Created a scriptest queue");
68 my $s1 = RT::Scrip->new($RT::SystemUser);
69 my ($val, $msg) =$s1->Create( Queue => $q->Id,
70 ScripAction => 'User Defined',
71 ScripCondition => 'User Defined',
72 CustomIsApplicableCode => 'if ($self->TicketObj->Subject =~ /fire/) { return (1);} else { return(0)}',
73 CustomPrepareCode => 'return 1',
74 CustomCommitCode => '$self->TicketObj->SetPriority("87");',
79 my $ticket = RT::Ticket->new($RT::SystemUser);
80 my ($tv,$ttv,$tm) = $ticket->Create(Queue => $q->Id,
81 Subject => "hair on fire",
85 ok ($ticket->Priority == '87', "Ticket priority is set right");
88 my $ticket2 = RT::Ticket->new($RT::SystemUser);
89 my ($t2v,$t2tv,$t2m) = $ticket2->Create(Queue => $q->Id,
90 Subject => "hair in water",
94 ok ($ticket2->Priority != '87', "Ticket priority is set right");
102 no warnings qw(redefine);
108 Creates a new entry in the Scrips table. Takes a paramhash with:
111 Description => undef,
113 ScripAction => undef,
114 ScripCondition => undef,
115 CustomPrepareCode => undef,
116 CustomCommitCode => undef,
117 CustomIsApplicableCode => undef,
122 Returns (retval, msg);
123 retval is 0 for failure or scrip id. msg is a textual description of what happened.
131 Template => 0, # name or id
132 ScripAction => 0, # name or id
133 ScripCondition => 0, # name or id
134 Stage => 'TransactionCreate',
135 Description => undef,
136 CustomPrepareCode => undef,
137 CustomCommitCode => undef,
138 CustomIsApplicableCode => undef,
142 if ( !$args{'Queue'} ) {
143 unless ( $self->CurrentUser->HasRight( Object => $RT::System,
144 Right => 'ModifyScrips' )
146 return ( 0, $self->loc('Permission Denied') );
148 $args{'Queue'} = 0; # avoid undef sneaking in
151 my $QueueObj = new RT::Queue( $self->CurrentUser );
152 $QueueObj->Load( $args{'Queue'} );
153 unless ( $QueueObj->id() ) {
154 return ( 0, $self->loc('Invalid queue') );
156 unless ( $QueueObj->CurrentUserHasRight('ModifyScrips') ) {
157 return ( 0, $self->loc('Permission Denied') );
159 $args{'Queue'} = $QueueObj->id();
162 #TODO +++ validate input
164 require RT::ScripAction;
165 my $action = new RT::ScripAction( $self->CurrentUser );
166 if ( $args{'ScripAction'} ) {
167 $action->Load( $args{'ScripAction'} );
169 return ( 0, $self->loc( "Action [_1] not found", $args{'ScripAction'} ) )
172 require RT::Template;
173 my $template = new RT::Template( $self->CurrentUser );
174 if ( $args{'Template'} ) {
175 $template->Load( $args{'Template'} );
177 return ( 0, $self->loc('Template not found') ) unless $template->Id;
179 require RT::ScripCondition;
180 my $condition = new RT::ScripCondition( $self->CurrentUser );
181 if ( $args{'ScripCondition'} ) {
182 $condition->Load( $args{'ScripCondition'} );
184 unless ( $condition->Id ) {
185 return ( 0, $self->loc('Condition not found') );
188 my ( $id, $msg ) = $self->SUPER::Create(
189 Queue => $args{'Queue'},
190 Template => $template->Id,
191 ScripCondition => $condition->id,
192 Stage => $args{'Stage'},
193 ScripAction => $action->Id,
194 Description => $args{'Description'},
195 CustomPrepareCode => $args{'CustomPrepareCode'},
196 CustomCommitCode => $args{'CustomCommitCode'},
197 CustomIsApplicableCode => $args{'CustomIsApplicableCode'},
201 return ( $id, $self->loc('Scrip Created') );
204 return ( $id, $msg );
221 unless ( $self->CurrentUserHasRight('ModifyScrips') ) {
222 return ( 0, $self->loc('Permission Denied') );
225 return ( $self->SUPER::Delete(@_) );
234 Retuns an RT::Queue object with this Scrip\'s queue
241 if ( !$self->{'QueueObj'} ) {
243 $self->{'QueueObj'} = RT::Queue->new( $self->CurrentUser );
244 $self->{'QueueObj'}->Load( $self->__Value('Queue') );
246 return ( $self->{'QueueObj'} );
255 Retuns an RT::Action object with this Scrip\'s Action
262 unless ( defined $self->{'ScripActionObj'} ) {
263 require RT::ScripAction;
265 $self->{'ScripActionObj'} = RT::ScripAction->new( $self->CurrentUser );
267 #TODO: why are we loading Actions with templates like this.
268 # two seperate methods might make more sense
269 $self->{'ScripActionObj'}->Load( $self->ScripAction, $self->Template );
271 return ( $self->{'ScripActionObj'} );
276 # {{{ sub ConditionObj
280 Retuns an RT::ScripCondition object with this Scrip's IsApplicable
287 unless ( defined $self->{'ScripConditionObj'} ) {
288 require RT::ScripCondition;
289 $self->{'ScripConditionObj'} =
290 RT::ScripCondition->new( $self->CurrentUser );
291 if ( $self->ScripCondition ) {
292 $self->{'ScripConditionObj'}->Load( $self->ScripCondition );
295 return ( $self->{'ScripConditionObj'} );
300 # {{{ sub TemplateObj
304 Retuns an RT::Template object with this Scrip\'s Template
311 unless ( defined $self->{'TemplateObj'} ) {
312 require RT::Template;
313 $self->{'TemplateObj'} = RT::Template->new( $self->CurrentUser );
314 $self->{'TemplateObj'}->Load( $self->Template );
316 return ( $self->{'TemplateObj'} );
321 # {{{ Dealing with this instance of a scrip
325 =head2 Apply { TicketObj => undef, TransactionObj => undef}
327 This method instantiates the ScripCondition and ScripAction objects for a
328 single execution of this scrip. it then calls the IsApplicable method of the
330 If that succeeds, it calls the Prepare method of the
331 ScripAction. If that succeeds, it calls the Commit method of the ScripAction.
333 Usually, the ticket and transaction objects passed to this method
334 should be loaded by the SuperUser role
341 my %args = ( TicketObj => undef,
342 TransactionObj => undef,
345 $RT::Logger->debug("Now applying scrip ".$self->Id . " for transaction ".$args{'TransactionObj'}->id);
347 my $ApplicableTransactionObj = $self->IsApplicable( TicketObj => $args{'TicketObj'},
348 TransactionObj => $args{'TransactionObj'} );
349 unless ( $ApplicableTransactionObj ) {
353 if ( $ApplicableTransactionObj->id != $args{'TransactionObj'}->id ) {
354 $RT::Logger->debug("Found an applicable transaction ".$ApplicableTransactionObj->Id . " in the same batch with transaction ".$args{'TransactionObj'}->id);
357 #If it's applicable, prepare and commit it
358 $RT::Logger->debug("Now preparing scrip ".$self->Id . " for transaction ".$ApplicableTransactionObj->id);
359 unless ( $self->Prepare( TicketObj => $args{'TicketObj'},
360 TransactionObj => $ApplicableTransactionObj )
365 $RT::Logger->debug("Now commiting scrip ".$self->Id . " for transaction ".$ApplicableTransactionObj->id);
366 unless ( $self->Commit( TicketObj => $args{'TicketObj'},
367 TransactionObj => $ApplicableTransactionObj)
372 $RT::Logger->debug("We actually finished scrip ".$self->Id . " for transaction ".$ApplicableTransactionObj->id);
379 # {{{ sub IsApplicable
383 Calls the Condition object\'s IsApplicable method
385 Upon success, returns the applicable Transaction object.
386 Otherwise, undef is returned.
388 If the Scrip is in the TransactionCreate Stage (the usual case), only test
389 the associated Transaction object to see if it is applicable.
391 For Scrips in the TransactionBatch Stage, test all Transaction objects
392 created during the Ticket object's lifetime, and returns the first one
399 my %args = ( TicketObj => undef,
400 TransactionObj => undef,
408 if ( $self->Stage eq 'TransactionCreate') {
409 # Only look at our current Transaction
410 @Transactions = ( $args{'TransactionObj'} );
412 elsif ( $self->Stage eq 'TransactionBatch') {
413 # Look at all Transactions in this Batch
414 @Transactions = @{ $args{'TicketObj'}->TransactionBatch || [] };
417 $RT::Logger->error( "Unknown Scrip stage:" . $self->Stage );
421 foreach my $TransactionObj ( @Transactions ) {
422 # Load the scrip's Condition object
423 $self->ConditionObj->LoadCondition(
425 TicketObj => $args{'TicketObj'},
426 TransactionObj => $TransactionObj,
429 if ( $self->ConditionObj->IsApplicable() ) {
430 # We found an application Transaction -- return it
431 $return = $TransactionObj;
437 $RT::Logger->error( "Scrip IsApplicable " . $self->Id . " died. - " . $@ );
451 Calls the action object's prepare method
457 my %args = ( TicketObj => undef,
458 TransactionObj => undef,
463 $self->ActionObj->LoadAction( ScripObj => $self,
464 TicketObj => $args{'TicketObj'},
465 TransactionObj => $args{'TransactionObj'},
468 $return = $self->ActionObj->Prepare();
471 $RT::Logger->error( "Scrip Prepare " . $self->Id . " died. - " . $@ );
485 Calls the action object's commit method
491 my %args = ( TicketObj => undef,
492 TransactionObj => undef,
497 $return = $self->ActionObj->Commit();
500 #Searchbuilder caching isn't perfectly coherent. got to reload the ticket object, since it
502 $args{'TicketObj'}->Load( $args{'TicketObj'}->Id );
505 $RT::Logger->error( "Scrip IsApplicable " . $self->Id . " died. - " . $@ );
509 # Not destroying or weakening hte Action and Condition here could cause a
519 # {{{ ACL related methods
523 # does an acl check and then passes off the call
527 unless ( $self->CurrentUserHasRight('ModifyScrips') ) {
529 "CurrentUser can't modify Scrips for " . $self->Queue . "\n" );
530 return ( 0, $self->loc('Permission Denied') );
532 return $self->__Set(@_);
538 # does an acl check and then passes off the call
542 unless ( $self->CurrentUserHasRight('ShowScrips') ) {
543 $RT::Logger->debug( "CurrentUser can't modify Scrips for "
544 . $self->__Value('Queue')
549 return $self->__Value(@_);
554 # {{{ sub CurrentUserHasRight
556 =head2 CurrentUserHasRight
558 Helper menthod for HasRight. Presets Principal to CurrentUser then
563 sub CurrentUserHasRight {
566 return ( $self->HasRight( Principal => $self->CurrentUser->UserObj,
577 Takes a param-hash consisting of "Right" and "Principal" Principal is
578 an RT::User object or an RT::CurrentUser object. "Right" is a textual
579 Right string that applies to Scrips.
585 my %args = ( Right => undef,
589 if ( ( defined $self->SUPER::_Value('Queue') )
590 and ( $self->SUPER::_Value('Queue') != 0 ) ) {
591 return ( $args{'Principal'}->HasRight( Right => $args{'Right'},
592 Object => $self->QueueObj ) );
596 return ( $args{'Principal'}
597 ->HasRight( Object => $RT::System, Right => $args{'Right'} ) );