Upgrade to 4.0.8 with mod of ExternalAuth + absolute paths to ticket-menu.
[usit-rt.git] / lib / RT / Scrips.pm
CommitLineData
84fb5b46
MKG
1# BEGIN BPS TAGGED BLOCK {{{
2#
3# COPYRIGHT:
4#
5# This software is Copyright (c) 1996-2012 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::Scrips - a collection of RT Scrip objects
52
53=head1 SYNOPSIS
54
55 use RT::Scrips;
56
57=head1 DESCRIPTION
58
59
60=head1 METHODS
61
62
63
64=cut
65
66
67package RT::Scrips;
68
69use strict;
70use warnings;
71
72use RT::Scrip;
73
74use base 'RT::SearchBuilder';
75
76sub Table { 'Scrips'}
77
78
79=head2 LimitToQueue
80
81Takes a queue id (numerical) as its only argument. Makes sure that
82Scopes it pulls out apply to this queue (or another that you've selected with
83another call to this method
84
85=cut
86
87sub LimitToQueue {
88 my $self = shift;
89 my $queue = shift;
90
91 $self->Limit (ENTRYAGGREGATOR => 'OR',
92 FIELD => 'Queue',
93 VALUE => "$queue")
94 if defined $queue;
95
96}
97
98
99=head2 LimitToGlobal
100
101Makes sure that
102Scopes it pulls out apply to all queues (or another that you've selected with
103another call to this method or LimitToQueue
104
105=cut
106
107
108sub LimitToGlobal {
109 my $self = shift;
110
111 $self->Limit (ENTRYAGGREGATOR => 'OR',
112 FIELD => 'Queue',
113 VALUE => 0);
114
115}
116
117# {{{ sub Next
118
119=head2 Next
120
121Returns the next scrip that this user can see.
122
123=cut
124
125sub Next {
126 my $self = shift;
127
128
129 my $Scrip = $self->SUPER::Next();
130 if ((defined($Scrip)) and (ref($Scrip))) {
131
132 if ($Scrip->CurrentUserHasRight('ShowScrips')) {
133 return($Scrip);
134 }
135
136 #If the user doesn't have the right to show this scrip
137 else {
138 return($self->Next());
139 }
140 }
141 #if there never was any scrip
142 else {
143 return(undef);
144 }
145
146}
147
148=head2 Apply
149
150Run through the relevant scrips. Scrips will run in order based on
151description. (Most common use case is to prepend a number to the description,
152forcing the scrips to run in ascending alphanumerical order.)
153
154=cut
155
156sub Apply {
157 my $self = shift;
158
159 my %args = ( TicketObj => undef,
160 Ticket => undef,
161 Transaction => undef,
162 TransactionObj => undef,
163 Stage => undef,
164 Type => undef,
165 @_ );
166
167 $self->Prepare(%args);
168 $self->Commit();
169
170}
171
172=head2 Commit
173
174Commit all of this object's prepared scrips
175
176=cut
177
178sub Commit {
179 my $self = shift;
180
84fb5b46
MKG
181 foreach my $scrip (@{$self->Prepared}) {
182 $RT::Logger->debug(
183 "Committing scrip #". $scrip->id
184 ." on txn #". $self->{'TransactionObj'}->id
185 ." of ticket #". $self->{'TicketObj'}->id
186 );
187
188 $scrip->Commit( TicketObj => $self->{'TicketObj'},
189 TransactionObj => $self->{'TransactionObj'} );
190 }
191
84fb5b46
MKG
192}
193
194
195=head2 Prepare
196
197Only prepare the scrips, returning an array of the scrips we're interested in
198in order of preparation, not execution
199
200=cut
201
202sub Prepare {
203 my $self = shift;
204 my %args = ( TicketObj => undef,
205 Ticket => undef,
206 Transaction => undef,
207 TransactionObj => undef,
208 Stage => undef,
209 Type => undef,
210 @_ );
211
84fb5b46
MKG
212 #We're really going to need a non-acled ticket for the scrips to work
213 $self->_SetupSourceObjects( TicketObj => $args{'TicketObj'},
214 Ticket => $args{'Ticket'},
215 TransactionObj => $args{'TransactionObj'},
216 Transaction => $args{'Transaction'} );
217
218
219 $self->_FindScrips( Stage => $args{'Stage'}, Type => $args{'Type'} );
220
221
222 #Iterate through each script and check it's applicability.
223 while ( my $scrip = $self->Next() ) {
224
225 unless ( $scrip->IsApplicable(
226 TicketObj => $self->{'TicketObj'},
227 TransactionObj => $self->{'TransactionObj'}
228 ) ) {
229 $RT::Logger->debug("Skipping Scrip #".$scrip->Id." because it isn't applicable");
230 next;
231 }
232
233 #If it's applicable, prepare and commit it
234 unless ( $scrip->Prepare( TicketObj => $self->{'TicketObj'},
235 TransactionObj => $self->{'TransactionObj'}
236 ) ) {
237 $RT::Logger->debug("Skipping Scrip #".$scrip->Id." because it didn't Prepare");
238 next;
239 }
240 push @{$self->{'prepared_scrips'}}, $scrip;
241
242 }
243
84fb5b46
MKG
244 return (@{$self->Prepared});
245
246};
247
248=head2 Prepared
249
250Returns an arrayref of the scrips this object has prepared
251
252
253=cut
254
255sub Prepared {
256 my $self = shift;
257 return ($self->{'prepared_scrips'} || []);
258}
259
84fb5b46
MKG
260=head2 _SetupSourceObjects { TicketObj , Ticket, Transaction, TransactionObj }
261
262Setup a ticket and transaction for this Scrip collection to work with as it runs through the
263relevant scrips. (Also to figure out which scrips apply)
264
265Returns: nothing
266
267=cut
268
269
270sub _SetupSourceObjects {
271
272 my $self = shift;
273 my %args = (
274 TicketObj => undef,
275 Ticket => undef,
276 Transaction => undef,
277 TransactionObj => undef,
278 @_ );
279
280
dab09ea8
MKG
281 if ( $args{'TicketObj'} ) {
282 # This loads a clean copy of the Ticket object to ensure that we
283 # don't accidentally escalate the privileges of the passed in
284 # ticket (this function can be invoked from the UI).
285 # We copy the TransactionBatch transactions so that Scrips
286 # running against the new Ticket will have access to them. We
287 # use RanTransactionBatch to guard against running
288 # TransactionBatch Scrips more than once.
289 $self->{'TicketObj'} = RT::Ticket->new( $self->CurrentUser );
290 $self->{'TicketObj'}->Load( $args{'TicketObj'}->Id );
291 if ( $args{'TicketObj'}->TransactionBatch ) {
292 # try to ensure that we won't infinite loop if something dies, triggering DESTROY while
293 # we have the _TransactionBatch objects;
294 $self->{'TicketObj'}->RanTransactionBatch(1);
295 $self->{'TicketObj'}->{'_TransactionBatch'} = $args{'TicketObj'}->{'_TransactionBatch'};
296 }
84fb5b46
MKG
297 }
298 else {
299 $self->{'TicketObj'} = RT::Ticket->new( $self->CurrentUser );
300 $self->{'TicketObj'}->Load( $args{'Ticket'} )
301 || $RT::Logger->err("$self couldn't load ticket $args{'Ticket'}");
302 }
303
304 if ( ( $self->{'TransactionObj'} = $args{'TransactionObj'} ) ) {
305 $self->{'TransactionObj'}->CurrentUser( $self->CurrentUser );
306 }
307 else {
308 $self->{'TransactionObj'} = RT::Transaction->new( $self->CurrentUser );
309 $self->{'TransactionObj'}->Load( $args{'Transaction'} )
310 || $RT::Logger->err( "$self couldn't load transaction $args{'Transaction'}");
311 }
312}
313
314
315
316=head2 _FindScrips
317
318Find only the apropriate scrips for whatever we're doing now. Order them
319by their description. (Most common use case is to prepend a number to the
320description, forcing the scrips to display and run in ascending alphanumerical
321order.)
322
323=cut
324
325sub _FindScrips {
326 my $self = shift;
327 my %args = (
328 Stage => undef,
329 Type => undef,
330 @_ );
331
332
333 $self->LimitToQueue( $self->{'TicketObj'}->QueueObj->Id )
334 ; #Limit it to $Ticket->QueueObj->Id
335 $self->LimitToGlobal();
336 # or to "global"
337
338 $self->Limit( FIELD => "Stage", VALUE => $args{'Stage'} );
339
340 my $ConditionsAlias = $self->NewAlias('ScripConditions');
341
342 $self->Join(
343 ALIAS1 => 'main',
344 FIELD1 => 'ScripCondition',
345 ALIAS2 => $ConditionsAlias,
346 FIELD2 => 'id'
347 );
348
349 #We only want things where the scrip applies to this sort of transaction
350 # TransactionBatch stage can define list of transaction
351 foreach( split /\s*,\s*/, ($args{'Type'} || '') ) {
352 $self->Limit(
353 ALIAS => $ConditionsAlias,
354 FIELD => 'ApplicableTransTypes',
355 OPERATOR => 'LIKE',
356 VALUE => $_,
357 ENTRYAGGREGATOR => 'OR',
358 )
359 }
360
361 # Or where the scrip applies to any transaction
362 $self->Limit(
363 ALIAS => $ConditionsAlias,
364 FIELD => 'ApplicableTransTypes',
365 OPERATOR => 'LIKE',
366 VALUE => "Any",
367 ENTRYAGGREGATOR => 'OR',
368 );
369
370 # Promise some kind of ordering
371 $self->OrderBy( FIELD => 'Description' );
372
373 # we call Count below, but later we always do search
374 # so just do search and get count from results
375 $self->_DoSearch if $self->{'must_redo_search'};
376
377 $RT::Logger->debug(
378 "Found ". $self->Count ." scrips for $args{'Stage'} stage"
379 ." with applicable type(s) $args{'Type'}"
380 ." for txn #".$self->{TransactionObj}->Id
381 ." on ticket #".$self->{TicketObj}->Id
382 );
383}
384
385
386
387
388=head2 NewItem
389
390Returns an empty new RT::Scrip item
391
392=cut
393
394sub NewItem {
395 my $self = shift;
396 return(RT::Scrip->new($self->CurrentUser));
397}
398RT::Base->_ImportOverlays();
399
4001;