3 # Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
5 # (Except where explictly superceded by other copyright notices)
7 # This work is made available to you under the terms of Version 2 of
8 # the GNU General Public License. A copy of that license should have
9 # been provided with this software, but in any event can be snarfed
12 # This work is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # General Public License for more details.
17 # Unless otherwise specified, all modifications, corrections or
18 # extensions to this work which alter its source code become the
19 # property of Best Practical Solutions, LLC when submitted for
20 # inclusion in the work.
26 RT::Scrip - an RT Scrip object
39 ok (require RT::Scrip);
42 my $q = RT::Queue->new($RT::SystemUser);
43 $q->Create(Name => 'ScripTest');
44 ok($q->Id, "Created a scriptest queue");
46 my $s1 = RT::Scrip->new($RT::SystemUser);
47 my ($val, $msg) =$s1->Create( Queue => $q->Id,
48 ScripAction => 'User Defined',
49 ScripCondition => 'User Defined',
50 CustomIsApplicableCode => 'if ($self->TicketObj->Subject =~ /fire/) { return (1);} else { return(0)}',
51 CustomPrepareCode => 'return 1',
52 CustomCommitCode => '$self->TicketObj->SetPriority("87");',
57 my $ticket = RT::Ticket->new($RT::SystemUser);
58 my ($tv,$ttv,$tm) = $ticket->Create(Queue => $q->Id,
59 Subject => "hair on fire",
63 ok ($ticket->Priority == '87', "Ticket priority is set right");
66 my $ticket2 = RT::Ticket->new($RT::SystemUser);
67 my ($t2v,$t2tv,$t2m) = $ticket2->Create(Queue => $q->Id,
68 Subject => "hair in water",
72 ok ($ticket2->Priority != '87', "Ticket priority is set right");
80 no warnings qw(redefine);
87 Creates a new entry in the Scrips table. Takes a paramhash with:
93 ScripCondition => undef,
94 CustomPrepareCode => undef,
95 CustomCommitCode => undef,
96 CustomIsApplicableCode => undef,
101 Returns (retval, msg);
102 retval is 0 for failure or scrip id. msg is a textual description of what happened.
110 Template => 0, # name or id
111 ScripAction => 0, # name or id
112 ScripCondition => 0, # name or id
113 Stage => 'TransactionCreate',
114 Description => undef,
115 CustomPrepareCode => undef,
116 CustomCommitCode => undef,
117 CustomIsApplicableCode => undef,
123 if (! $args{'Queue'} ) {
124 unless ( $self->CurrentUser->HasRight( Object => $RT::System, Right => 'ModifyScrips') ) {
125 return ( 0, $self->loc('Permission Denied') );
127 $args{'Queue'} = 0; # avoid undef sneaking in
130 my $QueueObj = new RT::Queue( $self->CurrentUser );
131 $QueueObj->Load( $args{'Queue'} );
132 unless ( $QueueObj->id() ) {
133 return ( 0, $self->loc('Invalid queue') );
135 unless ( $QueueObj->CurrentUserHasRight('ModifyScrips') ) {
136 return ( 0, $self->loc('Permission Denied') );
138 $args{'Queue'} = $QueueObj->id();
141 #TODO +++ validate input
143 require RT::ScripAction;
144 my $action = new RT::ScripAction( $self->CurrentUser );
145 if ($args{'ScripAction'}) {
146 $action->Load( $args{'ScripAction'});
148 return ( 0, $self->loc( "Action [_1] not found", $args{'ScripAction'} ) )
151 require RT::Template;
152 my $template = new RT::Template( $self->CurrentUser );
153 if ($args{'Template'} ) {
154 $template->Load( $args{'Template'});
156 return ( 0, $self->loc('Template not found') ) unless $template->Id;
158 require RT::ScripCondition;
159 my $condition = new RT::ScripCondition( $self->CurrentUser );
160 if ($args{'ScripCondition'} ) {
161 $condition->Load( $args{'ScripCondition'} );
163 unless ( $condition->Id ) {
164 return ( 0, $self->loc('Condition not found') );
167 my ($id,$msg) = $self->SUPER::Create(
168 Queue => $args{'Queue'},
169 Template => $template->Id,
170 ScripCondition => $condition->id,
171 Stage => $args{'Stage'},
172 ScripAction => $action->Id,
173 Description => $args{'Description'},
174 CustomPrepareCode => $args{'CustomPrepareCode'},
175 CustomCommitCode => $args{'CustomCommitCode'},
176 CustomIsApplicableCode => $args{'CustomIsApplicableCode'},
180 return ( $id, $self->loc('Scrip Created') );
200 unless ($self->CurrentUserHasRight('ModifyScrips')) {
201 return (0, $self->loc('Permission Denied'));
204 return ($self->SUPER::Delete(@_));
212 Retuns an RT::Queue object with this Scrip\'s queue
219 if (!$self->{'QueueObj'}) {
221 $self->{'QueueObj'} = RT::Queue->new($self->CurrentUser);
222 $self->{'QueueObj'}->Load($self->__Value('Queue'));
224 return ($self->{'QueueObj'});
234 Retuns an RT::Action object with this Scrip\'s Action
241 unless (defined $self->{'ScripActionObj'}) {
242 require RT::ScripAction;
244 $self->{'ScripActionObj'} = RT::ScripAction->new($self->CurrentUser);
245 #TODO: why are we loading Actions with templates like this.
246 # two separate methods might make more sense
247 $self->{'ScripActionObj'}->Load($self->ScripAction, $self->Template);
249 return ($self->{'ScripActionObj'});
254 # {{{ sub ConditionObj
258 Retuns an RT::ScripCondition object with this Scrip's IsApplicable
265 unless ( defined $self->{'ScripConditionObj'} ) {
266 require RT::ScripCondition;
267 $self->{'ScripConditionObj'} =
268 RT::ScripCondition->new( $self->CurrentUser );
269 if ( $self->ScripCondition ) {
270 $self->{'ScripConditionObj'}->Load( $self->ScripCondition );
273 return ( $self->{'ScripConditionObj'} );
278 # {{{ sub TemplateObj
281 Retuns an RT::Template object with this Scrip\'s Template
288 unless (defined $self->{'TemplateObj'}) {
289 require RT::Template;
290 $self->{'TemplateObj'} = RT::Template->new($self->CurrentUser);
291 $self->{'TemplateObj'}->Load($self->Template);
293 return ($self->{'TemplateObj'});
299 # {{{ Dealing with this instance of a scrip
301 =head2 Apply { TicketObj => undef, TransactionObj => undef}
303 This method instantiates the ScripCondition and ScripAction objects for a
304 single execution of this scrip. it then calls the IsApplicable method of the
306 If that succeeds, it calls the Prepare method of the
307 ScripAction. If that succeeds, it calls the Commit method of the ScripAction.
309 Usually, the ticket and transaction objects passed to this method
310 should be loaded by the SuperUser role
319 my %args = ( TicketObj => undef,
320 TransactionObj => undef,
323 # We want to make sure that if a scrip dies, we don't get
327 #Load the scrip's Condition object
328 $self->ConditionObj->LoadCondition(
330 TicketObj => $args{'TicketObj'},
331 TransactionObj => $args{'TransactionObj'},
334 unless ( $self->IsApplicable() ) {
335 $self->ConditionObj->DESTROY;
339 #If it's applicable, prepare and commit it
340 $self->ActionObj->LoadAction( ScripObj => $self,
341 TicketObj => $args{'TicketObj'},
342 TransactionObj => $args{'TransactionObj'},
345 unless ( $self->Prepare() ) {
347 "$self: Couldn't prepare " . $self->ActionObj->Name );
348 $self->ActionObj->DESTROY();
349 $self->ConditionObj->DESTROY();
352 unless ( $self->Commit() ) {
354 "$self: Couldn't commit " . $self->ActionObj->Name );
355 $self->ActionObj->DESTROY();
356 $self->ConditionObj->DESTROY();
360 #Searchbuilder caching isn't perfectly coherent. got to reload the ticket object, since it
362 $args{'TicketObj'}->Load($args{'TicketObj'}->Id);
364 #We're done with it. lets clean up.
365 #TODO: something else isn't letting these get garbage collected. check em out.
366 $self->ActionObj->DESTROY();
367 $self->ConditionObj->DESTROY();
371 $RT::Logger->error( "Scrip " . $self->Id . " died. - " . $@ );
377 # {{{ sub IsApplicable
381 Calls the Condition object\'s IsApplicable method
387 return ($self->ConditionObj->IsApplicable(@_));
396 Calls the action object's prepare method
402 $self->ActionObj->Prepare(@_);
411 Calls the action object's commit method
417 $self->ActionObj->Commit(@_);
427 $self->{'ActionObj'} = undef;
431 # {{{ ACL related methods
435 # does an acl check and then passes off the call
439 unless ($self->CurrentUserHasRight('ModifyScrips')) {
440 $RT::Logger->debug("CurrentUser can't modify Scrips for ".$self->Queue."\n");
441 return (0, $self->loc('Permission Denied'));
443 return $self->__Set(@_);
449 # does an acl check and then passes off the call
453 unless ($self->CurrentUserHasRight('ShowScrips')) {
454 $RT::Logger->debug("CurrentUser can't modify Scrips for ".$self->__Value('Queue')."\n");
458 return $self->__Value(@_);
462 # {{{ sub CurrentUserHasRight
464 =head2 CurrentUserHasRight
466 Helper menthod for HasRight. Presets Principal to CurrentUser then
471 sub CurrentUserHasRight {
474 return ($self->HasRight( Principal => $self->CurrentUser->UserObj,
485 Takes a param-hash consisting of "Right" and "Principal" Principal is
486 an RT::User object or an RT::CurrentUser object. "Right" is a textual
487 Right string that applies to Scrips.
493 my %args = ( Right => undef,
497 if ((defined $self->SUPER::_Value('Queue')) and ($self->SUPER::_Value('Queue') != 0)) {
498 return ( $args{'Principal'}->HasRight(
499 Right => $args{'Right'},
500 Object => $self->QueueObj
506 return( $args{'Principal'}->HasRight( Object => $RT::System, Right => $args{'Right'}) );