diff options
author | ivan <ivan> | 2009-12-31 13:16:41 +0000 |
---|---|---|
committer | ivan <ivan> | 2009-12-31 13:16:41 +0000 |
commit | 63a268637b2d51a8766412617724b9436439deb6 (patch) | |
tree | a50f6d4c7829d5c80905e989144317192a44dc90 /rt/lib/RT/Action | |
parent | 65a561e3cd8c1ba94f6282f5d2a1cd9783afbd21 (diff) | |
parent | b4b0c7e72d7eaee2fbfc7022022c9698323203dd (diff) |
This commit was generated by cvs2svn to compensate for changes in r8690,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'rt/lib/RT/Action')
-rw-r--r-- | rt/lib/RT/Action/AutoOpen.pm | 52 | ||||
-rw-r--r-- | rt/lib/RT/Action/CreateTickets.pm | 265 | ||||
-rw-r--r-- | rt/lib/RT/Action/EscalatePriority.pm | 11 | ||||
-rw-r--r-- | rt/lib/RT/Action/ExtractSubjectTag.pm | 103 | ||||
-rwxr-xr-x | rt/lib/RT/Action/LinearEscalate.pm | 279 | ||||
-rw-r--r-- | rt/lib/RT/Action/NotifyGroup.pm | 209 | ||||
-rw-r--r-- | rt/lib/RT/Action/NotifyGroupAsComment.pm | 91 | ||||
-rw-r--r-- | rt/lib/RT/Action/RecordComment.pm | 9 | ||||
-rw-r--r-- | rt/lib/RT/Action/RecordCorrespondence.pm | 9 | ||||
-rw-r--r-- | rt/lib/RT/Action/SetPriority.pm | 9 | ||||
-rw-r--r-- | rt/lib/RT/Action/UserDefined.pm | 9 |
11 files changed, 744 insertions, 302 deletions
diff --git a/rt/lib/RT/Action/AutoOpen.pm b/rt/lib/RT/Action/AutoOpen.pm index 004ed13cc..e1cf0ae7c 100644 --- a/rt/lib/RT/Action/AutoOpen.pm +++ b/rt/lib/RT/Action/AutoOpen.pm @@ -1,8 +1,8 @@ # BEGIN BPS TAGGED BLOCK {{{ # # COPYRIGHT: -# -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC # <jesse@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -45,28 +45,25 @@ # those contributions and any derivatives thereof. # # END BPS TAGGED BLOCK }}} -# This Action will open the BASE if a dependent is resolved. +# This Action will open the BASE if a dependent is resolved. package RT::Action::AutoOpen; -require RT::Action::Generic; use strict; -use vars qw/@ISA/; -@ISA=qw(RT::Action::Generic); +use warnings; -#Do what we need to do and send it out. +use base qw(RT::Action); -#What does this type of Action does +=head1 DESCRIPTION -# {{{ sub Describe -sub Describe { - my $self = shift; - return (ref $self ); -} -# }}} +Opens a ticket unless it's allready open, but only unless transaction +L<RT::Transaction/IsInbound is inbound>. +Doesn't open a ticket if message's head has field C<RT-Control> with +C<no-autoopen> substring. + +=cut -# {{{ sub Prepare sub Prepare { my $self = shift; @@ -83,22 +80,21 @@ sub Prepare { return 1; } -# }}} sub Commit { my $self = shift; - my $oldstatus = $self->TicketObj->Status(); - $self->TicketObj->__Set( Field => 'Status', Value => 'open' ); - $self->TicketObj->_NewTransaction( - Type => 'Status', - Field => 'Status', - OldValue => $oldstatus, - NewValue => 'open', - Data => 'Ticket auto-opened on incoming correspondence' - ); - - - return(1); + + my $oldstatus = $self->TicketObj->Status; + $self->TicketObj->__Set( Field => 'Status', Value => 'open' ); + $self->TicketObj->_NewTransaction( + Type => 'Status', + Field => 'Status', + OldValue => $oldstatus, + NewValue => 'open', + Data => 'Ticket auto-opened on incoming correspondence' + ); + + return 1; } eval "require RT::Action::AutoOpen_Vendor"; diff --git a/rt/lib/RT/Action/CreateTickets.pm b/rt/lib/RT/Action/CreateTickets.pm index 40d18d357..4883ae3a8 100644 --- a/rt/lib/RT/Action/CreateTickets.pm +++ b/rt/lib/RT/Action/CreateTickets.pm @@ -1,8 +1,8 @@ # BEGIN BPS TAGGED BLOCK {{{ # # COPYRIGHT: -# -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC # <jesse@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -45,13 +45,12 @@ # those contributions and any derivatives thereof. # # END BPS TAGGED BLOCK }}} + package RT::Action::CreateTickets; -require RT::Action::Generic; +use base 'RT::Action'; use strict; use warnings; -use vars qw/@ISA/; -@ISA = qw(RT::Action::Generic); use MIME::Entity; @@ -106,10 +105,12 @@ of perl inside the Text::Template using {} delimiters, but that such sections absolutely can not span a ===Create-Ticket boundary. After each ticket is created, it's stuffed into a hash called %Tickets -so as to be available during the creation of other tickets during the same -ScripAction. The hash is prepopulated with the ticket which triggered the -ScripAction as $Tickets{'TOP'}; you can also access that ticket using the -shorthand TOP. +so as to be available during the creation of other tickets during the +same ScripAction, using the key 'create-identifier', where +C<identifier> is the id you put after C<===Create-Ticket:>. The hash +is prepopulated with the ticket which triggered the ScripAction as +$Tickets{'TOP'}; you can also access that ticket using the shorthand +TOP. A simple example: @@ -164,8 +165,9 @@ A convoluted example ENDOFCONTENT ===Create-Ticket: two Subject: Manager approval + Type: approval Depended-On-By: TOP - Refers-On: {$Tickets{"approval"}->Id} + Refers-To: {$Tickets{"create-approval"}->Id} Queue: ___Approvals Content-Type: text/plain Content: @@ -236,236 +238,6 @@ Refers-To, RefersTo, refersto, refers-to and r-e-f-er-s-tO will all be treated as the same thing. -=begin testing - -ok (require RT::Action::CreateTickets); -use_ok(RT::Scrip); -use_ok(RT::Template); -use_ok(RT::ScripAction); -use_ok(RT::ScripCondition); -use_ok(RT::Ticket); - -my $approvalsq = RT::Queue->new($RT::SystemUser); -$approvalsq->Create(Name => 'Approvals'); -ok ($approvalsq->Id, "Created Approvals test queue"); - - -my $approvals = -'===Create-Ticket: approval -Queue: ___Approvals -Type: approval -AdminCc: {join ("\nAdminCc: ",@admins) } -Depended-On-By: {$Tickets{"TOP"}->Id} -Refers-To: TOP -Subject: Approval for ticket: {$Tickets{"TOP"}->Id} - {$Tickets{"TOP"}->Subject} -Due: {time + 86400} -Content-Type: text/plain -Content: Your approval is requested for the ticket {$Tickets{"TOP"}->Id}: {$Tickets{"TOP"}->Subject} -Blah -Blah -ENDOFCONTENT -===Create-Ticket: two -Subject: Manager approval. -Depended-On-By: approval -Queue: ___Approvals -Content-Type: text/plain -Content: -Your minion approved ticket {$Tickets{"TOP"}->Id}. you ok with that? -ENDOFCONTENT -'; - -ok ($approvals =~ /Content/, "Read in the approvals template"); - -my $apptemp = RT::Template->new($RT::SystemUser); -$apptemp->Create( Content => $approvals, Name => "Approvals", Queue => "0"); - -ok ($apptemp->Id); - -my $q = RT::Queue->new($RT::SystemUser); -$q->Create(Name => 'WorkflowTest'); -ok ($q->Id, "Created workflow test queue"); - -my $scrip = RT::Scrip->new($RT::SystemUser); -my ($sval, $smsg) =$scrip->Create( ScripCondition => 'On Transaction', - ScripAction => 'Create Tickets', - Template => 'Approvals', - Queue => $q->Id); -ok ($sval, $smsg); -ok ($scrip->Id, "Created the scrip"); -ok ($scrip->TemplateObj->Id, "Created the scrip template"); -ok ($scrip->ConditionObj->Id, "Created the scrip condition"); -ok ($scrip->ActionObj->Id, "Created the scrip action"); - -my $t = RT::Ticket->new($RT::SystemUser); -my($tid, $ttrans, $tmsg) = $t->Create(Subject => "Sample workflow test", - Owner => "root", - Queue => $q->Id); - -ok ($tid,$tmsg); - -my $deps = $t->DependsOn; -is ($deps->Count, 1, "The ticket we created depends on one other ticket"); -my $dependson= $deps->First->TargetObj; -ok ($dependson->Id, "It depends on a real ticket"); -unlike ($dependson->Subject, qr/{/, "The subject doesn't have braces in it. that means we're interpreting expressions"); -is ($t->ReferredToBy->Count,1, "It's only referred to by one other ticket"); -is ($t->ReferredToBy->First->BaseObj->Id,$t->DependsOn->First->TargetObj->Id, "The same ticket that depends on it refers to it."); -use RT::Action::CreateTickets; -my $action = RT::Action::CreateTickets->new( CurrentUser => $RT::SystemUser);; - -# comma-delimited templates -my $commas = <<"EOF"; -id,Queue,Subject,Owner,Content -ticket1,General,"foo, bar",root,blah -ticket2,General,foo bar,root,blah -ticket3,General,foo' bar,root,blah'boo -ticket4,General,foo' bar,,blah'boo -EOF - - -# Comma delimited templates with missing data -my $sparse_commas = <<"EOF"; -id,Queue,Subject,Owner,Requestor -ticket14,General,,,bobby -ticket15,General,,,tommy -ticket16,General,,suzie,tommy -ticket17,General,Foo "bar" baz,suzie,tommy -ticket18,General,'Foo "bar" baz',suzie,tommy -ticket19,General,'Foo bar' baz,suzie,tommy -EOF - - -# tab-delimited templates -my $tabs = <<"EOF"; -id\tQueue\tSubject\tOwner\tContent -ticket10\tGeneral\t"foo' bar"\troot\tblah' -ticket11\tGeneral\tfoo, bar\troot\tblah -ticket12\tGeneral\tfoo' bar\troot\tblah'boo -ticket13\tGeneral\tfoo' bar\t\tblah'boo -EOF - -my %expected; - -$expected{ticket1} = <<EOF; -Queue: General -Subject: foo, bar -Owner: root -Content: blah -ENDOFCONTENT -EOF - -$expected{ticket2} = <<EOF; -Queue: General -Subject: foo bar -Owner: root -Content: blah -ENDOFCONTENT -EOF - -$expected{ticket3} = <<EOF; -Queue: General -Subject: foo' bar -Owner: root -Content: blah'boo -ENDOFCONTENT -EOF - -$expected{ticket4} = <<EOF; -Queue: General -Subject: foo' bar -Owner: -Content: blah'boo -ENDOFCONTENT -EOF - -$expected{ticket10} = <<EOF; -Queue: General -Subject: foo' bar -Owner: root -Content: blah' -ENDOFCONTENT -EOF - -$expected{ticket11} = <<EOF; -Queue: General -Subject: foo, bar -Owner: root -Content: blah -ENDOFCONTENT -EOF - -$expected{ticket12} = <<EOF; -Queue: General -Subject: foo' bar -Owner: root -Content: blah'boo -ENDOFCONTENT -EOF - -$expected{ticket13} = <<EOF; -Queue: General -Subject: foo' bar -Owner: -Content: blah'boo -ENDOFCONTENT -EOF - - -$expected{'ticket14'} = <<EOF; -Queue: General -Subject: -Owner: -Requestor: bobby -EOF -$expected{'ticket15'} = <<EOF; -Queue: General -Subject: -Owner: -Requestor: tommy -EOF -$expected{'ticket16'} = <<EOF; -Queue: General -Subject: -Owner: suzie -Requestor: tommy -EOF -$expected{'ticket17'} = <<EOF; -Queue: General -Subject: Foo "bar" baz -Owner: suzie -Requestor: tommy -EOF -$expected{'ticket18'} = <<EOF; -Queue: General -Subject: Foo "bar" baz -Owner: suzie -Requestor: tommy -EOF -$expected{'ticket19'} = <<EOF; -Queue: General -Subject: 'Foo bar' baz -Owner: suzie -Requestor: tommy -EOF - - - - -$action->Parse(Content =>$commas); -$action->Parse(Content =>$sparse_commas); -$action->Parse(Content => $tabs); - -my %got; -foreach (@{ $action->{'create_tickets'} }) { - $got{$_} = $action->{'templates'}->{$_}; -} - -foreach my $id ( sort keys %expected ) { - ok(exists($got{"create-$id"}), "template exists for $id"); - is($got{"create-$id"}, $expected{$id}, "template is correct for $id"); -} - -=end testing =head1 AUTHOR @@ -541,16 +313,16 @@ sub Prepare { my $self = shift; unless ( $self->TemplateObj ) { - $RT::Logger->warning("No template object handed to $self\n"); + $RT::Logger->warning("No template object handed to $self"); } unless ( $self->TransactionObj ) { - $RT::Logger->warning("No transaction object handed to $self\n"); + $RT::Logger->warning("No transaction object handed to $self"); } unless ( $self->TicketObj ) { - $RT::Logger->warning("No ticket object handed to $self\n"); + $RT::Logger->warning("No ticket object handed to $self"); } @@ -575,7 +347,6 @@ sub CreateByTemplate { my @results; # XXX: cargo cult programming that works. i'll be back. - use bytes; local %T::Tickets = %T::Tickets; local $T::TOP = $T::TOP; @@ -637,7 +408,6 @@ sub UpdateByTemplate { my $top = shift; # XXX: cargo cult programming that works. i'll be back. - use bytes; my @results; local %T::Tickets = %T::Tickets; @@ -894,7 +664,7 @@ sub ParseLines { } ); - $RT::Logger->debug("Workflow: yielding\n$content"); + $RT::Logger->debug("Workflow: yielding $content"); if ($err) { $RT::Logger->error( "Ticket creation failed: " . $err ); @@ -990,6 +760,7 @@ sub ParseLines { TimeLeft => $args{'timeleft'}, InitialPriority => $args{'initialpriority'} || 0, FinalPriority => $args{'finalpriority'} || 0, + SquelchMailTo => $args{'squelchmailto'}, Type => $args{'type'}, ); @@ -1223,7 +994,7 @@ sub GetUpdateTemplate { my $mode = $LINKTYPEMAP{$type}->{Mode}; my $method = $LINKTYPEMAP{$type}->{Type}; - my $links; + my $links = ''; while ( my $link = $t->$method->Next ) { $links .= ", " if $links; diff --git a/rt/lib/RT/Action/EscalatePriority.pm b/rt/lib/RT/Action/EscalatePriority.pm index 46635df05..bf9de92c2 100644 --- a/rt/lib/RT/Action/EscalatePriority.pm +++ b/rt/lib/RT/Action/EscalatePriority.pm @@ -1,8 +1,8 @@ # BEGIN BPS TAGGED BLOCK {{{ # # COPYRIGHT: -# -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC # <jesse@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -45,6 +45,7 @@ # those contributions and any derivatives thereof. # # END BPS TAGGED BLOCK }}} + =head1 NAME RT::Action::EscalatePriority @@ -71,11 +72,9 @@ as the ticket heads toward its due date. package RT::Action::EscalatePriority; -require RT::Action::Generic; +use base 'RT::Action'; use strict; -use vars qw/@ISA/; -@ISA=qw(RT::Action::Generic); #Do what we need to do and send it out. @@ -155,7 +154,7 @@ sub Commit { my ($val, $msg) = $self->TicketObj->SetPriority($self->{'prio'}); unless ($val) { - $RT::Logger->debug($self . " $msg\n"); + $RT::Logger->debug($self . " $msg"); } } diff --git a/rt/lib/RT/Action/ExtractSubjectTag.pm b/rt/lib/RT/Action/ExtractSubjectTag.pm new file mode 100644 index 000000000..4a173ce76 --- /dev/null +++ b/rt/lib/RT/Action/ExtractSubjectTag.pm @@ -0,0 +1,103 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +package RT::Action::ExtractSubjectTag; +use base 'RT::Action'; +use strict; + +sub Describe { + my $self = shift; + return ( ref $self ); +} + +sub Prepare { + return (1); +} + +sub Commit { + my $self = shift; + my $Transaction = $self->TransactionObj; + my $FirstAttachment = $Transaction->Attachments->First; + return 1 unless ($FirstAttachment); + + my $Ticket = $self->TicketObj; + + my $TicketSubject = $self->TicketObj->Subject; + my $origTicketSubject = $TicketSubject; + my $TransactionSubject = $FirstAttachment->Subject; + + my $match = RT->Config->Get('ExtractSubjectTagMatch'); + my $nomatch = RT->Config->Get('ExtractSubjectTagNoMatch'); + TAGLIST: while ( $TransactionSubject =~ /($match)/g ) { + my $tag = $1; + next if $tag =~ /$nomatch/; + foreach my $subject_tag ( RT->System->SubjectTag ) { + if ($tag =~ /\[\Q$subject_tag\E\s+\#(\d+)\s*\]/) { + next TAGLIST; + } + } + $TicketSubject .= " $tag" unless ( $TicketSubject =~ /\Q$tag\E/ ); + } + + $self->TicketObj->SetSubject($TicketSubject) + if ( $TicketSubject ne $origTicketSubject ); + + return (1); +} + +eval "require RT::Action::ExtractSubjectTag_Vendor"; +if ($@ && $@ !~ qr{^Can't locate RT/Action/ExtractSubjectTag_Vendor.pm}) { + die $@; +}; + +eval "require RT::Action::ExtractSubjectTag_Local"; +if ($@ && $@ !~ qr{^Can't locate RT/Action/ExtractSubjectTag_Local.pm}) { + die $@; +}; + +1; diff --git a/rt/lib/RT/Action/LinearEscalate.pm b/rt/lib/RT/Action/LinearEscalate.pm new file mode 100755 index 000000000..9130f40ca --- /dev/null +++ b/rt/lib/RT/Action/LinearEscalate.pm @@ -0,0 +1,279 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +=head1 NAME + +RT::Action::LinearEscalate - will move a ticket's priority toward its final priority. + +=head1 This vs. RT::Action::EscalatePriority + +This action doesn't change priority if due date is not set. + +This action honor the Starts date. + +This action can apply changes silently. + +This action can replace EscalatePriority completly. If you want to tickets +that have been created without Due date then you can add scrip that sets +default due date. For example a week then priorities of your tickets will +escalate linearly during the week from intial value towards final. + +=head1 This vs. LinearEscalate from the CPAN + +This action is an integration of the module from the CPAN into RT's core +that's happened in RT 3.8. If you're upgrading from 3.6 and have been using +module from the CPAN with old version of RT then you should uninstall it +and use this one. + +However, this action doesn't support control over config. Read </CONFIGURATION> +to find out ways to deal with it. + +=head1 DESCRIPTION + +LinearEscalate is a ScripAction that will move a ticket's priority +from its initial priority to its final priority linearly as +the ticket approaches its due date. + +It's intended to be called by an RT escalation tool. One such tool is called +rt-crontool and is located in $RTHOME/bin (see C<rt-crontool -h> for more details). + +=head1 USAGE + +Once the ScripAction is installed, the following script in "cron" +will get tickets to where they need to be: + + rt-crontool --search RT::Search::FromSQL --search-arg \ + "(Status='new' OR Status='open' OR Status = 'stalled')" \ + --action RT::Action::LinearEscalate + +The Starts date is associated with intial ticket's priority or +the Created field if the former is not set. End of interval is +the Due date. Tickets without due date B<are not updated>. + +=head1 CONFIGURATION + +Initial and Final priorities are controlled by queue's options +and can be defined using the web UI via Configuration tab. This +action should handle correctly situations when initial priority +is greater than final. + +LinearEscalate's behavior can be controlled by two options: + +=over 4 + +=item RecordTransaction - defaults to false and if option is true then +causes the tool to create a transaction on the ticket when it is escalated. + +=item UpdateLastUpdated - which defaults to true and updates the LastUpdated +field when the ticket is escalated, otherwise don't touch anything. + +=back + +You cannot set "UpdateLastUpdated" to false unless "RecordTransaction" +is also false. Well, you can, but we'll just ignore you. + +You can set this options using either in F<RT_SiteConfig.pm>, as action +argument in call to the rt-crontool or in DB if you want to use the action +in scrips. + +From a shell you can use the following command: + + rt-crontool --search RT::Search::FromSQL --search-arg \ + "(Status='new' OR Status='open' OR Status = 'stalled')" \ + --action RT::Action::LinearEscalate \ + --action-arg "RecordTransaction: 1" + +This ScripAction uses RT's internal _Set or __Set calls to set ticket +priority without running scrips or recording a transaction on each +update, if it's been said to. + +=cut + +package RT::Action::LinearEscalate; + +use strict; +use warnings; +use base qw(RT::Action); + +our $VERSION = '0.06'; + +#Do what we need to do and send it out. + +#What does this type of Action does + +sub Describe { + my $self = shift; + my $class = ref($self) || $self; + return "$class will move a ticket's priority toward its final priority."; +} + +sub Prepare { + my $self = shift; + + my $ticket = $self->TicketObj; + + my $due = $ticket->DueObj->Unix; + unless ( $due > 0 ) { + $RT::Logger->debug('Due is not set. Not escalating.'); + return 1; + } + + my $priority_range = ($ticket->FinalPriority ||0) - ($ticket->InitialPriority ||0); + unless ( $priority_range ) { + $RT::Logger->debug('Final and Initial priorities are equal. Not escalating.'); + return 1; + } + + if ( $ticket->Priority >= $ticket->FinalPriority && $priority_range > 0 ) { + $RT::Logger->debug('Current priority is greater than final. Not escalating.'); + return 1; + } + elsif ( $ticket->Priority <= $ticket->FinalPriority && $priority_range < 0 ) { + $RT::Logger->debug('Current priority is lower than final. Not escalating.'); + return 1; + } + + # TODO: compute the number of business days until the ticket is due + + # now we know we have a due date. for every day that passes, + # increment priority according to the formula + + my $starts = $ticket->StartsObj->Unix; + $starts = $ticket->CreatedObj->Unix unless $starts > 0; + my $now = time; + + # do nothing if we didn't reach starts or created date + if ( $starts > $now ) { + $RT::Logger->debug('Starts(Created) is in future. Not escalating.'); + return 1; + } + + $due = $starts + 1 if $due <= $starts; # +1 to avoid div by zero + + my $percent_complete = ($now-$starts)/($due - $starts); + + my $new_priority = int($percent_complete * $priority_range) + ($ticket->InitialPriority || 0); + $new_priority = $ticket->FinalPriority if $new_priority > $ticket->FinalPriority; + $self->{'new_priority'} = $new_priority; + + return 1; +} + +sub Commit { + my $self = shift; + + my $new_value = $self->{'new_priority'}; + return 1 unless defined $new_value; + + my $ticket = $self->TicketObj; + # if the priority hasn't changed do nothing + return 1 if $ticket->Priority == $new_value; + + # override defaults from argument + my ($record, $update) = (0, 1); + { + my $arg = $self->Argument || ''; + if ( $arg =~ /RecordTransaction:\s*(\d+)/i ) { + $record = $1; + $RT::Logger->debug("Overrode RecordTransaction: $record"); + } + if ( $arg =~ /UpdateLastUpdated:\s*(\d+)/i ) { + $update = $1; + $RT::Logger->debug("Overrode UpdateLastUpdated: $update"); + } + $update = 1 if $record; + } + + $RT::Logger->debug( + 'Linearly escalating priority of ticket #'. $ticket->Id + .' from '. $ticket->Priority .' to '. $new_value + .' and'. ($record? '': ' do not') .' record a transaction' + .' and'. ($update? '': ' do not') .' touch last updated field' + ); + + my ( $val, $msg ); + unless ( $record ) { + unless ( $update ) { + ( $val, $msg ) = $ticket->__Set( + Field => 'Priority', + Value => $new_value, + ); + } + else { + ( $val, $msg ) = $ticket->_Set( + Field => 'Priority', + Value => $new_value, + RecordTransaction => 0, + ); + } + } + else { + ( $val, $msg ) = $ticket->SetPriority( $new_value ); + } + + unless ($val) { + $RT::Logger->error( "Couldn't set new priority value: $msg" ); + return (0, $msg); + } + return 1; +} + +eval "require RT::Action::LinearEscalate_Vendor"; +die $@ if ( $@ && $@ !~ qr{^Can't locate RT/Action/LinearEscalate_Vendor.pm} ); +eval "require RT::Action::LinearEscalate_Local"; +die $@ if ( $@ && $@ !~ qr{^Can't locate RT/Action/LinearEscalate_Local.pm} ); + +1; + +=head1 AUTHORS + +Kevin Riggle E<lt>kevinr@bestpractical.comE<gt> + +Ruslan Zakirov E<lt>ruz@bestpractical.comE<gt> + +=cut diff --git a/rt/lib/RT/Action/NotifyGroup.pm b/rt/lib/RT/Action/NotifyGroup.pm new file mode 100644 index 000000000..6b830cb86 --- /dev/null +++ b/rt/lib/RT/Action/NotifyGroup.pm @@ -0,0 +1,209 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +=head1 NAME + +RT::Action::NotifyGroup - RT Action that sends notifications to groups and/or users + +=head1 DESCRIPTION + +RT action module that allow you to notify particular groups and/or users. +Distribution is shipped with C<rt-email-group-admin> script that +is command line tool for managing NotifyGroup scrip actions. For more +more info see its documentation. + +=cut + +package RT::Action::NotifyGroup; + +use strict; +use warnings; +use base qw(RT::Action::Notify); + +require RT::User; +require RT::Group; + +=head1 METHODS + +=head2 SetRecipients + +Sets the recipients of this message to Groups and/or Users. + +=cut + +sub SetRecipients { + my $self = shift; + + my $arg = $self->Argument; + foreach( $self->__SplitArg( $arg ) ) { + $self->_HandleArgument( $_ ); + } + + my $creator = $self->TransactionObj->CreatorObj->EmailAddress(); + unless( $RT::NotifyActor ) { + @{ $self->{'To'} } = grep ( !/^\Q$creator\E$/, @{ $self->{'To'} } ); + } + + $self->{'seen_ueas'} = {}; + + return 1; +} + +sub _HandleArgument { + my $self = shift; + my $instance = shift; + + if ( $instance !~ /\D/ ) { + my $obj = RT::Principal->new( $self->CurrentUser ); + $obj->Load( $instance ); + return $self->_HandlePrincipal( $obj ); + } + + my $group = RT::Group->new( $self->CurrentUser ); + $group->LoadUserDefinedGroup( $instance ); + # to check disabled and so on + return $self->_HandlePrincipal( $group->PrincipalObj ) + if $group->id; + + require Email::Address; + + my $user = RT::User->new( $self->CurrentUser ); + if ( $instance =~ /^$Email::Address::addr_spec$/ ) { + $user->LoadByEmail( $instance ); + return $self->__PushUserAddress( $instance ) + unless $user->id; + } else { + $user->Load( $instance ); + } + return $self->_HandlePrincipal( $user->PrincipalObj ) + if $user->id; + + $RT::Logger->error( + "'$instance' is not principal id, group name, user name," + ." user email address or any email address" + ); + + return; +} + +sub _HandlePrincipal { + my $self = shift; + my $obj = shift; + unless( $obj->id ) { + $RT::Logger->error( "Couldn't load principal #$obj" ); + return; + } + if( $obj->Disabled ) { + $RT::Logger->info( "Principal #$obj is disabled => skip" ); + return; + } + if( !$obj->PrincipalType ) { + $RT::Logger->crit( "Principal #$obj has empty type" ); + } elsif( lc $obj->PrincipalType eq 'user' ) { + $self->__HandleUserArgument( $obj->Object ); + } elsif( lc $obj->PrincipalType eq 'group' ) { + $self->__HandleGroupArgument( $obj->Object ); + } else { + $RT::Logger->info( "Principal #$obj has unsupported type" ); + } + return; +} + +sub __HandleUserArgument { + my $self = shift; + my $obj = shift; + + my $uea = $obj->EmailAddress; + unless( $uea ) { + $RT::Logger->warning( "User #". $obj->id ." has no email address" ); + return; + } + $self->__PushUserAddress( $uea ); +} + +sub __HandleGroupArgument { + my $self = shift; + my $obj = shift; + + my $members = $obj->UserMembersObj; + while( my $m = $members->Next ) { + $self->__HandleUserArgument( $m ); + } +} + +sub __SplitArg { + return grep length, map {s/^\s+//; s/\s+$//; $_} split /,/, $_[1]; +} + +sub __PushUserAddress { + my $self = shift; + my $uea = shift; + push @{ $self->{'To'} }, $uea unless $self->{'seen_ueas'}{ $uea }++; + return; +} + + +=head1 AUTHOR + +Ruslan U. Zakirov E<lt>ruz@bestpractical.comE<gt> + +L<RT::Action::NotifyGroupAsComment>, F<rt-email-group-admin> + +=cut + +eval "require RT::Action::NotifyGroup_Vendor"; +if ($@ && $@ !~ qr{^Can't locate RT/Action/NotifyGroup_Vendor.pm}) { + die $@; +}; + +eval "require RT::Action::NotifyGroup_Local"; +if ($@ && $@ !~ qr{^Can't locate RT/Action/NotifyGroup_Local.pm}) { + die $@; +}; + +1; diff --git a/rt/lib/RT/Action/NotifyGroupAsComment.pm b/rt/lib/RT/Action/NotifyGroupAsComment.pm new file mode 100644 index 000000000..bee0a01a1 --- /dev/null +++ b/rt/lib/RT/Action/NotifyGroupAsComment.pm @@ -0,0 +1,91 @@ +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# <jesse@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# +# This work is made available to you under the terms of Version 2 of +# the GNU General Public License. A copy of that license should have +# been provided with this software, but in any event can be snarfed +# from www.gnu.org. +# +# This work is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +=head1 NAME + +RT::Action::NotifyGroupAsComment - RT Action that sends notifications to groups and/or users as comment + +=head1 DESCRIPTION + +This is subclass of L<RT::Action::NotifyGroup> that send comments instead of replies. +See C<rt-email-group-admin> and L<RT::Action::NotifyGroup> docs for more info. + +=cut + +package RT::Action::NotifyGroupAsComment; + +use strict; +use warnings; + +use RT::Action::NotifyGroup; + +use base qw(RT::Action::NotifyGroup); + +sub SetReturnAddress { + my $self = shift; + $self->{'comment'} = 1; + return $self->SUPER::SetReturnAddress( @_, is_comment => 1 ); +} + +=head1 AUTHOR + +Ruslan U. Zakirov E<lt>ruz@bestpractical.comE<gt> + +=cut + +eval "require RT::Action::NotifyGroupAsComment_Vendor"; +if ($@ && $@ !~ qr{^Can't locate RT/Action/NotifyGroupAsComment_Vendor.pm}) { + die $@; +}; + +eval "require RT::Action::NotifyGroupAsComment_Local"; +if ($@ && $@ !~ qr{^Can't locate RT/Action/NotifyGroupAsComment_Local.pm}) { + die $@; +}; + +1; diff --git a/rt/lib/RT/Action/RecordComment.pm b/rt/lib/RT/Action/RecordComment.pm index c0256d6d7..bac17e96e 100644 --- a/rt/lib/RT/Action/RecordComment.pm +++ b/rt/lib/RT/Action/RecordComment.pm @@ -1,8 +1,8 @@ # BEGIN BPS TAGGED BLOCK {{{ # # COPYRIGHT: -# -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC # <jesse@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -45,11 +45,10 @@ # those contributions and any derivatives thereof. # # END BPS TAGGED BLOCK }}} + package RT::Action::RecordComment; -require RT::Action::Generic; +use base 'RT::Action'; use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Action::Generic); =head1 NAME diff --git a/rt/lib/RT/Action/RecordCorrespondence.pm b/rt/lib/RT/Action/RecordCorrespondence.pm index 10a890e4e..044893b97 100644 --- a/rt/lib/RT/Action/RecordCorrespondence.pm +++ b/rt/lib/RT/Action/RecordCorrespondence.pm @@ -1,8 +1,8 @@ # BEGIN BPS TAGGED BLOCK {{{ # # COPYRIGHT: -# -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC # <jesse@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -45,11 +45,10 @@ # those contributions and any derivatives thereof. # # END BPS TAGGED BLOCK }}} + package RT::Action::RecordCorrespondence; -require RT::Action::Generic; +use base 'RT::Action'; use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Action::Generic); =head1 NAME diff --git a/rt/lib/RT/Action/SetPriority.pm b/rt/lib/RT/Action/SetPriority.pm index b4c8ee199..9b0838926 100644 --- a/rt/lib/RT/Action/SetPriority.pm +++ b/rt/lib/RT/Action/SetPriority.pm @@ -1,8 +1,8 @@ # BEGIN BPS TAGGED BLOCK {{{ # # COPYRIGHT: -# -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC # <jesse@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -45,12 +45,11 @@ # those contributions and any derivatives thereof. # # END BPS TAGGED BLOCK }}} + package RT::Action::SetPriority; -require RT::Action::Generic; +use base 'RT::Action'; use strict; -use vars qw/@ISA/; -@ISA=qw(RT::Action::Generic); #Do what we need to do and send it out. diff --git a/rt/lib/RT/Action/UserDefined.pm b/rt/lib/RT/Action/UserDefined.pm index 7bf6eee51..80ef49224 100644 --- a/rt/lib/RT/Action/UserDefined.pm +++ b/rt/lib/RT/Action/UserDefined.pm @@ -1,8 +1,8 @@ # BEGIN BPS TAGGED BLOCK {{{ # # COPYRIGHT: -# -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +# +# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC # <jesse@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -45,14 +45,11 @@ # those contributions and any derivatives thereof. # # END BPS TAGGED BLOCK }}} - package RT::Action::UserDefined; -use RT::Action::Generic; +use base 'RT::Action'; use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Action::Generic); =head2 Prepare |