rt 4.2.14 (#13852)
[freeside.git] / rt / lib / RT / Scrip.pm
1 # BEGIN BPS TAGGED BLOCK {{{
2 #
3 # COPYRIGHT:
4 #
5 # This software is Copyright (c) 1996-2017 Best Practical Solutions, LLC
6 #                                          <sales@bestpractical.com>
7 #
8 # (Except where explicitly superseded by other copyright notices)
9 #
10 #
11 # LICENSE:
12 #
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
16 # from www.gnu.org.
17 #
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.
22 #
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/licenses/old-licenses/gpl-2.0.html.
28 #
29 #
30 # CONTRIBUTION SUBMISSION POLICY:
31 #
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.)
37 #
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.
46 #
47 # END BPS TAGGED BLOCK }}}
48
49 =head1 NAME
50
51   RT::Scrip - an RT Scrip object
52
53 =head1 SYNOPSIS
54
55   use RT::Scrip;
56
57 =head1 DESCRIPTION
58
59
60 =head1 METHODS
61
62
63 =cut
64
65
66 package RT::Scrip;
67
68 use strict;
69 use warnings;
70 use base 'RT::Record';
71
72 use RT::Queue;
73 use RT::Template;
74 use RT::ScripCondition;
75 use RT::ScripAction;
76 use RT::Scrips;
77 use RT::ObjectScrip;
78
79 sub Table {'Scrips'}
80
81 # {{{ sub Create
82
83 =head2 Create
84
85 Creates a new entry in the Scrips table. Takes a paramhash with:
86
87         Queue                  => 0,
88         Description            => undef,
89         Template               => undef,
90         ScripAction            => undef,
91         ScripCondition         => undef,
92         CustomPrepareCode      => undef,
93         CustomCommitCode       => undef,
94         CustomIsApplicableCode => undef,
95
96
97
98
99 Returns (retval, msg);
100 retval is 0 for failure or scrip id.  msg is a textual description of what happened.
101
102 =cut
103
104 sub Create {
105     my $self = shift;
106     my %args = (
107         Queue                  => 0,
108         Template               => undef,                 # name or id
109         ScripAction            => 0,                     # name or id
110         ScripCondition         => 0,                     # name or id
111         Stage                  => 'TransactionCreate',
112         Description            => undef,
113         CustomPrepareCode      => undef,
114         CustomCommitCode       => undef,
115         CustomIsApplicableCode => undef,
116         @_
117     );
118
119     if ($args{CustomPrepareCode} || $args{CustomCommitCode} || $args{CustomIsApplicableCode}) {
120         unless ( $self->CurrentUser->HasRight( Object => $RT::System,
121                                                Right  => 'ExecuteCode' ) )
122         {
123             return ( 0, $self->loc('Permission Denied') );
124         }
125     }
126
127     unless ( $args{'Queue'} ) {
128         unless ( $self->CurrentUser->HasRight( Object => $RT::System,
129                                                Right  => 'ModifyScrips' ) )
130         {
131             return ( 0, $self->loc('Permission Denied') );
132         }
133         $args{'Queue'} = 0;    # avoid undef sneaking in
134     }
135     else {
136         my $QueueObj = RT::Queue->new( $self->CurrentUser );
137         $QueueObj->Load( $args{'Queue'} );
138         unless ( $QueueObj->id ) {
139             return ( 0, $self->loc('Invalid queue') );
140         }
141         unless ( $QueueObj->CurrentUserHasRight('ModifyScrips') ) {
142             return ( 0, $self->loc('Permission Denied') );
143         }
144         $args{'Queue'} = $QueueObj->id;
145     }
146
147     #TODO +++ validate input
148
149     return ( 0, $self->loc("Action is mandatory argument") )
150         unless $args{'ScripAction'};
151     my $action = RT::ScripAction->new( $self->CurrentUser );
152     $action->Load( $args{'ScripAction'} );
153     return ( 0, $self->loc( "Action '[_1]' not found", $args{'ScripAction'} ) ) 
154         unless $action->Id;
155
156     return ( 0, $self->loc("Template is mandatory argument") )
157         unless $args{'Template'};
158     my $template = RT::Template->new( $self->CurrentUser );
159     if ( $args{'Template'} =~ /\D/ ) {
160         $template->LoadByName( Name => $args{'Template'}, Queue => $args{'Queue'} );
161         return ( 0, $self->loc( "Global template '[_1]' not found", $args{'Template'} ) )
162             if !$template->Id && !$args{'Queue'};
163         return ( 0, $self->loc( "Global or queue specific template '[_1]' not found", $args{'Template'} ) )
164             if !$template->Id;
165     } else {
166         $template->Load( $args{'Template'} );
167         return ( 0, $self->loc( "Template '[_1]' not found", $args{'Template'} ) )
168             unless $template->Id;
169
170         return (0, $self->loc( "Template '[_1]' is not global" ))
171             if !$args{'Queue'} && $template->Queue;
172         return (0, $self->loc( "Template '[_1]' is not global nor queue specific" ))
173             if $args{'Queue'} && $template->Queue && $template->Queue != $args{'Queue'};
174     }
175
176     return ( 0, $self->loc("Condition is mandatory argument") )
177         unless $args{'ScripCondition'};
178     my $condition = RT::ScripCondition->new( $self->CurrentUser );
179     $condition->Load( $args{'ScripCondition'} );
180     return ( 0, $self->loc( "Condition '[_1]' not found", $args{'ScripCondition'} ) )
181         unless $condition->Id;
182
183     if ( $args{'Stage'} eq 'Disabled' ) {
184         $RT::Logger->warning("Disabled Stage is deprecated");
185         $args{'Stage'} = 'TransactionCreate';
186         $args{'Disabled'} = 1;
187     }
188     $args{'Disabled'} ||= 0;
189
190     my ( $id, $msg ) = $self->SUPER::Create(
191         Template               => $template->Name,
192         ScripCondition         => $condition->id,
193         ScripAction            => $action->Id,
194         Disabled               => $args{'Disabled'},
195         Description            => $args{'Description'},
196         CustomPrepareCode      => $args{'CustomPrepareCode'},
197         CustomCommitCode       => $args{'CustomCommitCode'},
198         CustomIsApplicableCode => $args{'CustomIsApplicableCode'},
199     );
200     return ( $id, $msg ) unless $id;
201
202     (my $status, $msg) = RT::ObjectScrip->new( $self->CurrentUser )->Add(
203         Scrip    => $self,
204         Stage    => $args{'Stage'},
205         ObjectId => $args{'Queue'},
206     );
207     $RT::Logger->error( "Couldn't add scrip: $msg" ) unless $status;
208
209     return ( $id, $self->loc('Scrip Created') );
210 }
211
212
213
214 =head2 Delete
215
216 Delete this object
217
218 =cut
219
220 sub Delete {
221     my $self = shift;
222
223     unless ( $self->CurrentUserHasRight('ModifyScrips') ) {
224         return ( 0, $self->loc('Permission Denied') );
225     }
226
227     RT::ObjectScrip->new( $self->CurrentUser )->DeleteAll( Scrip => $self );
228
229     return ( $self->SUPER::Delete(@_) );
230 }
231
232 sub IsGlobal { return shift->IsAdded(0) }
233
234 sub IsAdded {
235     my $self = shift;
236     my $record = RT::ObjectScrip->new( $self->CurrentUser );
237     $record->LoadByCols( Scrip => $self->id, ObjectId => shift || 0 );
238     return undef unless $record->id;
239     return $record;
240 }
241
242 sub IsAddedToAny {
243     my $self = shift;
244     my $record = RT::ObjectScrip->new( $self->CurrentUser );
245     $record->LoadByCols( Scrip => $self->id );
246     return $record->id ? 1 : 0;
247 }
248
249 sub AddedTo {
250     my $self = shift;
251     return RT::ObjectScrip->new( $self->CurrentUser )
252         ->AddedTo( Scrip => $self );
253 }
254
255 sub NotAddedTo {
256     my $self = shift;
257     return RT::ObjectScrip->new( $self->CurrentUser )
258         ->NotAddedTo( Scrip => $self );
259 }
260
261 =head2 AddToObject
262
263 Adds (applies) the current scrip to the provided queue (ObjectId).
264
265 Accepts a param hash of:
266
267 =over
268
269 =item C<ObjectId>
270
271 Queue name or id. 0 makes the scrip global.
272
273 =item C<Stage>
274
275 Stage to run in. Valid stages are TransactionCreate or
276 TransactionBatch. Defaults to TransactionCreate. As of RT 4.2, Disabled
277 is no longer a stage.
278
279 =item C<Template>
280
281 Name of global or queue-specific template for the scrip. Use 'Blank' for
282 non-notification scrips.
283
284 =item C<SortOrder>
285
286 Number indicating the relative order the scrip should run in.
287
288 =back
289
290 Returns (val, message). If val is false, the message contains an error
291 message.
292
293 =cut
294
295 sub AddToObject {
296     my $self = shift;
297     my %args = @_%2? (ObjectId => @_) : (@_);
298
299     # Default Stage explicitly rather than in %args assignment to handle
300     # Stage coming in set to undef.
301     $args{'Stage'} //= 'TransactionCreate';
302
303     my $queue;
304     if ( $args{'ObjectId'} ) {
305         $queue = RT::Queue->new( $self->CurrentUser );
306         $queue->Load( $args{'ObjectId'} );
307         return (0, $self->loc('Invalid queue'))
308             unless $queue->id;
309
310         $args{'ObjectId'} = $queue->id;
311     }
312     return ( 0, $self->loc('Permission Denied') )
313         unless $self->CurrentUser->PrincipalObj->HasRight(
314             Object => $queue || $RT::System, Right => 'ModifyScrips',
315         )
316     ;
317
318     my $tname = $self->Template;
319     my $template = RT::Template->new( $self->CurrentUser );
320     $template->LoadByName( Queue => $queue? $queue->id : 0, Name => $tname );
321     unless ( $template->id ) {
322         if ( $queue ) {
323             return (0, $self->loc('No template [_1] in queue [_2] or global',
324                     $tname, $queue->Name||$queue->id));
325         } else {
326             return (0, $self->loc('No global template [_1]', $tname));
327         }
328     }
329
330     my $rec = RT::ObjectScrip->new( $self->CurrentUser );
331     return $rec->Add( %args, Scrip => $self );
332 }
333
334 =head2 RemoveFromObject
335
336 Removes the current scrip to the provided queue (ObjectId).
337
338 Accepts a param hash of:
339
340 =over
341
342 =item C<ObjectId>
343
344 Queue name or id. 0 makes the scrip global.
345
346 =back
347
348 Returns (val, message). If val is false, the message contains an error
349 message.
350
351 =cut
352
353 sub RemoveFromObject {
354     my $self = shift;
355     my %args = @_%2? (ObjectId => @_) : (@_);
356
357     my $queue;
358     if ( $args{'ObjectId'} ) {
359         $queue = RT::Queue->new( $self->CurrentUser );
360         $queue->Load( $args{'ObjectId'} );
361         return (0, $self->loc('Invalid queue id'))
362             unless $queue->id;
363     }
364     return ( 0, $self->loc('Permission Denied') )
365         unless $self->CurrentUser->PrincipalObj->HasRight(
366             Object => $queue || $RT::System, Right => 'ModifyScrips',
367         )
368     ;
369
370     my $rec = RT::ObjectScrip->new( $self->CurrentUser );
371     $rec->LoadByCols( Scrip => $self->id, ObjectId => $args{'ObjectId'} );
372     return (0, $self->loc('Scrip is not added') ) unless $rec->id;
373     return $rec->Delete;
374 }
375
376 =head2 ActionObj
377
378 Retuns an RT::Action object with this Scrip's Action
379
380 =cut
381
382 sub ActionObj {
383     my $self = shift;
384
385     unless ( defined $self->{'ScripActionObj'} ) {
386         require RT::ScripAction;
387         $self->{'ScripActionObj'} = RT::ScripAction->new( $self->CurrentUser );
388         $self->{'ScripActionObj'}->Load( $self->ScripAction );
389     }
390     return ( $self->{'ScripActionObj'} );
391 }
392
393
394
395 =head2 ConditionObj
396
397 Retuns an L<RT::ScripCondition> object with this Scrip's IsApplicable
398
399 =cut
400
401 sub ConditionObj {
402     my $self = shift;
403
404     my $res = RT::ScripCondition->new( $self->CurrentUser );
405     $res->Load( $self->ScripCondition );
406     return $res;
407 }
408
409
410 =head2 LoadModules
411
412 Loads scrip's condition and action modules.
413
414 =cut
415
416 sub LoadModules {
417     my $self = shift;
418
419     $self->ConditionObj->LoadCondition;
420     $self->ActionObj->LoadAction;
421 }
422
423
424 =head2 TemplateObj
425
426 Retuns an RT::Template object with this Scrip's Template
427
428 =cut
429
430 sub TemplateObj {
431     my $self = shift;
432     my $queue = shift;
433
434     my $res = RT::Template->new( $self->CurrentUser );
435     $res->LoadByName( Queue => $queue, Name => $self->Template );
436     return $res;
437 }
438
439 =head2 Stage
440
441 Takes TicketObj named argument and returns scrip's stage when
442 added to ticket's queue.
443
444 =cut
445
446 sub Stage {
447     my $self = shift;
448     my %args = ( TicketObj => undef, @_ );
449
450     my $queue = $args{'TicketObj'}->Queue;
451     my $rec = RT::ObjectScrip->new( $self->CurrentUser );
452     $rec->LoadByCols( Scrip => $self->id, ObjectId => $queue );
453     return $rec->Stage if $rec->id;
454
455     $rec->LoadByCols( Scrip => $self->id, ObjectId => 0 );
456     return $rec->Stage if $rec->id;
457
458     return undef;
459 }
460
461 =head2 FriendlyStage($Stage)
462
463 Helper function that returns a localized human-readable version of the
464 C<$Stage> argument.
465
466 =cut
467
468 sub FriendlyStage {
469     my ( $class, $stage ) = @_;
470     my $stage_i18n_lookup = {
471         TransactionCreate => 'Normal', # loc
472         TransactionBatch => 'Batch', # loc
473         TransactionBatchDisabled => 'Batch (disabled by config)', # loc
474     };
475     $stage = 'TransactionBatchDisabled'
476         if $stage eq 'TransactionBatch'
477             and not RT->Config->Get('UseTransactionBatch');
478     return $stage_i18n_lookup->{$stage};
479 }
480
481 =head2 Apply { TicketObj => undef, TransactionObj => undef}
482
483 This method instantiates the ScripCondition and ScripAction objects for a
484 single execution of this scrip. it then calls the IsApplicable method of the 
485 ScripCondition.
486 If that succeeds, it calls the Prepare method of the
487 ScripAction. If that succeeds, it calls the Commit method of the ScripAction.
488
489 Usually, the ticket and transaction objects passed to this method
490 should be loaded by the SuperUser role
491
492 =cut
493
494
495 # XXX TODO : This code appears to be obsoleted in favor of similar code in Scrips->Apply.
496 # Why is this here? Is it still called?
497
498 sub Apply {
499     my $self = shift;
500     my %args = ( TicketObj      => undef,
501                  TransactionObj => undef,
502                  @_ );
503
504     $RT::Logger->debug("Now applying scrip ".$self->Id . " for transaction ".$args{'TransactionObj'}->id);
505
506     my $ApplicableTransactionObj = $self->IsApplicable( TicketObj      => $args{'TicketObj'},
507                                                         TransactionObj => $args{'TransactionObj'} );
508     unless ( $ApplicableTransactionObj ) {
509         return undef;
510     }
511
512     if ( $ApplicableTransactionObj->id != $args{'TransactionObj'}->id ) {
513         $RT::Logger->debug("Found an applicable transaction ".$ApplicableTransactionObj->Id . " in the same batch with transaction ".$args{'TransactionObj'}->id);
514     }
515
516     #If it's applicable, prepare and commit it
517     $RT::Logger->debug("Now preparing scrip ".$self->Id . " for transaction ".$ApplicableTransactionObj->id);
518     unless ( $self->Prepare( TicketObj      => $args{'TicketObj'},
519                              TransactionObj => $ApplicableTransactionObj )
520       ) {
521         return undef;
522     }
523
524     $RT::Logger->debug("Now commiting scrip ".$self->Id . " for transaction ".$ApplicableTransactionObj->id);
525     unless ( $self->Commit( TicketObj => $args{'TicketObj'},
526                             TransactionObj => $ApplicableTransactionObj)
527       ) {
528         return undef;
529     }
530
531     $RT::Logger->debug("We actually finished scrip ".$self->Id . " for transaction ".$ApplicableTransactionObj->id);
532     return (1);
533
534 }
535
536
537
538 =head2 IsApplicable
539
540 Calls the  Condition object's IsApplicable method
541
542 Upon success, returns the applicable Transaction object.
543 Otherwise, undef is returned.
544
545 If the Scrip is in the TransactionCreate Stage (the usual case), only test
546 the associated Transaction object to see if it is applicable.
547
548 For Scrips in the TransactionBatch Stage, test all Transaction objects
549 created during the Ticket object's lifetime, and returns the first one
550 that is applicable.
551
552 =cut
553
554 sub IsApplicable {
555     my $self = shift;
556     my %args = ( TicketObj      => undef,
557                  TransactionObj => undef,
558                  @_ );
559
560     my $return;
561     eval {
562
563         my @Transactions;
564
565         my $stage = $self->Stage( TicketObj => $args{'TicketObj'} );
566         unless ( $stage ) {
567             $RT::Logger->error(
568                 "Scrip #". $self->id ." is not applied to"
569                 ." queue #". $args{'TicketObj'}->Queue
570             );
571             return (undef);
572         }
573         elsif ( $stage eq 'TransactionCreate') {
574             # Only look at our current Transaction
575             @Transactions = ( $args{'TransactionObj'} );
576         }
577         elsif ( $stage eq 'TransactionBatch') {
578             # Look at all Transactions in this Batch
579             @Transactions = @{ $args{'TicketObj'}->TransactionBatch || [] };
580         }
581         else {
582             $RT::Logger->error( "Unknown Scrip stage: '$stage'" );
583             return (undef);
584         }
585         my $ConditionObj = $self->ConditionObj;
586         foreach my $TransactionObj ( @Transactions ) {
587             # in TxnBatch stage we can select scrips that are not applicable to all txns
588             my $txn_type = $TransactionObj->Type;
589             next unless( $ConditionObj->ApplicableTransTypes =~ /(?:^|,)(?:Any|\Q$txn_type\E)(?:,|$)/i );
590             # Load the scrip's Condition object
591             $ConditionObj->LoadCondition(
592                 ScripObj       => $self,
593                 TicketObj      => $args{'TicketObj'},
594                 TransactionObj => $TransactionObj,
595             );
596
597             if ( $ConditionObj->IsApplicable() ) {
598                 # We found an application Transaction -- return it
599                 $return = $TransactionObj;
600                 last;
601             }
602         }
603     };
604
605     if ($@) {
606         $RT::Logger->error( "Scrip IsApplicable " . $self->Id . " died. - " . $@ );
607         return (undef);
608     }
609
610             return ($return);
611
612 }
613
614
615
616 =head2 Prepare
617
618 Calls the action object's prepare method
619
620 =cut
621
622 sub Prepare {
623     my $self = shift;
624     my %args = ( TicketObj      => undef,
625                  TransactionObj => undef,
626                  @_ );
627
628     my $return;
629     eval {
630         $self->ActionObj->LoadAction(
631             ScripObj       => $self,
632             TicketObj      => $args{'TicketObj'},
633             TransactionObj => $args{'TransactionObj'},
634             TemplateObj    => $self->TemplateObj( $args{'TicketObj'}->Queue ),
635         );
636
637         $return = $self->ActionObj->Prepare();
638     };
639     if ($@) {
640         $RT::Logger->error( "Scrip Prepare " . $self->Id . " died. - " . $@ );
641         return (undef);
642     }
643         unless ($return) {
644         }
645         return ($return);
646 }
647
648
649
650 =head2 Commit
651
652 Calls the action object's commit method
653
654 =cut
655
656 sub Commit {
657     my $self = shift;
658     my %args = ( TicketObj      => undef,
659                  TransactionObj => undef,
660                  @_ );
661
662     my $return;
663     eval {
664         $return = $self->ActionObj->Commit();
665     };
666
667 #Searchbuilder caching isn't perfectly coherent. got to reload the ticket object, since it
668 # may have changed
669     $args{'TicketObj'}->Load( $args{'TicketObj'}->Id );
670
671     if ($@) {
672         $RT::Logger->error( "Scrip Commit " . $self->Id . " died. - " . $@ );
673         return (undef);
674     }
675
676     # Not destroying or weakening hte Action and Condition here could cause a
677     # leak
678
679     return ($return);
680 }
681
682
683
684
685
686 # does an acl check and then passes off the call
687 sub _Set {
688     my $self = shift;
689     my %args = (
690         Field => undef,
691         Value => undef,
692         @_,
693     );
694
695     unless ( $self->CurrentUserHasRight('ModifyScrips') ) {
696         $RT::Logger->debug( "CurrentUser can't modify Scrips" );
697         return ( 0, $self->loc('Permission Denied') );
698     }
699
700
701     if (exists $args{Value}) {
702         if ($args{Field} eq 'CustomIsApplicableCode' || $args{Field} eq 'CustomPrepareCode' || $args{Field} eq 'CustomCommitCode') {
703             unless ( $self->CurrentUser->HasRight( Object => $RT::System,
704                                                    Right  => 'ExecuteCode' ) ) {
705                 return ( 0, $self->loc('Permission Denied') );
706             }
707         }
708         elsif ($args{Field} eq 'Queue') {
709             if ($args{Value}) {
710                 # moving to another queue
711                 my $queue = RT::Queue->new( $self->CurrentUser );
712                 $queue->Load($args{Value});
713                 unless ($queue->Id and $queue->CurrentUserHasRight('ModifyScrips')) {
714                     return ( 0, $self->loc('Permission Denied') );
715                 }
716             } else {
717                 # moving to global
718                 unless ($self->CurrentUser->HasRight( Object => RT->System, Right => 'ModifyScrips' )) {
719                     return ( 0, $self->loc('Permission Denied') );
720                 }
721             }
722         }
723         elsif ($args{Field} eq 'Template') {
724             my $template = RT::Template->new( $self->CurrentUser );
725             $template->Load($args{Value});
726             unless ($template->Id and $template->CurrentUserCanRead) {
727                 return ( 0, $self->loc('Permission Denied') );
728             }
729         }
730     }
731
732     return $self->SUPER::_Set(@_);
733 }
734
735
736 # does an acl check and then passes off the call
737 sub _Value {
738     my $self = shift;
739
740     return unless $self->CurrentUserHasRight('ShowScrips');
741
742     return $self->__Value(@_);
743 }
744
745 =head2 ACLEquivalenceObjects
746
747 Having rights on any of the queues the scrip applies to is equivalent to
748 having rights on the scrip.
749
750 =cut
751
752 sub ACLEquivalenceObjects {
753     my $self = shift;
754     return unless $self->id;
755     return @{ $self->AddedTo->ItemsArrayRef };
756 }
757
758
759
760 =head2 CompileCheck
761
762 This routine compile-checks the custom prepare, commit, and is-applicable code
763 to see if they are syntactically valid Perl. We eval them in a codeblock to
764 avoid actually executing the code.
765
766 If one of the fields has a compile error, only the first is reported.
767
768 Returns an (ok, message) pair.
769
770 =cut
771
772 sub CompileCheck {
773     my $self = shift;
774
775     for my $method (qw/CustomPrepareCode CustomCommitCode CustomIsApplicableCode/) {
776         my $code = $self->$method;
777         next if !defined($code);
778
779         do {
780             no strict 'vars';
781             eval "sub { $code \n }";
782         };
783         next if !$@;
784
785         my $error = $@;
786         return (0, $self->loc("Couldn't compile [_1] codeblock '[_2]': [_3]", $method, $code, $error));
787     }
788 }
789
790
791 =head2 SetScripAction
792
793 =cut
794
795 sub SetScripAction {
796     my $self  = shift;
797     my $value = shift;
798
799     return ( 0, $self->loc("Action is mandatory argument") ) unless $value;
800
801     require RT::ScripAction;
802     my $action = RT::ScripAction->new( $self->CurrentUser );
803     $action->Load($value);
804     return ( 0, $self->loc( "Action '[_1]' not found", $value ) )
805       unless $action->Id;
806
807     return $self->_Set( Field => 'ScripAction', Value => $action->Id );
808 }
809
810 =head2 SetScripCondition
811
812 =cut
813
814 sub SetScripCondition {
815     my $self  = shift;
816     my $value = shift;
817
818     return ( 0, $self->loc("Condition is mandatory argument") )
819       unless $value;
820
821     require RT::ScripCondition;
822     my $condition = RT::ScripCondition->new( $self->CurrentUser );
823     $condition->Load($value);
824
825     return ( 0, $self->loc( "Condition '[_1]' not found", $value ) )
826       unless $condition->Id;
827
828     return $self->_Set( Field => 'ScripCondition', Value => $condition->Id );
829 }
830
831 =head2 SetTemplate
832
833 =cut
834
835 sub SetTemplate {
836     my $self  = shift;
837     my $value = shift;
838
839     return ( 0, $self->loc("Template is mandatory argument") ) unless $value;
840
841     require RT::Template;
842     my $template = RT::Template->new( $self->CurrentUser );
843     $template->Load($value);
844     return ( 0, $self->loc( "Template '[_1]' not found", $value ) )
845       unless $template->Id;
846
847     return $self->_Set( Field => 'Template', Value => $template->Name );
848 }
849
850 1;
851
852
853
854
855
856
857 =head2 id
858
859 Returns the current value of id.
860 (In the database, id is stored as int(11).)
861
862
863 =cut
864
865
866 =head2 Description
867
868 Returns the current value of Description.
869 (In the database, Description is stored as varchar(255).)
870
871
872
873 =head2 SetDescription VALUE
874
875
876 Set Description to VALUE.
877 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
878 (In the database, Description will be stored as a varchar(255).)
879
880
881 =cut
882
883
884 =head2 ScripCondition
885
886 Returns the current value of ScripCondition.
887 (In the database, ScripCondition is stored as int(11).)
888
889
890
891 =head2 SetScripCondition VALUE
892
893
894 Set ScripCondition to VALUE.
895 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
896 (In the database, ScripCondition will be stored as a int(11).)
897
898
899 =cut
900
901
902 =head2 ScripConditionObj
903
904 Returns the ScripCondition Object which has the id returned by ScripCondition
905
906
907 =cut
908
909 sub ScripConditionObj {
910         my $self = shift;
911         my $ScripCondition =  RT::ScripCondition->new($self->CurrentUser);
912         $ScripCondition->Load($self->__Value('ScripCondition'));
913         return($ScripCondition);
914 }
915
916 =head2 ScripAction
917
918 Returns the current value of ScripAction.
919 (In the database, ScripAction is stored as int(11).)
920
921
922
923 =head2 SetScripAction VALUE
924
925
926 Set ScripAction to VALUE.
927 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
928 (In the database, ScripAction will be stored as a int(11).)
929
930
931 =cut
932
933
934 =head2 ScripActionObj
935
936 Returns the ScripAction Object which has the id returned by ScripAction
937
938
939 =cut
940
941 sub ScripActionObj {
942         my $self = shift;
943         my $ScripAction =  RT::ScripAction->new($self->CurrentUser);
944         $ScripAction->Load($self->__Value('ScripAction'));
945         return($ScripAction);
946 }
947
948 =head2 CustomIsApplicableCode
949
950 Returns the current value of CustomIsApplicableCode.
951 (In the database, CustomIsApplicableCode is stored as text.)
952
953
954
955 =head2 SetCustomIsApplicableCode VALUE
956
957
958 Set CustomIsApplicableCode to VALUE.
959 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
960 (In the database, CustomIsApplicableCode will be stored as a text.)
961
962
963 =cut
964
965
966 =head2 CustomPrepareCode
967
968 Returns the current value of CustomPrepareCode.
969 (In the database, CustomPrepareCode is stored as text.)
970
971
972
973 =head2 SetCustomPrepareCode VALUE
974
975
976 Set CustomPrepareCode to VALUE.
977 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
978 (In the database, CustomPrepareCode will be stored as a text.)
979
980
981 =cut
982
983
984 =head2 CustomCommitCode
985
986 Returns the current value of CustomCommitCode.
987 (In the database, CustomCommitCode is stored as text.)
988
989
990
991 =head2 SetCustomCommitCode VALUE
992
993
994 Set CustomCommitCode to VALUE.
995 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
996 (In the database, CustomCommitCode will be stored as a text.)
997
998
999 =cut
1000
1001
1002 =head2 Disabled
1003
1004 Returns the current value of Disabled.
1005 (In the database, Disabled is stored as smallint(6).)
1006
1007
1008
1009 =head2 SetDisabled VALUE
1010
1011
1012 Set Disabled to VALUE.
1013 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1014 (In the database, Disabled will be stored as a smallint(6).)
1015
1016
1017 =cut
1018
1019
1020 =head2 Template
1021
1022 Returns the current value of Template.
1023 (In the database, Template is stored as varchar(200).)
1024
1025
1026
1027 =head2 SetTemplate VALUE
1028
1029
1030 Set Template to VALUE.
1031 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
1032 (In the database, Template will be stored as a varchar(200).)
1033
1034
1035 =cut
1036
1037
1038 =head2 Creator
1039
1040 Returns the current value of Creator.
1041 (In the database, Creator is stored as int(11).)
1042
1043
1044 =cut
1045
1046
1047 =head2 Created
1048
1049 Returns the current value of Created.
1050 (In the database, Created is stored as datetime.)
1051
1052
1053 =cut
1054
1055
1056 =head2 LastUpdatedBy
1057
1058 Returns the current value of LastUpdatedBy.
1059 (In the database, LastUpdatedBy is stored as int(11).)
1060
1061
1062 =cut
1063
1064
1065 =head2 LastUpdated
1066
1067 Returns the current value of LastUpdated.
1068 (In the database, LastUpdated is stored as datetime.)
1069
1070
1071 =cut
1072
1073
1074
1075 sub _CoreAccessible {
1076     {
1077
1078         id =>
1079                 {read => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
1080         Description =>
1081                 {read => 1, write => 1, sql_type => 12, length => 255,  is_blob => 0,  is_numeric => 0,  type => 'varchar(255)', default => ''},
1082         ScripCondition =>
1083                 {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
1084         ScripAction =>
1085                 {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
1086         CustomIsApplicableCode =>
1087                 {read => 1, write => 1, sql_type => -4, length => 0,  is_blob => 1,  is_numeric => 0,  type => 'text', default => ''},
1088         CustomPrepareCode =>
1089                 {read => 1, write => 1, sql_type => -4, length => 0,  is_blob => 1,  is_numeric => 0,  type => 'text', default => ''},
1090         CustomCommitCode =>
1091                 {read => 1, write => 1, sql_type => -4, length => 0,  is_blob => 1,  is_numeric => 0,  type => 'text', default => ''},
1092         Disabled =>
1093                 {read => 1, write => 1, sql_type => 5, length => 6,  is_blob => 0,  is_numeric => 1,  type => 'smallint(6)', default => '0'},
1094         Template =>
1095                 {read => 1, write => 1, sql_type => 12, length => 200,  is_blob => 0,  is_numeric => 0,  type => 'varchar(200)', default => 'Blank'},
1096         Creator =>
1097                 {read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
1098         Created =>
1099                 {read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
1100         LastUpdatedBy =>
1101                 {read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
1102         LastUpdated =>
1103                 {read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
1104
1105  }
1106 };
1107
1108 sub FindDependencies {
1109     my $self = shift;
1110     my ($walker, $deps) = @_;
1111
1112     $self->SUPER::FindDependencies($walker, $deps);
1113
1114     my $applied = RT::ObjectScrips->new( $self->CurrentUser );
1115     $applied->LimitToScrip( $self->id );
1116     $deps->Add( in => $applied );
1117
1118     $deps->Add( out => $self->ScripConditionObj );
1119     $deps->Add( out => $self->ScripActionObj );
1120     $deps->Add( out => $self->TemplateObj );
1121 }
1122
1123 sub __DependsOn {
1124     my $self = shift;
1125     my %args = (
1126         Shredder => undef,
1127         Dependencies => undef,
1128         @_,
1129     );
1130     my $deps = $args{'Dependencies'};
1131     my $list = [];
1132
1133     my $objs = RT::ObjectScrips->new( $self->CurrentUser );
1134     $objs->LimitToScrip( $self->Id );
1135     push @$list, $objs;
1136
1137     $deps->_PushDependencies(
1138         BaseObject    => $self,
1139         Flags         => RT::Shredder::Constants::DEPENDS_ON,
1140         TargetObjects => $list,
1141         Shredder      => $args{'Shredder'}
1142     );
1143
1144     return $self->SUPER::__DependsOn( %args );
1145 }
1146
1147 sub Serialize {
1148     my $self = shift;
1149     my %args = (@_);
1150     my %store = $self->SUPER::Serialize(@_);
1151
1152     # Store the string, not a reference to the object
1153     $store{Template} = $self->Template;
1154
1155     return %store;
1156 }
1157
1158 RT::Base->_ImportOverlays();
1159
1160 1;