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