diff options
author | cvs2git <cvs2git> | 2010-12-27 00:04:45 +0000 |
---|---|---|
committer | cvs2git <cvs2git> | 2010-12-27 00:04:45 +0000 |
commit | c82d349f864e6bd9f96fd1156903bc1f7193a203 (patch) | |
tree | e117a87533656110b6acd56fc0ca64289892a9f5 /rt/lib/RT/Action | |
parent | 74e058c8a010ef6feb539248a550d0bb169c1e94 (diff) |
This commit was manufactured by cvs2svn to create tag 'TORRUS_1_0_9'.TORRUS_1_0_9
Diffstat (limited to 'rt/lib/RT/Action')
-rw-r--r-- | rt/lib/RT/Action/AutoOpen.pm | 105 | ||||
-rwxr-xr-x | rt/lib/RT/Action/Autoreply.pm | 96 | ||||
-rw-r--r-- | rt/lib/RT/Action/CreateTickets.pm | 1266 | ||||
-rw-r--r-- | rt/lib/RT/Action/EscalatePriority.pm | 166 | ||||
-rw-r--r-- | rt/lib/RT/Action/ExtractSubjectTag.pm | 103 | ||||
-rwxr-xr-x | rt/lib/RT/Action/Generic.pm | 195 | ||||
-rwxr-xr-x | rt/lib/RT/Action/LinearEscalate.pm | 279 | ||||
-rwxr-xr-x | rt/lib/RT/Action/Notify.pm | 132 | ||||
-rwxr-xr-x | rt/lib/RT/Action/NotifyAsComment.pm | 55 | ||||
-rw-r--r-- | rt/lib/RT/Action/NotifyGroup.pm | 214 | ||||
-rw-r--r-- | rt/lib/RT/Action/NotifyGroupAsComment.pm | 91 | ||||
-rw-r--r-- | rt/lib/RT/Action/RecordComment.pm | 119 | ||||
-rw-r--r-- | rt/lib/RT/Action/RecordCorrespondence.pm | 120 | ||||
-rw-r--r-- | rt/lib/RT/Action/ResolveMembers.pm | 88 | ||||
-rwxr-xr-x | rt/lib/RT/Action/SendEmail.pm | 685 | ||||
-rw-r--r-- | rt/lib/RT/Action/SetPriority.pm | 84 | ||||
-rw-r--r-- | rt/lib/RT/Action/UserDefined.pm | 92 |
17 files changed, 0 insertions, 3890 deletions
diff --git a/rt/lib/RT/Action/AutoOpen.pm b/rt/lib/RT/Action/AutoOpen.pm deleted file mode 100644 index e1cf0ae7c..000000000 --- a/rt/lib/RT/Action/AutoOpen.pm +++ /dev/null @@ -1,105 +0,0 @@ -# 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 }}} - -# This Action will open the BASE if a dependent is resolved. -package RT::Action::AutoOpen; - -use strict; -use warnings; - -use base qw(RT::Action); - -=head1 DESCRIPTION - -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 { - my $self = shift; - - # if the ticket is already open or the ticket is new and the message is more mail from the - # requestor, don't reopen it. - - my $status = $self->TicketObj->Status; - return undef if $status eq 'open'; - return undef if $status eq 'new' && $self->TransactionObj->IsInbound; - - if ( my $msg = $self->TransactionObj->Message->First ) { - return undef if ($msg->GetHeader('RT-Control') || '') =~ /\bno-autoopen\b/i; - } - - 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; -} - -eval "require RT::Action::AutoOpen_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/AutoOpen_Vendor.pm}); -eval "require RT::Action::AutoOpen_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/AutoOpen_Local.pm}); - -1; diff --git a/rt/lib/RT/Action/Autoreply.pm b/rt/lib/RT/Action/Autoreply.pm deleted file mode 100755 index 81f7bddfa..000000000 --- a/rt/lib/RT/Action/Autoreply.pm +++ /dev/null @@ -1,96 +0,0 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# -# 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. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK -package RT::Action::Autoreply; -require RT::Action::SendEmail; - -use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Action::SendEmail); - - -# {{{ sub SetRecipients - -=head2 SetRecipients - -Sets the recipients of this message to this ticket's Requestor. - -=cut - - -sub SetRecipients { - my $self=shift; - - push(@{$self->{'To'}}, $self->TicketObj->Requestors->MemberEmailAddresses); - - return(1); -} - -# }}} - - -# {{{ sub SetReturnAddress - -=head2 SetReturnAddress - -Set this message\'s return address to the apropriate queue address - -=cut - -sub SetReturnAddress { - my $self = shift; - my %args = ( is_comment => 0, - @_ - ); - - my $replyto; - if ($args{'is_comment'}) { - $replyto = $self->TicketObj->QueueObj->CommentAddress || - $RT::CommentAddress; - } - else { - $replyto = $self->TicketObj->QueueObj->CorrespondAddress || - $RT::CorrespondAddress; - } - - unless ($self->TemplateObj->MIMEObj->head->get('From')) { - my $friendly_name = $self->TicketObj->QueueObj->Description || - $self->TicketObj->QueueObj->Name; - $friendly_name =~ s/"/\\"/g; - $self->SetHeader('From', "\"$friendly_name\" <$replyto>"); - } - - unless ($self->TemplateObj->MIMEObj->head->get('Reply-To')) { - $self->SetHeader('Reply-To', "$replyto"); - } - -} - -# }}} - -eval "require RT::Action::Autoreply_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/Autoreply_Vendor.pm}); -eval "require RT::Action::Autoreply_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/Autoreply_Local.pm}); - -1; diff --git a/rt/lib/RT/Action/CreateTickets.pm b/rt/lib/RT/Action/CreateTickets.pm deleted file mode 100644 index 74520ca69..000000000 --- a/rt/lib/RT/Action/CreateTickets.pm +++ /dev/null @@ -1,1266 +0,0 @@ -# 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::CreateTickets; -use base 'RT::Action'; - -use strict; -use warnings; - -use MIME::Entity; - -=head1 NAME - - RT::Action::CreateTickets - -Create one or more tickets according to an externally supplied template. - - -=head1 SYNOPSIS - - ===Create-Ticket codereview - Subject: Code review for {$Tickets{'TOP'}->Subject} - Depended-On-By: TOP - Content: Someone has created a ticket. you should review and approve it, - so they can finish their work - ENDOFCONTENT - -=head1 DESCRIPTION - - -Using the "CreateTickets" ScripAction and mandatory dependencies, RT now has -the ability to model complex workflow. When a ticket is created in a queue -that has a "CreateTickets" scripaction, that ScripAction parses its "Template" - - - -=head2 FORMAT - -CreateTickets uses the template as a template for an ordered set of tickets -to create. The basic format is as follows: - - - ===Create-Ticket: identifier - Param: Value - Param2: Value - Param3: Value - Content: Blah - blah - blah - ENDOFCONTENT - ===Create-Ticket: id2 - Param: Value - Content: Blah - ENDOFCONTENT - - -Each ===Create-Ticket: section is evaluated as its own -Text::Template object, which means that you can embed snippets -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, 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: - - ===Create-Ticket: codereview - Subject: Code review for {$Tickets{'TOP'}->Subject} - Depended-On-By: TOP - Content: Someone has created a ticket. you should review and approve it, - so they can finish their work - ENDOFCONTENT - - - -A convoluted example - - ===Create-Ticket: approval - { # Find out who the administrators of the group called "HR" - # of which the creator of this ticket is a member - my $name = "HR"; - - my $groups = RT::Groups->new($RT::SystemUser); - $groups->LimitToUserDefinedGroups(); - $groups->Limit(FIELD => "Name", OPERATOR => "=", VALUE => "$name"); - $groups->WithMember($TransactionObj->CreatorObj->Id); - - my $groupid = $groups->First->Id; - - my $adminccs = RT::Users->new($RT::SystemUser); - $adminccs->WhoHaveRight( - Right => "AdminGroup", - Object =>$groups->First, - IncludeSystemRights => undef, - IncludeSuperusers => 0, - IncludeSubgroupMembers => 0, - ); - - my @admins; - while (my $admin = $adminccs->Next) { - push (@admins, $admin->EmailAddress); - } - } - Queue: ___Approvals - Type: approval - AdminCc: {join ("\nAdminCc: ",@admins) } - Depended-On-By: TOP - 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 - Type: approval - Depended-On-By: TOP - Refers-To: {$Tickets{"create-approval"}->Id} - Queue: ___Approvals - Content-Type: text/plain - Content: - Your approval is requred for this ticket, too. - ENDOFCONTENT - -=head2 Acceptable fields - -A complete list of acceptable fields for this beastie: - - - * Queue => Name or id# of a queue - Subject => A text string - ! Status => A valid status. defaults to 'new' - Due => Dates can be specified in seconds since the epoch - to be handled literally or in a semi-free textual - format which RT will attempt to parse. - - - - Starts => - Started => - Resolved => - Owner => Username or id of an RT user who can and should own - this ticket; forces the owner if necessary - + Requestor => Email address - + Cc => Email address - + AdminCc => Email address - TimeWorked => - TimeEstimated => - TimeLeft => - InitialPriority => - FinalPriority => - Type => - +! DependsOn => - +! DependedOnBy => - +! RefersTo => - +! ReferredToBy => - +! Members => - +! MemberOf => - Content => content. Can extend to multiple lines. Everything - within a template after a Content: header is treated - as content until we hit a line containing only - ENDOFCONTENT - ContentType => the content-type of the Content field. Defaults to - 'text/plain' - UpdateType => 'correspond' or 'comment'; used in conjunction with - 'content' if this is an update. Defaults to - 'correspond' - - CustomField-<id#> => custom field value - CF-name => custom field value - CustomField-name => custom field value - -Fields marked with an * are required. - -Fields marked with a + may have multiple values, simply -by repeating the fieldname on a new line with an additional value. - -Fields marked with a ! are postponed to be processed after all -tickets in the same actions are created. Except for 'Status', those -field can also take a ticket name within the same action (i.e. -the identifiers after ==Create-Ticket), instead of raw Ticket ID -numbers. - -When parsed, field names are converted to lowercase and have -s stripped. -Refers-To, RefersTo, refersto, refers-to and r-e-f-er-s-tO will all -be treated as the same thing. - - - - -=head1 AUTHOR - -Jesse Vincent <jesse@bestpractical.com> - -=head1 SEE ALSO - -perl(1). - -=cut - -my %LINKTYPEMAP = ( - MemberOf => { - Type => 'MemberOf', - Mode => 'Target', - }, - Parents => { - Type => 'MemberOf', - Mode => 'Target', - }, - Members => { - Type => 'MemberOf', - Mode => 'Base', - }, - Children => { - Type => 'MemberOf', - Mode => 'Base', - }, - HasMember => { - Type => 'MemberOf', - Mode => 'Base', - }, - RefersTo => { - Type => 'RefersTo', - Mode => 'Target', - }, - ReferredToBy => { - Type => 'RefersTo', - Mode => 'Base', - }, - DependsOn => { - Type => 'DependsOn', - Mode => 'Target', - }, - DependedOnBy => { - Type => 'DependsOn', - Mode => 'Base', - }, - -); - -# {{{ Scrip methods (Commit, Prepare) - -# {{{ sub Commit -#Do what we need to do and send it out. -sub Commit { - my $self = shift; - - # Create all the tickets we care about - return (1) unless $self->TicketObj->Type eq 'ticket'; - - $self->CreateByTemplate( $self->TicketObj ); - $self->UpdateByTemplate( $self->TicketObj ); - return (1); -} - -# }}} - -# {{{ sub Prepare - -sub Prepare { - my $self = shift; - - unless ( $self->TemplateObj ) { - $RT::Logger->warning("No template object handed to $self"); - } - - unless ( $self->TransactionObj ) { - $RT::Logger->warning("No transaction object handed to $self"); - - } - - unless ( $self->TicketObj ) { - $RT::Logger->warning("No ticket object handed to $self"); - - } - - $self->Parse( - Content => $self->TemplateObj->Content, - _ActiveContent => 1 - ); - return 1; - -} - -# }}} - -# }}} - -sub CreateByTemplate { - my $self = shift; - my $top = shift; - - $RT::Logger->debug("In CreateByTemplate"); - - my @results; - - # XXX: cargo cult programming that works. i'll be back. - - local %T::Tickets = %T::Tickets; - local $T::TOP = $T::TOP; - local $T::ID = $T::ID; - $T::Tickets{'TOP'} = $T::TOP = $top if $top; - - my $ticketargs; - my ( @links, @postponed ); - foreach my $template_id ( @{ $self->{'create_tickets'} } ) { - $RT::Logger->debug("Workflow: processing $template_id of $T::TOP") - if $T::TOP; - - $T::ID = $template_id; - @T::AllID = @{ $self->{'create_tickets'} }; - - ( $T::Tickets{$template_id}, $ticketargs ) - = $self->ParseLines( $template_id, \@links, \@postponed ); - - # Now we have a %args to work with. - # Make sure we have at least the minimum set of - # reasonable data and do our thang - - my ( $id, $transid, $msg ) - = $T::Tickets{$template_id}->Create(%$ticketargs); - - foreach my $res ( split( '\n', $msg ) ) { - push @results, - $T::Tickets{$template_id} - ->loc( "Ticket [_1]", $T::Tickets{$template_id}->Id ) . ': ' - . $res; - } - if ( !$id ) { - if ( $self->TicketObj ) { - $msg = "Couldn't create related ticket $template_id for " - . $self->TicketObj->Id . " " - . $msg; - } else { - $msg = "Couldn't create ticket $template_id " . $msg; - } - - $RT::Logger->error($msg); - next; - } - - $RT::Logger->debug("Assigned $template_id with $id"); - $T::Tickets{$template_id}->SetOriginObj( $self->TicketObj ) - if $self->TicketObj - && $T::Tickets{$template_id}->can('SetOriginObj'); - - } - - $self->PostProcess( \@links, \@postponed ); - - return @results; -} - -sub UpdateByTemplate { - my $self = shift; - my $top = shift; - - # XXX: cargo cult programming that works. i'll be back. - - my @results; - local %T::Tickets = %T::Tickets; - local $T::ID = $T::ID; - - my $ticketargs; - my ( @links, @postponed ); - foreach my $template_id ( @{ $self->{'update_tickets'} } ) { - $RT::Logger->debug("Update Workflow: processing $template_id"); - - $T::ID = $template_id; - @T::AllID = @{ $self->{'update_tickets'} }; - - ( $T::Tickets{$template_id}, $ticketargs ) - = $self->ParseLines( $template_id, \@links, \@postponed ); - - # Now we have a %args to work with. - # Make sure we have at least the minimum set of - # reasonable data and do our thang - - my @attribs = qw( - Subject - FinalPriority - Priority - TimeEstimated - TimeWorked - TimeLeft - Status - Queue - Due - Starts - Started - Resolved - ); - - my $id = $template_id; - $id =~ s/update-(\d+).*/$1/; - my ($loaded, $msg) = $T::Tickets{$template_id}->LoadById($id); - - unless ( $loaded ) { - $RT::Logger->error("Couldn't update ticket $template_id: " . $msg); - push @results, $self->loc( "Couldn't load ticket '[_1]'", $id ); - next; - } - - my $current = $self->GetBaseTemplate( $T::Tickets{$template_id} ); - - $template_id =~ m/^update-(.*)/; - my $base_id = "base-$1"; - my $base = $self->{'templates'}->{$base_id}; - if ($base) { - $base =~ s/\r//g; - $base =~ s/\n+$//; - $current =~ s/\n+$//; - - # If we have no base template, set what we can. - if ( $base ne $current ) { - push @results, - "Could not update ticket " - . $T::Tickets{$template_id}->Id - . ": Ticket has changed"; - next; - } - } - push @results, $T::Tickets{$template_id}->Update( - AttributesRef => \@attribs, - ARGSRef => $ticketargs - ); - - if ( $ticketargs->{'Owner'} ) { - ($id, $msg) = $T::Tickets{$template_id}->SetOwner($ticketargs->{'Owner'}, "Force"); - push @results, $msg unless $msg eq $self->loc("That user already owns that ticket"); - } - - push @results, - $self->UpdateWatchers( $T::Tickets{$template_id}, $ticketargs ); - - push @results, - $self->UpdateCustomFields( $T::Tickets{$template_id}, $ticketargs ); - - next unless $ticketargs->{'MIMEObj'}; - if ( $ticketargs->{'UpdateType'} =~ /^(private|comment)$/i ) { - my ( $Transaction, $Description, $Object ) - = $T::Tickets{$template_id}->Comment( - BccMessageTo => $ticketargs->{'Bcc'}, - MIMEObj => $ticketargs->{'MIMEObj'}, - TimeTaken => $ticketargs->{'TimeWorked'} - ); - push( @results, - $T::Tickets{$template_id} - ->loc( "Ticket [_1]", $T::Tickets{$template_id}->id ) - . ': ' - . $Description ); - } elsif ( $ticketargs->{'UpdateType'} =~ /^(public|response|correspond)$/i ) { - my ( $Transaction, $Description, $Object ) - = $T::Tickets{$template_id}->Correspond( - BccMessageTo => $ticketargs->{'Bcc'}, - MIMEObj => $ticketargs->{'MIMEObj'}, - TimeTaken => $ticketargs->{'TimeWorked'} - ); - push( @results, - $T::Tickets{$template_id} - ->loc( "Ticket [_1]", $T::Tickets{$template_id}->id ) - . ': ' - . $Description ); - } else { - push( - @results, - $T::Tickets{$template_id}->loc( - "Update type was neither correspondence nor comment.") - . " " - . $T::Tickets{$template_id}->loc("Update not recorded.") - ); - } - } - - $self->PostProcess( \@links, \@postponed ); - - return @results; -} - -=head2 Parse TEMPLATE_CONTENT, DEFAULT_QUEUE, DEFAULT_REQEUESTOR ACTIVE - -Parse a template from TEMPLATE_CONTENT - -If $active is set to true, then we'll use Text::Template to parse the templates, -allowing you to embed active perl in your templates. - -=cut - -sub Parse { - my $self = shift; - my %args = ( - Content => undef, - Queue => undef, - Requestor => undef, - _ActiveContent => undef, - @_ - ); - - if ( $args{'_ActiveContent'} ) { - $self->{'UsePerlTextTemplate'} = 1; - } else { - - $self->{'UsePerlTextTemplate'} = 0; - } - - if ( substr( $args{'Content'}, 0, 3 ) eq '===' ) { - $self->_ParseMultilineTemplate(%args); - } elsif ( $args{'Content'} =~ /(?:\t|,)/i ) { - $self->_ParseXSVTemplate(%args); - - } -} - -=head2 _ParseMultilineTemplate - -Parses mulitline templates. Things like: - - ===Create-Ticket ... - -Takes the same arguments as Parse - -=cut - -sub _ParseMultilineTemplate { - my $self = shift; - my %args = (@_); - - my $template_id; - my ( $queue, $requestor ); - $RT::Logger->debug("Line: ==="); - foreach my $line ( split( /\n/, $args{'Content'} ) ) { - $line =~ s/\r$//; - $RT::Logger->debug("Line: $line"); - if ( $line =~ /^===/ ) { - if ( $template_id && !$queue && $args{'Queue'} ) { - $self->{'templates'}->{$template_id} - .= "Queue: $args{'Queue'}\n"; - } - if ( $template_id && !$requestor && $args{'Requestor'} ) { - $self->{'templates'}->{$template_id} - .= "Requestor: $args{'Requestor'}\n"; - } - $queue = 0; - $requestor = 0; - } - if ( $line =~ /^===Create-Ticket: (.*)$/ ) { - $template_id = "create-$1"; - $RT::Logger->debug("**** Create ticket: $template_id"); - push @{ $self->{'create_tickets'} }, $template_id; - } elsif ( $line =~ /^===Update-Ticket: (.*)$/ ) { - $template_id = "update-$1"; - $RT::Logger->debug("**** Update ticket: $template_id"); - push @{ $self->{'update_tickets'} }, $template_id; - } elsif ( $line =~ /^===Base-Ticket: (.*)$/ ) { - $template_id = "base-$1"; - $RT::Logger->debug("**** Base ticket: $template_id"); - push @{ $self->{'base_tickets'} }, $template_id; - } elsif ( $line =~ /^===#.*$/ ) { # a comment - next; - } else { - if ( $line =~ /^Queue:(.*)/i ) { - $queue = 1; - my $value = $1; - $value =~ s/^\s//; - $value =~ s/\s$//; - if ( !$value && $args{'Queue'} ) { - $value = $args{'Queue'}; - $line = "Queue: $value"; - } - } - if ( $line =~ /^Requestors?:(.*)/i ) { - $requestor = 1; - my $value = $1; - $value =~ s/^\s//; - $value =~ s/\s$//; - if ( !$value && $args{'Requestor'} ) { - $value = $args{'Requestor'}; - $line = "Requestor: $value"; - } - } - $self->{'templates'}->{$template_id} .= $line . "\n"; - } - } - if ( $template_id && !$queue && $args{'Queue'} ) { - $self->{'templates'}->{$template_id} .= "Queue: $args{'Queue'}\n"; - } - } - -sub ParseLines { - my $self = shift; - my $template_id = shift; - my $links = shift; - my $postponed = shift; - - my $content = $self->{'templates'}->{$template_id}; - - if ( $self->{'UsePerlTextTemplate'} ) { - - $RT::Logger->debug( - "Workflow: evaluating\n$self->{templates}{$template_id}"); - - my $template = Text::Template->new( - TYPE => 'STRING', - SOURCE => $content - ); - - my $err; - $content = $template->fill_in( - PACKAGE => 'T', - BROKEN => sub { - $err = {@_}->{error}; - } - ); - - $RT::Logger->debug("Workflow: yielding $content"); - - if ($err) { - $RT::Logger->error( "Ticket creation failed: " . $err ); - while ( my ( $k, $v ) = each %T::X ) { - $RT::Logger->debug( - "Eliminating $template_id from ${k}'s parents."); - delete $v->{$template_id}; - } - next; - } - } - - my $TicketObj ||= RT::Ticket->new( $self->CurrentUser ); - - my %args; - my %original_tags; - my @lines = ( split( /\n/, $content ) ); - while ( defined( my $line = shift @lines ) ) { - if ( $line =~ /^(.*?):(?:\s+)(.*?)(?:\s*)$/ ) { - my $value = $2; - my $original_tag = $1; - my $tag = lc($original_tag); - $tag =~ s/-//g; - $tag =~ s/^(requestor|cc|admincc)s?$/$1/i; - - $original_tags{$tag} = $original_tag; - - if ( ref( $args{$tag} ) ) - { #If it's an array, we want to push the value - push @{ $args{$tag} }, $value; - } elsif ( defined( $args{$tag} ) ) - { #if we're about to get a second value, make it an array - $args{$tag} = [ $args{$tag}, $value ]; - } else { #if there's nothing there, just set the value - $args{$tag} = $value; - } - - if ( $tag =~ /^content$/i ) { #just build up the content - # convert it to an array - $args{$tag} = defined($value) ? [ $value . "\n" ] : []; - while ( defined( my $l = shift @lines ) ) { - last if ( $l =~ /^ENDOFCONTENT\s*$/ ); - push @{ $args{'content'} }, $l . "\n"; - } - } else { - # if it's not content, strip leading and trailing spaces - if ( $args{$tag} ) { - $args{$tag} =~ s/^\s+//g; - $args{$tag} =~ s/\s+$//g; - } - if (($tag =~ /^(requestor|cc|admincc)$/i or grep {lc $_ eq $tag} keys %LINKTYPEMAP) and $args{$tag} =~ /,/) { - $args{$tag} = [ split /,\s*/, $args{$tag} ]; - } - } - } - } - - foreach my $date qw(due starts started resolved) { - my $dateobj = RT::Date->new( $self->CurrentUser ); - next unless $args{$date}; - if ( $args{$date} =~ /^\d+$/ ) { - $dateobj->Set( Format => 'unix', Value => $args{$date} ); - } else { - eval { - $dateobj->Set( Format => 'iso', Value => $args{$date} ); - }; - if ($@ or $dateobj->Unix <= 0) { - $dateobj->Set( Format => 'unknown', Value => $args{$date} ); - } - } - $args{$date} = $dateobj->ISO; - } - - $args{'requestor'} ||= $self->TicketObj->Requestors->MemberEmailAddresses - if $self->TicketObj; - - $args{'type'} ||= 'ticket'; - - my %ticketargs = ( - Queue => $args{'queue'}, - Subject => $args{'subject'}, - Status => $args{'status'} || 'new', - Due => $args{'due'}, - Starts => $args{'starts'}, - Started => $args{'started'}, - Resolved => $args{'resolved'}, - Owner => $args{'owner'}, - Requestor => $args{'requestor'}, - Cc => $args{'cc'}, - AdminCc => $args{'admincc'}, - TimeWorked => $args{'timeworked'}, - TimeEstimated => $args{'timeestimated'}, - TimeLeft => $args{'timeleft'}, - InitialPriority => $args{'initialpriority'} || 0, - FinalPriority => $args{'finalpriority'} || 0, - SquelchMailTo => $args{'squelchmailto'}, - Type => $args{'type'}, - $self->Rules - ); - - if ( $args{content} ) { - my $mimeobj = MIME::Entity->new(); - $mimeobj->build( - Type => $args{'contenttype'} || 'text/plain', - Data => $args{'content'} - ); - $ticketargs{MIMEObj} = $mimeobj; - $ticketargs{UpdateType} = $args{'updatetype'} || 'correspond'; - } - - foreach my $tag ( keys(%args) ) { - # if the tag was added later, skip it - my $orig_tag = $original_tags{$tag} or next; - if ( $orig_tag =~ /^customfield-?(\d+)$/i ) { - $ticketargs{ "CustomField-" . $1 } = $args{$tag}; - } elsif ( $orig_tag =~ /^(?:customfield|cf)-?(.*)$/i ) { - my $cf = RT::CustomField->new( $self->CurrentUser ); - $cf->LoadByName( Name => $1, Queue => $ticketargs{Queue} ); - $ticketargs{ "CustomField-" . $cf->id } = $args{$tag}; - } elsif ($orig_tag) { - my $cf = RT::CustomField->new( $self->CurrentUser ); - $cf->LoadByName( Name => $orig_tag, Queue => $ticketargs{Queue} ); - next unless ($cf->id) ; - $ticketargs{ "CustomField-" . $cf->id } = $args{$tag}; - - } - } - - $self->GetDeferred( \%args, $template_id, $links, $postponed ); - - return $TicketObj, \%ticketargs; -} - - -=head2 _ParseXSVTemplate - -Parses a tab or comma delimited template. Should only ever be called by Parse - -=cut - -sub _ParseXSVTemplate { - my $self = shift; - my %args = (@_); - - use Regexp::Common qw(delimited); - my($first, $content) = split(/\r?\n/, $args{'Content'}, 2); - - my $delimiter; - if ( $first =~ /\t/ ) { - $delimiter = "\t"; - } else { - $delimiter = ','; - } - my @fields = split( /$delimiter/, $first ); - - my $delimiter_re = qr[$delimiter]; - my $justquoted = qr[$RE{quoted}]; - - # Used to generate automatic template ids - my $autoid = 1; - - LINE: - while ($content) { - $content =~ s/^(\s*\r?\n)+//; - - # Keep track of Queue and Requestor, so we can provide defaults - my $queue; - my $requestor; - - # The template for this line - my $template; - - # What column we're on - my $i = 0; - - # If the last iteration was the end of the line - my $EOL = 0; - - # The template id - my $template_id; - - COLUMN: - while (not $EOL and length $content and $content =~ s/^($justquoted|.*?)($delimiter_re|$)//smix) { - $EOL = not $2; - - # Strip off quotes, if they exist - my $value = $1; - if ( $value =~ /^$RE{delimited}{-delim=>qq{\'\"}}$/ ) { - substr( $value, 0, 1 ) = ""; - substr( $value, -1, 1 ) = ""; - } - - # What column is this? - my $field = $fields[$i++]; - next COLUMN unless $field =~ /\S/; - $field =~ s/^\s//; - $field =~ s/\s$//; - - if ( $field =~ /^id$/i ) { - # Special case if this is the ID column - if ( $value =~ /^\d+$/ ) { - $template_id = 'update-' . $value; - push @{ $self->{'update_tickets'} }, $template_id; - } elsif ( $value =~ /^#base-(\d+)$/ ) { - $template_id = 'base-' . $1; - push @{ $self->{'base_tickets'} }, $template_id; - } elsif ( $value =~ /\S/ ) { - $template_id = 'create-' . $value; - push @{ $self->{'create_tickets'} }, $template_id; - } - } else { - # Some translations - if ( $field =~ /^Body$/i - || $field =~ /^Data$/i - || $field =~ /^Message$/i ) - { - $field = 'Content'; - } elsif ( $field =~ /^Summary$/i ) { - $field = 'Subject'; - } elsif ( $field =~ /^Queue$/i ) { - # Note that we found a queue - $queue = 1; - $value ||= $args{'Queue'}; - } elsif ( $field =~ /^Requestors?$/i ) { - $field = 'Requestor'; # Remove plural - # Note that we found a requestor - $requestor = 1; - $value ||= $args{'Requestor'}; - } - - # Tack onto the end of the template - $template .= $field . ": "; - $template .= (defined $value ? $value : ""); - $template .= "\n"; - $template .= "ENDOFCONTENT\n" - if $field =~ /^Content$/i; - } - } - - # Ignore blank lines - next unless $template; - - # If we didn't find a queue of requestor, tack on the defaults - if ( !$queue && $args{'Queue'} ) { - $template .= "Queue: $args{'Queue'}\n"; - } - if ( !$requestor && $args{'Requestor'} ) { - $template .= "Requestor: $args{'Requestor'}\n"; - } - - # If we never found an ID, come up with one - unless ($template_id) { - $autoid++ while exists $self->{'templates'}->{"create-auto-$autoid"}; - $template_id = "create-auto-$autoid"; - # Also, it's a ticket to create - push @{ $self->{'create_tickets'} }, $template_id; - } - - # Save the template we generated - $self->{'templates'}->{$template_id} = $template; - - } -} - -sub GetDeferred { - my $self = shift; - my $args = shift; - my $id = shift; - my $links = shift; - my $postponed = shift; - - # Deferred processing - push @$links, - ( - $id, - { DependsOn => $args->{'dependson'}, - DependedOnBy => $args->{'dependedonby'}, - RefersTo => $args->{'refersto'}, - ReferredToBy => $args->{'referredtoby'}, - Children => $args->{'children'}, - Parents => $args->{'parents'}, - } - ); - - push @$postponed, ( - - # Status is postponed so we don't violate dependencies - $id, { Status => $args->{'status'}, } - ); -} - -sub GetUpdateTemplate { - my $self = shift; - my $t = shift; - - my $string; - $string .= "Queue: " . $t->QueueObj->Name . "\n"; - $string .= "Subject: " . $t->Subject . "\n"; - $string .= "Status: " . $t->Status . "\n"; - $string .= "UpdateType: correspond\n"; - $string .= "Content: \n"; - $string .= "ENDOFCONTENT\n"; - $string .= "Due: " . $t->DueObj->AsString . "\n"; - $string .= "Starts: " . $t->StartsObj->AsString . "\n"; - $string .= "Started: " . $t->StartedObj->AsString . "\n"; - $string .= "Resolved: " . $t->ResolvedObj->AsString . "\n"; - $string .= "Owner: " . $t->OwnerObj->Name . "\n"; - $string .= "Requestor: " . $t->RequestorAddresses . "\n"; - $string .= "Cc: " . $t->CcAddresses . "\n"; - $string .= "AdminCc: " . $t->AdminCcAddresses . "\n"; - $string .= "TimeWorked: " . $t->TimeWorked . "\n"; - $string .= "TimeEstimated: " . $t->TimeEstimated . "\n"; - $string .= "TimeLeft: " . $t->TimeLeft . "\n"; - $string .= "InitialPriority: " . $t->Priority . "\n"; - $string .= "FinalPriority: " . $t->FinalPriority . "\n"; - - foreach my $type ( sort keys %LINKTYPEMAP ) { - - # don't display duplicates - if ( $type eq "HasMember" - || $type eq "Members" - || $type eq "MemberOf" ) - { - next; - } - $string .= "$type: "; - - my $mode = $LINKTYPEMAP{$type}->{Mode}; - my $method = $LINKTYPEMAP{$type}->{Type}; - - my $links = ''; - while ( my $link = $t->$method->Next ) { - $links .= ", " if $links; - - my $object = $mode . "Obj"; - my $member = $link->$object; - $links .= $member->Id if $member; - } - $string .= $links; - $string .= "\n"; - } - - return $string; -} - -sub GetBaseTemplate { - my $self = shift; - my $t = shift; - - my $string; - $string .= "Queue: " . $t->Queue . "\n"; - $string .= "Subject: " . $t->Subject . "\n"; - $string .= "Status: " . $t->Status . "\n"; - $string .= "Due: " . $t->DueObj->Unix . "\n"; - $string .= "Starts: " . $t->StartsObj->Unix . "\n"; - $string .= "Started: " . $t->StartedObj->Unix . "\n"; - $string .= "Resolved: " . $t->ResolvedObj->Unix . "\n"; - $string .= "Owner: " . $t->Owner . "\n"; - $string .= "Requestor: " . $t->RequestorAddresses . "\n"; - $string .= "Cc: " . $t->CcAddresses . "\n"; - $string .= "AdminCc: " . $t->AdminCcAddresses . "\n"; - $string .= "TimeWorked: " . $t->TimeWorked . "\n"; - $string .= "TimeEstimated: " . $t->TimeEstimated . "\n"; - $string .= "TimeLeft: " . $t->TimeLeft . "\n"; - $string .= "InitialPriority: " . $t->Priority . "\n"; - $string .= "FinalPriority: " . $t->FinalPriority . "\n"; - - return $string; -} - -sub GetCreateTemplate { - my $self = shift; - - my $string; - - $string .= "Queue: General\n"; - $string .= "Subject: \n"; - $string .= "Status: new\n"; - $string .= "Content: \n"; - $string .= "ENDOFCONTENT\n"; - $string .= "Due: \n"; - $string .= "Starts: \n"; - $string .= "Started: \n"; - $string .= "Resolved: \n"; - $string .= "Owner: \n"; - $string .= "Requestor: \n"; - $string .= "Cc: \n"; - $string .= "AdminCc:\n"; - $string .= "TimeWorked: \n"; - $string .= "TimeEstimated: \n"; - $string .= "TimeLeft: \n"; - $string .= "InitialPriority: \n"; - $string .= "FinalPriority: \n"; - - foreach my $type ( keys %LINKTYPEMAP ) { - - # don't display duplicates - if ( $type eq "HasMember" - || $type eq 'Members' - || $type eq 'MemberOf' ) - { - next; - } - $string .= "$type: \n"; - } - return $string; -} - -sub UpdateWatchers { - my $self = shift; - my $ticket = shift; - my $args = shift; - - my @results; - - foreach my $type qw(Requestor Cc AdminCc) { - my $method = $type . 'Addresses'; - my $oldaddr = $ticket->$method; - - # Skip unless we have a defined field - next unless defined $args->{$type}; - my $newaddr = $args->{$type}; - - my @old = split( /,\s*/, $oldaddr ); - my @new; - for (ref $newaddr ? @{$newaddr} : split( /,\s*/, $newaddr )) { - # Sometimes these are email addresses, sometimes they're - # users. Try to guess which is which, as we want to deal - # with email addresses if at all possible. - if (/^\S+@\S+$/) { - push @new, $_; - } else { - # It doesn't look like an email address. Try to load it. - my $user = RT::User->new($self->CurrentUser); - $user->Load($_); - if ($user->Id) { - push @new, $user->EmailAddress; - } else { - push @new, $_; - } - } - } - - my %oldhash = map { $_ => 1 } @old; - my %newhash = map { $_ => 1 } @new; - - my @add = grep( !defined $oldhash{$_}, @new ); - my @delete = grep( !defined $newhash{$_}, @old ); - - foreach (@add) { - my ( $val, $msg ) = $ticket->AddWatcher( - Type => $type, - Email => $_ - ); - - push @results, - $ticket->loc( "Ticket [_1]", $ticket->Id ) . ': ' . $msg; - } - - foreach (@delete) { - my ( $val, $msg ) = $ticket->DeleteWatcher( - Type => $type, - Email => $_ - ); - push @results, - $ticket->loc( "Ticket [_1]", $ticket->Id ) . ': ' . $msg; - } - } - return @results; -} - -sub UpdateCustomFields { - my $self = shift; - my $ticket = shift; - my $args = shift; - - my @results; - foreach my $arg (keys %{$args}) { - next unless $arg =~ /^CustomField-(\d+)$/; - my $cf = $1; - - my $CustomFieldObj = RT::CustomField->new($self->CurrentUser); - $CustomFieldObj->LoadById($cf); - - my @values; - if ($CustomFieldObj->Type =~ /text/i) { # Both Text and Wikitext - @values = ($args->{$arg}); - } else { - @values = split /\n/, $args->{$arg}; - } - - if ( ($CustomFieldObj->Type eq 'Freeform' - && ! $CustomFieldObj->SingleValue) || - $CustomFieldObj->Type =~ /text/i) { - foreach my $val (@values) { - $val =~ s/\r//g; - } - } - - foreach my $value (@values) { - next unless length($value); - my ( $val, $msg ) = $ticket->AddCustomFieldValue( - Field => $cf, - Value => $value - ); - push ( @results, $msg ); - } - } - return @results; -} - -sub PostProcess { - my $self = shift; - my $links = shift; - my $postponed = shift; - - # postprocessing: add links - - while ( my $template_id = shift(@$links) ) { - my $ticket = $T::Tickets{$template_id}; - $RT::Logger->debug( "Handling links for " . $ticket->Id ); - my %args = %{ shift(@$links) }; - - foreach my $type ( keys %LINKTYPEMAP ) { - next unless ( defined $args{$type} ); - foreach my $link ( - ref( $args{$type} ) ? @{ $args{$type} } : ( $args{$type} ) ) - { - next unless $link; - - if ( $link =~ /^TOP$/i ) { - $RT::Logger->debug( "Building $type link for $link: " - . $T::Tickets{TOP}->Id ); - $link = $T::Tickets{TOP}->Id; - - } elsif ( $link !~ m/^\d+$/ ) { - my $key = "create-$link"; - if ( !exists $T::Tickets{$key} ) { - $RT::Logger->debug( - "Skipping $type link for $key (non-existent)"); - next; - } - $RT::Logger->debug( "Building $type link for $link: " - . $T::Tickets{$key}->Id ); - $link = $T::Tickets{$key}->Id; - } else { - $RT::Logger->debug("Building $type link for $link"); - } - - my ( $wval, $wmsg ) = $ticket->AddLink( - Type => $LINKTYPEMAP{$type}->{'Type'}, - $LINKTYPEMAP{$type}->{'Mode'} => $link, - Silent => 1 - ); - - $RT::Logger->warning("AddLink thru $link failed: $wmsg") - unless $wval; - - # push @non_fatal_errors, $wmsg unless ($wval); - } - - } - } - - # postponed actions -- Status only, currently - while ( my $template_id = shift(@$postponed) ) { - my $ticket = $T::Tickets{$template_id}; - $RT::Logger->debug( "Handling postponed actions for " . $ticket->id ); - my %args = %{ shift(@$postponed) }; - $ticket->SetStatus( $args{Status} ) if defined $args{Status}; - } - -} - -sub Options { - my $self = shift; - my $queues = RT::Queues->new($self->CurrentUser); - $queues->UnLimit; - my @names; - while (my $queue = $queues->Next) { - push @names, $queue->Id, $queue->Name; - } - return ( - { - 'name' => 'Queue', - 'label' => 'In queue', - 'type' => 'select', - 'options' => \@names - } - ) -} - -eval "require RT::Action::CreateTickets_Vendor"; -die $@ if ( $@ && $@ !~ qr{^Can't locate RT/Action/CreateTickets_Vendor.pm} ); -eval "require RT::Action::CreateTickets_Local"; -die $@ if ( $@ && $@ !~ qr{^Can't locate RT/Action/CreateTickets_Local.pm} ); - -1; - diff --git a/rt/lib/RT/Action/EscalatePriority.pm b/rt/lib/RT/Action/EscalatePriority.pm deleted file mode 100644 index bf9de92c2..000000000 --- a/rt/lib/RT/Action/EscalatePriority.pm +++ /dev/null @@ -1,166 +0,0 @@ -# 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::EscalatePriority - -=head1 DESCRIPTION - -EscalatePriority is a ScripAction which is NOT intended to be called -per transaction. 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) - -EsclatePriority uses the following formula to change a ticket's priority: - - Priority = Priority + (( FinalPriority - Priority ) / ( DueDate-Today)) - -Unless the duedate is past, in which case priority gets bumped straight -to final priority. - -In this way, priority is either increased or decreased toward the final priority -as the ticket heads toward its due date. - - -=cut - - -package RT::Action::EscalatePriority; -use base 'RT::Action'; - -use strict; - -#Do what we need to do and send it out. - -#What does this type of Action does - -# {{{ sub Describe -sub Describe { - my $self = shift; - return (ref $self . " will move a ticket's priority toward its final priority."); -} -# }}} - - -# {{{ sub Prepare -sub Prepare { - my $self = shift; - - if ($self->TicketObj->Priority() == $self->TicketObj->FinalPriority()) { - # no update necessary. - return 0; - } - - #compute the number of days until the ticket is due - my $due = $self->TicketObj->DueObj(); - - - # If we don't have a due date, adjust the priority by one - # until we hit the final priority - if ($due->Unix() < 1) { - if ( $self->TicketObj->Priority > $self->TicketObj->FinalPriority ){ - $self->{'prio'} = ($self->TicketObj->Priority - 1); - return 1; - } - elsif ( $self->TicketObj->Priority < $self->TicketObj->FinalPriority ){ - $self->{'prio'} = ($self->TicketObj->Priority + 1); - return 1; - } - # otherwise the priority is at the final priority. we don't need to - # Continue - else { - return 0; - } - } - - # we've got a due date. now there are other things we should do - else { - my $diff_in_seconds = $due->Diff(time()); - my $diff_in_days = int( $diff_in_seconds / 86400); - - #if we haven't hit the due date yet - if ($diff_in_days > 0 ) { - - # compute the difference between the current priority and the - # final priority - - my $prio_delta = - $self->TicketObj->FinalPriority() - $self->TicketObj->Priority; - - my $inc_priority_by = int( $prio_delta / $diff_in_days ); - - #set the ticket's priority to that amount - $self->{'prio'} = $self->TicketObj->Priority + $inc_priority_by; - - } - #if $days is less than 1, set priority to final_priority - else { - $self->{'prio'} = $self->TicketObj->FinalPriority(); - } - - } - return 1; -} -# }}} - -sub Commit { - my $self = shift; - my ($val, $msg) = $self->TicketObj->SetPriority($self->{'prio'}); - - unless ($val) { - $RT::Logger->debug($self . " $msg"); - } -} - -eval "require RT::Action::EscalatePriority_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/EscalatePriority_Vendor.pm}); -eval "require RT::Action::EscalatePriority_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/EscalatePriority_Local.pm}); - -1; diff --git a/rt/lib/RT/Action/ExtractSubjectTag.pm b/rt/lib/RT/Action/ExtractSubjectTag.pm deleted file mode 100644 index 4a173ce76..000000000 --- a/rt/lib/RT/Action/ExtractSubjectTag.pm +++ /dev/null @@ -1,103 +0,0 @@ -# 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/Generic.pm b/rt/lib/RT/Action/Generic.pm deleted file mode 100755 index 007d299c7..000000000 --- a/rt/lib/RT/Action/Generic.pm +++ /dev/null @@ -1,195 +0,0 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# -# 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. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK -=head1 NAME - - RT::Action::Generic - a generic baseclass for RT Actions - -=head1 SYNOPSIS - - use RT::Action::Generic; - -=head1 DESCRIPTION - -=head1 METHODS - -=begin testing - -ok (require RT::Action::Generic); - -=end testing - -=cut - -package RT::Action::Generic; - -use strict; - -# {{{ sub new -sub new { - my $proto = shift; - my $class = ref($proto) || $proto; - my $self = {}; - bless ($self, $class); - $self->_Init(@_); - return $self; -} -# }}} - -# {{{ sub new -sub loc { - my $self = shift; - return $self->{'ScripObj'}->loc(@_); -} -# }}} - -# {{{ sub _Init -sub _Init { - my $self = shift; - my %args = ( TransactionObj => undef, - TicketObj => undef, - ScripObj => undef, - TemplateObj => undef, - Argument => undef, - Type => undef, - @_ ); - - - $self->{'Argument'} = $args{'Argument'}; - $self->{'ScripObj'} = $args{'ScripObj'}; - $self->{'TicketObj'} = $args{'TicketObj'}; - $self->{'TransactionObj'} = $args{'TransactionObj'}; - $self->{'TemplateObj'} = $args{'TemplateObj'}; - $self->{'Type'} = $args{'Type'}; -} -# }}} - -# Access Scripwide data - -# {{{ sub Argument -sub Argument { - my $self = shift; - return($self->{'Argument'}); -} -# }}} - -# {{{ sub TicketObj -sub TicketObj { - my $self = shift; - return($self->{'TicketObj'}); -} -# }}} - -# {{{ sub TransactionObj -sub TransactionObj { - my $self = shift; - return($self->{'TransactionObj'}); -} -# }}} - -# {{{ sub TemplateObj -sub TemplateObj { - my $self = shift; - return($self->{'TemplateObj'}); -} -# }}} - -# {{{ sub ScripObj -sub ScripObj { - my $self = shift; - return($self->{'ScripObj'}); -} -# }}} - -# {{{ sub Type -sub Type { - my $self = shift; - return($self->{'Type'}); -} -# }}} - - -# Scrip methods - -#Do what we need to do and send it out. - -# {{{ sub Commit -sub Commit { - my $self = shift; - return(0, $self->loc("Commit Stubbed")); -} -# }}} - - -#What does this type of Action does - -# {{{ sub Describe -sub Describe { - my $self = shift; - return $self->loc("No description for [_1]", ref $self); -} -# }}} - - -#Parse the templates, get things ready to go. - -# {{{ sub Prepare -sub Prepare { - my $self = shift; - return (0, $self->loc("Prepare Stubbed")); -} -# }}} - - -#If this rule applies to this transaction, return true. - -# {{{ sub IsApplicable -sub IsApplicable { - my $self = shift; - return(undef); -} -# }}} - -# {{{ sub DESTROY -sub DESTROY { - my $self = shift; - - # We need to clean up all the references that might maybe get - # oddly circular - $self->{'TemplateObj'} =undef - $self->{'TicketObj'} = undef; - $self->{'TransactionObj'} = undef; - $self->{'ScripObj'} = undef; - - - -} - -# }}} - -eval "require RT::Action::Generic_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/Generic_Vendor.pm}); -eval "require RT::Action::Generic_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/Generic_Local.pm}); - -1; diff --git a/rt/lib/RT/Action/LinearEscalate.pm b/rt/lib/RT/Action/LinearEscalate.pm deleted file mode 100755 index 9130f40ca..000000000 --- a/rt/lib/RT/Action/LinearEscalate.pm +++ /dev/null @@ -1,279 +0,0 @@ -# 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/Notify.pm b/rt/lib/RT/Action/Notify.pm deleted file mode 100755 index 1e4e4c073..000000000 --- a/rt/lib/RT/Action/Notify.pm +++ /dev/null @@ -1,132 +0,0 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# -# 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. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK -package RT::Action::Notify; -require RT::Action::SendEmail; - -use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Action::SendEmail); - -# {{{ sub SetRecipients - -=head2 SetRecipients - -Sets the recipients of this meesage to Owner, Requestor, AdminCc, Cc or All. -Explicitly B<does not> notify the creator of the transaction by default - -=cut - -sub SetRecipients { - my $self = shift; - - my $arg = $self->Argument; - - $arg =~ s/\bAll\b/Owner,Requestor,AdminCc,Cc/; - - my ( @To, @PseudoTo, @Cc, @Bcc ); - - - if ($arg =~ /\bOtherRecipients\b/) { - if ($self->TransactionObj->Attachments->First) { - push (@Cc, $self->TransactionObj->Attachments->First->GetHeader('RT-Send-Cc')); - push (@Bcc, $self->TransactionObj->Attachments->First->GetHeader('RT-Send-Bcc')); - } - } - - if ( $arg =~ /\bRequestor\b/ ) { - push ( @To, $self->TicketObj->Requestors->MemberEmailAddresses ); - } - - - - if ( $arg =~ /\bCc\b/ ) { - - #If we have a To, make the Ccs, Ccs, otherwise, promote them to To - if (@To) { - push ( @Cc, $self->TicketObj->Cc->MemberEmailAddresses ); - push ( @Cc, $self->TicketObj->QueueObj->Cc->MemberEmailAddresses ); - } - else { - push ( @Cc, $self->TicketObj->Cc->MemberEmailAddresses ); - push ( @To, $self->TicketObj->QueueObj->Cc->MemberEmailAddresses ); - } - } - - if ( ( $arg =~ /\bOwner\b/ ) - && ( $self->TicketObj->OwnerObj->id != $RT::Nobody->id ) ) - { - - # If we're not sending to Ccs or requestors, - # then the Owner can be the To. - if (@To) { - push ( @Bcc, $self->TicketObj->OwnerObj->EmailAddress ); - } - else { - push ( @To, $self->TicketObj->OwnerObj->EmailAddress ); - } - - } - - if ( $arg =~ /\bAdminCc\b/ ) { - push ( @Bcc, $self->TicketObj->AdminCc->MemberEmailAddresses ); - push ( @Bcc, $self->TicketObj->QueueObj->AdminCc->MemberEmailAddresses ); - } - - if ($RT::UseFriendlyToLine) { - unless (@To) { - push ( - @PseudoTo, - sprintf($RT::FriendlyToLineFormat, $arg, $self->TicketObj->id), - ); - } - } - - my $creator = $self->TransactionObj->CreatorObj->EmailAddress(); - - #Strip the sender out of the To, Cc and AdminCc and set the - # recipients fields used to build the message by the superclass. - # unless a flag is set - if ($RT::NotifyActor) { - @{ $self->{'To'} } = @To; - @{ $self->{'Cc'} } = @Cc; - @{ $self->{'Bcc'} } = @Bcc; - } - else { - @{ $self->{'To'} } = grep ( !/^$creator$/, @To ); - @{ $self->{'Cc'} } = grep ( !/^$creator$/, @Cc ); - @{ $self->{'Bcc'} } = grep ( !/^$creator$/, @Bcc ); - } - @{ $self->{'PseudoTo'} } = @PseudoTo; - return (1); - -} - -# }}} - -eval "require RT::Action::Notify_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/Notify_Vendor.pm}); -eval "require RT::Action::Notify_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/Notify_Local.pm}); - -1; diff --git a/rt/lib/RT/Action/NotifyAsComment.pm b/rt/lib/RT/Action/NotifyAsComment.pm deleted file mode 100755 index 210e4ab15..000000000 --- a/rt/lib/RT/Action/NotifyAsComment.pm +++ /dev/null @@ -1,55 +0,0 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# -# 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. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK -package RT::Action::NotifyAsComment; -require RT::Action::Notify; - -use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Action::Notify); - - -=head2 SetReturnAddress - -Tell SendEmail that this message should come out as a comment. -Calls SUPER::SetReturnAddress. - -=cut - -sub SetReturnAddress { - my $self = shift; - - # Tell RT::Action::SendEmail that this should come - # from the relevant comment email address. - $self->{'comment'} = 1; - - return($self->SUPER::SetReturnAddress(is_comment => 1)); -} - -eval "require RT::Action::NotifyAsComment_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/NotifyAsComment_Vendor.pm}); -eval "require RT::Action::NotifyAsComment_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/NotifyAsComment_Local.pm}); - -1; - diff --git a/rt/lib/RT/Action/NotifyGroup.pm b/rt/lib/RT/Action/NotifyGroup.pm deleted file mode 100644 index 131c583d9..000000000 --- a/rt/lib/RT/Action/NotifyGroup.pm +++ /dev/null @@ -1,214 +0,0 @@ -# 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 $creatorObj = $self->TransactionObj->CreatorObj; - my $creator = $creatorObj->EmailAddress(); - - my $TransactionCurrentUser = RT::CurrentUser->new; - $TransactionCurrentUser->LoadByName($creatorObj->Name); - - unless (RT->Config->Get('NotifyActor',$TransactionCurrentUser)) { - @{ $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 deleted file mode 100644 index bee0a01a1..000000000 --- a/rt/lib/RT/Action/NotifyGroupAsComment.pm +++ /dev/null @@ -1,91 +0,0 @@ -# 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 deleted file mode 100644 index bac17e96e..000000000 --- a/rt/lib/RT/Action/RecordComment.pm +++ /dev/null @@ -1,119 +0,0 @@ -# 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::RecordComment; -use base 'RT::Action'; -use strict; - -=head1 NAME - -RT::Action::RecordComment - An Action which can be used from an -external tool, or in any situation where a ticket transaction has not -been started, to make a comment on the ticket. - -=head1 SYNOPSIS - -my $action_obj = RT::Action::RecordComment->new('TicketObj' => $ticket_obj, - 'TemplateObj' => $template_obj, - ); -my $result = $action_obj->Prepare(); -$action_obj->Commit() if $result; - -=head1 METHODS - -=head2 Prepare - -Check for the existence of a Transaction. If a Transaction already -exists, and is of type "Comment" or "Correspond", abort because that -will give us a loop. - -=cut - - -sub Prepare { - my $self = shift; - if (defined $self->{'TransactionObj'} && - $self->{'TransactionObj'}->Type =~ /^(Comment|Correspond)$/) { - return undef; - } - return 1; -} - -=head2 Commit - -Create a Transaction by calling the ticket's Comment method on our -parsed Template, which may have an RT-Send-Cc or RT-Send-Bcc header. -The Transaction will be of type Comment. This Transaction can then be -used by the scrips that actually send the email. - -=cut - -sub Commit { - my $self = shift; - $self->CreateTransaction(); -} - -sub CreateTransaction { - my $self = shift; - - my ($result, $msg) = $self->{'TemplateObj'}->Parse( - TicketObj => $self->{'TicketObj'}); - return undef unless $result; - - my ($trans, $desc, $transaction) = $self->{'TicketObj'}->Comment( - MIMEObj => $self->TemplateObj->MIMEObj); - $self->{'TransactionObj'} = $transaction; -} - - -eval "require RT::Action::RecordComment_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/RecordComment_Vendor.pm}); -eval "require RT::Action::RecordComment_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/RecordComment_Local.pm}); - -1; diff --git a/rt/lib/RT/Action/RecordCorrespondence.pm b/rt/lib/RT/Action/RecordCorrespondence.pm deleted file mode 100644 index 044893b97..000000000 --- a/rt/lib/RT/Action/RecordCorrespondence.pm +++ /dev/null @@ -1,120 +0,0 @@ -# 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::RecordCorrespondence; -use base 'RT::Action'; -use strict; - -=head1 NAME - -RT::Action::RecordCorrespondence - An Action which can be used from an -external tool, or in any situation where a ticket transaction has not -been started, to make a comment on the ticket. - -=head1 SYNOPSIS - -my $action_obj = RT::Action::RecordCorrespondence->new( - 'TicketObj' => $ticket_obj, - 'TemplateObj' => $template_obj, - ); -my $result = $action_obj->Prepare(); -$action_obj->Commit() if $result; - -=head1 METHODS - -=head2 Prepare - -Check for the existence of a Transaction. If a Transaction already -exists, and is of type "Comment" or "Correspond", abort because that -will give us a loop. - -=cut - - -sub Prepare { - my $self = shift; - if (defined $self->{'TransactionObj'} && - $self->{'TransactionObj'}->Type =~ /^(Comment|Correspond)$/) { - return undef; - } - return 1; -} - -=head2 Commit - -Create a Transaction by calling the ticket's Correspond method on our -parsed Template, which may have an RT-Send-Cc or RT-Send-Bcc header. -The Transaction will be of type Correspond. This Transaction can then -be used by the scrips that actually send the email. - -=cut - -sub Commit { - my $self = shift; - $self->CreateTransaction(); -} - -sub CreateTransaction { - my $self = shift; - - my ($result, $msg) = $self->{'TemplateObj'}->Parse( - TicketObj => $self->{'TicketObj'}); - return undef unless $result; - - my ($trans, $desc, $transaction) = $self->{'TicketObj'}->Correspond( - MIMEObj => $self->TemplateObj->MIMEObj); - $self->{'TransactionObj'} = $transaction; -} - - -eval "require RT::Action::RecordCorrespondence_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/RecordCorrespondence_Vendor.pm}); -eval "require RT::Action::RecordCorrespondence_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/RecordCorrespondence_Local.pm}); - -1; diff --git a/rt/lib/RT/Action/ResolveMembers.pm b/rt/lib/RT/Action/ResolveMembers.pm deleted file mode 100644 index 02ff3a58c..000000000 --- a/rt/lib/RT/Action/ResolveMembers.pm +++ /dev/null @@ -1,88 +0,0 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# -# 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. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK -# This Action will resolve all members of a resolved group ticket - -package RT::Action::ResolveMembers; -require RT::Action::Generic; -require RT::Links; - -use strict; -use vars qw/@ISA/; -@ISA=qw(RT::Action::Generic); - -#Do what we need to do and send it out. - -#What does this type of Action does - -# {{{ sub Describe -sub Describe { - my $self = shift; - return $self->loc("[_1] will resolve all members of a resolved group ticket.", ref $self); -} -# }}} - - -# {{{ sub Prepare -sub Prepare { - # nothing to prepare - return 1; -} -# }}} - -sub Commit { - my $self = shift; - - my $Links=RT::Links->new($RT::SystemUser); - $Links->Limit(FIELD => 'Type', VALUE => 'MemberOf'); - $Links->Limit(FIELD => 'Target', VALUE => $self->TicketObj->id); - - while (my $Link=$Links->Next()) { - # Todo: Try to deal with remote URIs as well - next unless $Link->BaseURI->IsLocal; - my $base=RT::Ticket->new($self->TicketObj->CurrentUser); - # Todo: Only work if Base is a plain ticket num: - $base->Load($Link->Base); - # I'm afraid this might be a major bottleneck if ResolveGroupTicket is on. - $base->Resolve; - } -} - - -# Applicability checked in Commit. - -# {{{ sub IsApplicable -sub IsApplicable { - my $self = shift; - 1; - return 1; -} -# }}} - -eval "require RT::Action::ResolveMembers_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/ResolveMembers_Vendor.pm}); -eval "require RT::Action::ResolveMembers_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/ResolveMembers_Local.pm}); - -1; - diff --git a/rt/lib/RT/Action/SendEmail.pm b/rt/lib/RT/Action/SendEmail.pm deleted file mode 100755 index dac8fc8e7..000000000 --- a/rt/lib/RT/Action/SendEmail.pm +++ /dev/null @@ -1,685 +0,0 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# -# 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. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK -# Portions Copyright 2000 Tobias Brox <tobix@cpan.org> - -package RT::Action::SendEmail; -require RT::Action::Generic; - -use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Action::Generic); - -use MIME::Words qw(encode_mimeword); - -use RT::EmailParser; - -=head1 NAME - -RT::Action::SendEmail - An Action which users can use to send mail -or can subclassed for more specialized mail sending behavior. -RT::Action::AutoReply is a good example subclass. - -=head1 SYNOPSIS - - require RT::Action::SendEmail; - @ISA = qw(RT::Action::SendEmail); - - -=head1 DESCRIPTION - -Basically, you create another module RT::Action::YourAction which ISA -RT::Action::SendEmail. - -If you want to set the recipients of the mail to something other than -the addresses mentioned in the To, Cc, Bcc and headers in -the template, you should subclass RT::Action::SendEmail and override -either the SetRecipients method or the SetTo, SetCc, etc methods (see -the comments for the SetRecipients sub). - - -=begin testing - -ok (require RT::Action::SendEmail); - -=end testing - - -=head1 AUTHOR - -Jesse Vincent <jesse@bestpractical.com> and Tobias Brox <tobix@cpan.org> - -=head1 SEE ALSO - -perl(1). - -=cut - -# {{{ Scrip methods (_Init, Commit, Prepare, IsApplicable) - -# {{{ sub _Init -# We use _Init from RT::Action -# }}} - -# {{{ sub Commit -#Do what we need to do and send it out. -sub Commit { - my $self = shift; - - my $MIMEObj = $self->TemplateObj->MIMEObj; - my $msgid = $MIMEObj->head->get('Message-Id'); - chomp $msgid; - $RT::Logger->info($msgid." #".$self->TicketObj->id."/".$self->TransactionObj->id." - Scrip ". $self->ScripObj->id ." ".$self->ScripObj->Description); - #send the email - - # Weed out any RT addresses. We really don't want to talk to ourselves! - @{$self->{'To'}} = RT::EmailParser::CullRTAddresses("", @{$self->{'To'}}); - @{$self->{'Cc'}} = RT::EmailParser::CullRTAddresses("", @{$self->{'Cc'}}); - @{$self->{'Bcc'}} = RT::EmailParser::CullRTAddresses("", @{$self->{'Bcc'}}); - # If there are no recipients, don't try to send the message. - # If the transaction has content and has the header RT-Squelch-Replies-To - - if ( defined $self->TransactionObj->Attachments->First() ) { - - my $squelch = $self->TransactionObj->Attachments->First->GetHeader( 'RT-Squelch-Replies-To'); - - if ($squelch) { - my @blacklist = split ( /,/, $squelch ); - - # Cycle through the people we're sending to and pull out anyone on the - # system blacklist - - foreach my $person_to_yank (@blacklist) { - $person_to_yank =~ s/\s//g; - @{ $self->{'To'} } = - grep ( !/^$person_to_yank$/, @{ $self->{'To'} } ); - @{ $self->{'Cc'} } = - grep ( !/^$person_to_yank$/, @{ $self->{'Cc'} } ); - @{ $self->{'Bcc'} } = - grep ( !/^$person_to_yank$/, @{ $self->{'Bcc'} } ); - } - } - } - - # Go add all the Tos, Ccs and Bccs that we need to to the message to - # make it happy, but only if we actually have values in those arrays. - - $self->SetHeader( 'To', join ( ',', @{ $self->{'To'} } ) ) - if ( $self->{'To'} && @{ $self->{'To'} } ); - $self->SetHeader( 'Cc', join ( ',', @{ $self->{'Cc'} } ) ) - if ( $self->{'Cc'} && @{ $self->{'Cc'} } ); - $self->SetHeader( 'Bcc', join ( ',', @{ $self->{'Bcc'} } ) ) - if ( $self->{'Cc'} && @{ $self->{'Bcc'} } ); - - - $self->SetHeader('MIME-Version', '1.0'); - - # try to convert message body from utf-8 to $RT::EmailOutputEncoding - $self->SetHeader( 'Content-Type', 'text/plain; charset="utf-8"' ); - - RT::I18N::SetMIMEEntityToEncoding( $MIMEObj, $RT::EmailOutputEncoding, 'mime_words_ok' ); - $self->SetHeader( 'Content-Type', 'text/plain; charset="' . $RT::EmailOutputEncoding . '"' ); - - - # Build up a MIME::Entity that looks like the original message. - - my $do_attach = $self->TemplateObj->MIMEObj->head->get('RT-Attach-Message'); - - if ($do_attach) { - $self->TemplateObj->MIMEObj->head->delete('RT-Attach-Message'); - - my $attachments = RT::Attachments->new($RT::SystemUser); - $attachments->Limit( FIELD => 'TransactionId', - VALUE => $self->TransactionObj->Id ); - $attachments->OrderBy('id'); - - my $transaction_content_obj = $self->TransactionObj->ContentObj; - - # attach any of this transaction's attachments - while ( my $attach = $attachments->Next ) { - - # Don't attach anything blank - next unless ( $attach->ContentLength ); - - # We want to make sure that we don't include the attachment that's being sued as the "Content" of this message" - next - if ( $transaction_content_obj - && $transaction_content_obj->Id == $attach->Id - && $transaction_content_obj->ContentType =~ qr{text/plain}i - ); - $MIMEObj->make_multipart('mixed'); - $MIMEObj->attach( Type => $attach->ContentType, - Charset => $attach->OriginalEncoding, - Data => $attach->OriginalContent, - Filename => $self->MIMEEncodeString( $attach->Filename, $RT::EmailOutputEncoding ), - Encoding => '-SUGGEST'); - } - - } - - - my $retval = $self->SendMessage($MIMEObj); - - - return ($retval); -} - -# }}} - -# {{{ sub Prepare - -sub Prepare { - my $self = shift; - - # This actually populates the MIME::Entity fields in the Template Object - - unless ( $self->TemplateObj ) { - $RT::Logger->warning("No template object handed to $self\n"); - } - - unless ( $self->TransactionObj ) { - $RT::Logger->warning("No transaction object handed to $self\n"); - - } - - unless ( $self->TicketObj ) { - $RT::Logger->warning("No ticket object handed to $self\n"); - - } - - my ( $result, $message ) = $self->TemplateObj->Parse( - Argument => $self->Argument, - TicketObj => $self->TicketObj, - TransactionObj => $self->TransactionObj - ); - if ($result) { - - # Header - $self->SetSubject(); - $self->SetSubjectToken(); - $self->SetRecipients(); - $self->SetReturnAddress(); - $self->SetRTSpecialHeaders(); - if ($RT::EmailOutputEncoding) { - - # l10n related header - $self->SetHeaderAsEncoding( 'Subject', $RT::EmailOutputEncoding ); - } - } - - return $result; - -} - -# }}} - -# }}} - -# {{{ SendMessage -=head2 SendMessage MIMEObj - -sends the message using RT's preferred API. -TODO: Break this out to a seperate module - -=cut - -sub SendMessage { - my $self = shift; - my $MIMEObj = shift; - - my $msgid = $MIMEObj->head->get('Message-Id'); - - - #If we don't have any recipients to send to, don't send a message; - unless ( $MIMEObj->head->get('To') - || $MIMEObj->head->get('Cc') - || $MIMEObj->head->get('Bcc') ) { - $RT::Logger->info($msgid. " No recipients found. Not sending.\n"); - return (1); - } - - # PseudoTo (fake to headers) shouldn't get matched for message recipients. - # If we don't have any 'To' header, drop in the pseudo-to header. - - $self->SetHeader( 'To', join ( ',', @{ $self->{'PseudoTo'} } ) ) - if ( $self->{'PseudoTo'} && ( @{ $self->{'PseudoTo'} } ) - and ( !$MIMEObj->head->get('To') ) ); - if ( $RT::MailCommand eq 'sendmailpipe' ) { - eval { - open( MAIL, "|$RT::SendmailPath $RT::SendmailArguments" ); - print MAIL $MIMEObj->as_string; - close(MAIL); - }; - if ($@) { - $RT::Logger->crit($msgid. "Could not send mail. -".$@ ); - } - } - else { - my @mailer_args = ($RT::MailCommand); - local $ENV{MAILADDRESS}; - - if ( $RT::MailCommand eq 'sendmail' ) { - push @mailer_args, $RT::SendmailArguments; - } - elsif ( $RT::MailCommand eq 'smtp' ) { - $ENV{MAILADDRESS} = $RT::SMTPFrom || $MIMEObj->head->get('From'); - push @mailer_args, (Server => $RT::SMTPServer); - push @mailer_args, (Debug => $RT::SMTPDebug); - } - else { - push @mailer_args, $RT::MailParams; - } - - unless ( $MIMEObj->send( @mailer_args ) ) { - $RT::Logger->crit($msgid. "Could not send mail." ); - return (0); - } - } - - - my $success = ($msgid. " sent To: ".$MIMEObj->head->get('To') . " Cc: ".$MIMEObj->head->get('Cc') . " Bcc: ".$MIMEObj->head->get('Bcc')); - $success =~ s/\n//gi; - $RT::Logger->info($success); - - return (1); -} - -# }}} - -# {{{ Deal with message headers (Set* subs, designed for easy overriding) - -# {{{ sub SetRTSpecialHeaders - -=head2 SetRTSpecialHeaders - -This routine adds all the random headers that RT wants in a mail message -that don't matter much to anybody else. - -=cut - -sub SetRTSpecialHeaders { - my $self = shift; - - $self->SetReferences(); - - $self->SetMessageID(); - - $self->SetPrecedence(); - - $self->SetHeader( 'X-RT-Loop-Prevention', $RT::rtname ); - $self->SetHeader( 'RT-Ticket', - $RT::rtname . " #" . $self->TicketObj->id() ); - $self->SetHeader( 'Managed-by', - "RT $RT::VERSION (http://www.bestpractical.com/rt/)" ); - - $self->SetHeader( 'RT-Originator', - $self->TransactionObj->CreatorObj->EmailAddress ); - return (); - -} - -# {{{ sub SetReferences - -=head2 SetReferences - - # This routine will set the References: and In-Reply-To headers, -# autopopulating it with all the correspondence on this ticket so -# far. This should make RT responses threadable. - -=cut - -sub SetReferences { - my $self = shift; - - # TODO: this one is broken. What is this email really a reply to? - # If it's a reply to an incoming message, we'll need to use the - # actual message-id from the appropriate Attachment object. For - # incoming mails, we would like to preserve the In-Reply-To and/or - # References. - - $self->SetHeader( 'In-Reply-To', - "<rt-" . $self->TicketObj->id() . "\@" . $RT::rtname . ">" ); - - # TODO We should always add References headers for all message-ids - # of previous messages related to this ticket. -} - -# }}} - -# {{{ sub SetMessageID - -=head2 SetMessageID - -Without this one, threading won't work very nice in email agents. -Anyway, I'm not really sure it's that healthy if we need to send -several separate/different emails about the same transaction. - -=cut - -sub SetMessageID { - my $self = shift; - - # TODO this one might be sort of broken. If we have several scrips +++ - # sending several emails to several different persons, we need to - # pull out different message-ids. I'd suggest message ids like - # "rt-ticket#-transaction#-scrip#-receipient#" - - $self->SetHeader( 'Message-ID', - "<rt-" - . $RT::VERSION ."-" - . $self->TicketObj->id() . "-" - . $self->TransactionObj->id() . "." - . rand(20) . "\@" - . $RT::Organization . ">" ) - unless $self->TemplateObj->MIMEObj->head->get('Message-ID'); -} - -# }}} - -# }}} - -# {{{ sub SetReturnAddress - -=head2 SetReturnAddress is_comment => BOOLEAN - -Calculate and set From and Reply-To headers based on the is_comment flag. - -=cut - -sub SetReturnAddress { - - my $self = shift; - my %args = ( is_comment => 0, - @_ ); - - # From and Reply-To - # $args{is_comment} should be set if the comment address is to be used. - my $replyto; - - if ( $args{'is_comment'} ) { - $replyto = $self->TicketObj->QueueObj->CommentAddress - || $RT::CommentAddress; - } - else { - $replyto = $self->TicketObj->QueueObj->CorrespondAddress - || $RT::CorrespondAddress; - } - - unless ( $self->TemplateObj->MIMEObj->head->get('From') ) { - if ($RT::UseFriendlyFromLine) { - my $friendly_name = $self->TransactionObj->CreatorObj->RealName; - if ( $friendly_name =~ /^"(.*)"$/ ) { # a quoted string - $friendly_name = $1; - } - - $friendly_name =~ s/"/\\"/g; - $self->SetHeader( 'From', - sprintf($RT::FriendlyFromLineFormat, - $self->MIMEEncodeString( $friendly_name, $RT::EmailOutputEncoding ), $replyto), - ); - } - else { - $self->SetHeader( 'From', $replyto ); - } - } - - unless ( $self->TemplateObj->MIMEObj->head->get('Reply-To') ) { - $self->SetHeader( 'Reply-To', "$replyto" ); - } - -} - -# }}} - -# {{{ sub SetHeader - -=head2 SetHeader FIELD, VALUE - -Set the FIELD of the current MIME object into VALUE. - -=cut - -sub SetHeader { - my $self = shift; - my $field = shift; - my $val = shift; - - chomp $val; - chomp $field; - $self->TemplateObj->MIMEObj->head->fold_length( $field, 10000 ); - $self->TemplateObj->MIMEObj->head->replace( $field, $val ); - return $self->TemplateObj->MIMEObj->head->get($field); -} - -# }}} - -# {{{ sub SetRecipients - -=head2 SetRecipients - -Dummy method to be overriden by subclasses which want to set the recipients. - -=cut - -sub SetRecipients { - my $self = shift; - return (); -} - -# }}} - -# {{{ sub SetTo - -=head2 SetTo - -Takes a string that is the addresses you want to send mail to - -=cut - -sub SetTo { - my $self = shift; - my $addresses = shift; - return $self->SetHeader( 'To', $addresses ); -} - -# }}} - -# {{{ sub SetCc - -=head2 SetCc - -Takes a string that is the addresses you want to Cc - -=cut - -sub SetCc { - my $self = shift; - my $addresses = shift; - - return $self->SetHeader( 'Cc', $addresses ); -} - -# }}} - -# {{{ sub SetBcc - -=head2 SetBcc - -Takes a string that is the addresses you want to Bcc - -=cut - -sub SetBcc { - my $self = shift; - my $addresses = shift; - - return $self->SetHeader( 'Bcc', $addresses ); -} - -# }}} - -# {{{ sub SetPrecedence - -sub SetPrecedence { - my $self = shift; - - unless ( $self->TemplateObj->MIMEObj->head->get("Precedence") ) { - $self->SetHeader( 'Precedence', "bulk" ); - } -} - -# }}} - -# {{{ sub SetSubject - -=head2 SetSubject - -This routine sets the subject. it does not add the rt tag. that gets done elsewhere -If $self->{'Subject'} is already defined, it uses that. otherwise, it tries to get -the transaction's subject. - -=cut - -sub SetSubject { - my $self = shift; - my $subject; - - unless ( $self->TemplateObj->MIMEObj->head->get('Subject') ) { - my $message = $self->TransactionObj->Attachments; - my $ticket = $self->TicketObj->Id; - - if ( $self->{'Subject'} ) { - $subject = $self->{'Subject'}; - } - elsif ( ( $message->First() ) - && ( $message->First->Headers ) ) { - my $header = $message->First->Headers(); - $header =~ s/\n\s+/ /g; - if ( $header =~ /^Subject: (.*?)$/m ) { - $subject = $1; - } - else { - $subject = $self->TicketObj->Subject(); - } - - } - else { - $subject = $self->TicketObj->Subject(); - } - - $subject =~ s/(\r\n|\n|\s)/ /gi; - - chomp $subject; - $self->SetHeader( 'Subject', $subject ); - - } - return ($subject); -} - -# }}} - -# {{{ sub SetSubjectToken - -=head2 SetSubjectToken - -This routine fixes the RT tag in the subject. It's unlikely that you want to overwrite this. - -=cut - -sub SetSubjectToken { - my $self = shift; - my $tag = "[$RT::rtname #" . $self->TicketObj->id . "]"; - my $sub = $self->TemplateObj->MIMEObj->head->get('Subject'); - unless ( $sub =~ /\Q$tag\E/ ) { - $sub =~ s/(\r\n|\n|\s)/ /gi; - chomp $sub; - $self->TemplateObj->MIMEObj->head->replace( 'Subject', "$tag $sub" ); - } -} - -# }}} - -# }}} - -# {{{ - -=head2 SetHeaderAsEncoding($field_name, $charset_encoding) - -This routine converts the field into specified charset encoding. - -=cut - -sub SetHeaderAsEncoding { - my $self = shift; - my ( $field, $enc ) = ( shift, shift ); - - if ($field eq 'From' and $RT::SMTPFrom) { - $self->TemplateObj->MIMEObj->head->replace( $field, $RT::SMTPFrom ); - return; - } - - my $value = $self->TemplateObj->MIMEObj->head->get($field); - - # don't bother if it's us-ascii - - # See RT::I18N, 'NOTES: Why Encode::_utf8_off before Encode::from_to' - - $value = $self->MIMEEncodeString($value, $enc); - - $self->TemplateObj->MIMEObj->head->replace( $field, $value ); - - -} -# }}} - -# {{{ MIMENcodeString - -=head2 MIMEEncodeString STRING ENCODING - -Takes a string and a possible encoding and returns the string wrapped in MIME goo. - -=cut - -sub MIMEEncodeString { - my $self = shift; - my $value = shift; - my $enc = shift; - - chomp $value; - return ($value) unless $value =~ /[^\x20-\x7e]/; - - $value =~ s/\s*$//; - Encode::_utf8_off($value); - my $res = Encode::from_to( $value, "utf-8", $enc ); - $value = encode_mimeword( $value, 'B', $enc ); -} - -# }}} - -eval "require RT::Action::SendEmail_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/SendEmail_Vendor.pm}); -eval "require RT::Action::SendEmail_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/SendEmail_Local.pm}); - -1; - diff --git a/rt/lib/RT/Action/SetPriority.pm b/rt/lib/RT/Action/SetPriority.pm deleted file mode 100644 index 9b0838926..000000000 --- a/rt/lib/RT/Action/SetPriority.pm +++ /dev/null @@ -1,84 +0,0 @@ -# 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::SetPriority; -use base 'RT::Action'; - -use strict; - -#Do what we need to do and send it out. - -#What does this type of Action does - -# {{{ sub Describe -sub Describe { - my $self = shift; - return (ref $self . " will set a ticket's priority to the argument provided."); -} -# }}} - - -# {{{ sub Prepare -sub Prepare { - # nothing to prepare - return 1; -} -# }}} - -sub Commit { - my $self = shift; - $self->TicketObj->SetPriority($self->Argument); - -} - -eval "require RT::Action::SetPriority_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/SetPriority_Vendor.pm}); -eval "require RT::Action::SetPriority_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/SetPriority_Local.pm}); - -1; diff --git a/rt/lib/RT/Action/UserDefined.pm b/rt/lib/RT/Action/UserDefined.pm deleted file mode 100644 index 80ef49224..000000000 --- a/rt/lib/RT/Action/UserDefined.pm +++ /dev/null @@ -1,92 +0,0 @@ -# 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::UserDefined; -use base 'RT::Action'; - -use strict; - -=head2 Prepare - -This happens on every transaction. it's always applicable - -=cut - -sub Prepare { - my $self = shift; - my $retval = eval $self->ScripObj->CustomPrepareCode; - if ($@) { - $RT::Logger->error("Scrip ".$self->ScripObj->Id. " Prepare failed: ".$@); - return (undef); - } - return ($retval); -} - -=head2 Commit - -This happens on every transaction. it's always applicable - -=cut - -sub Commit { - my $self = shift; - my $retval = eval $self->ScripObj->CustomCommitCode; - if ($@) { - $RT::Logger->error("Scrip ".$self->ScripObj->Id. " Commit failed: ".$@); - return (undef); - } - return ($retval); -} - -eval "require RT::Action::UserDefined_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/UserDefined_Vendor.pm}); -eval "require RT::Action::UserDefined_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/UserDefined_Local.pm}); - -1; - |