package RT::Action::GenerateTickets;
use base 'RT::Action';
use strict;
use warnings;
use MIME::Entity;
use RT::Link;
use Data::Dumper;
my @oTicket;
my $dependTicket;
my $subOwners;
my $mainOwner;
my $currentOwner;
my $defContent;
my $subQueue;
my $customSubject;
my @allSubjects;
my $customRequestor;
sub Commit {
my $self = shift;
# Create all the tickets we care about
return (1) unless $self->TicketObj->Type eq 'ticket';
@$dependTicket=[];
push(@$dependTicket, $self->TicketObj->id );
$defContent=$self->TransactionObj->Content;
$mainOwner=$self->TicketObj->QueueObj->FirstCustomFieldValue('Parent Owner');
$customRequestor=$self->TicketObj->QueueObj->FirstCustomFieldValue('Requestor');
$subQueue=$self->TicketObj->QueueObj->FirstCustomFieldValue('Destination Queue');
$customSubject=$self->TicketObj->QueueObj->FirstCustomFieldValue('Subject').': '.$self->TicketObj->Subject;
my @contentParts=split(';',$self->TicketObj->QueueObj->FirstCustomFieldValue('Ticket Texts (Divided by semicolons)'));
@$subOwners=split('\n', $self->TicketObj->QueueObj->CustomFieldValuesAsString('Sub owners'));
@allSubjects=split('\n', $self->TicketObj->QueueObj->CustomFieldValuesAsString('Subticket subjects'));
$currentOwner=$mainOwner;
@oTicket=$self->CreateByTemplate( $self->TicketObj );
RT::Logger->debug("--createBy size:");
RT::Logger->debug($self->TicketObj->QueueObj->FirstCustomFieldValue('Enable CC and Bcc'));
my @ticketParts = split(':', @oTicket[0]);
@ticketParts[0] =~ s/\D//g;
my $ticketId = @ticketParts[0];
@$dependTicket=[];
push(@$dependTicket, $ticketId);
RT::Logger->debug(@oTicket[0]);
@oTicket=$self->UpdateByTemplate( $self->TicketObj );
RT::Logger->debug("--updateBy");
RT::Logger->debug(scalar(@oTicket));
my $ticketCount=0;
for my $subOwner (@$subOwners){
if($ticketCount<scalar(@contentParts)){
$defContent = @contentParts[$ticketCount];
}else{
$defContent='';
}
if($ticketCount<scalar(@allSubjects)){
$customSubject = @allSubjects[$ticketCount].': '.$self->TicketObj->Subject;
}else{
$customSubject = ''.': '.$self->TicketObj->Subject;
}
$currentOwner=$subOwner;
$self->CreateByTemplate( $self->TicketObj);
$self->UpdateByTemplate( $self->TicketObj);
$ticketCount++;
}
return (1);
}
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");
}
my $active = 0;
if ( $self->TemplateObj->Type eq 'Perl' ) {
$active = 1;
} else {
RT->Logger->info(sprintf(
"Template #%d is type %s. You most likely want to use a Perl template instead.",
$self->TemplateObj->id, $self->TemplateObj->Type
));
}
$self->Parse(
Content => $self->TemplateObj->Content,
_ActiveContent => $active,
);
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;
local $T::TransactionObj = $self->TransactionObj;
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");
}
$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 );
RT::Logger->debug("--UpdateByTemplate");
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 );
RT::Logger->debug('Result 1: '.scalar(@results));
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";
RT::Logger->debug('Result 2: '.scalar(@results));
next;
}
}
push @results, $T::Tickets{$template_id}->Update(
AttributesRef => \@attribs,
ARGSRef => $ticketargs
);
RT::Logger->debug('Result 3: '.scalar(@results));
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");
RT::Logger->debug('Result 4: '.scalar(@results));
}
push @results, $self->UpdateWatchers( $T::Tickets{$template_id}, $ticketargs );
push @results, $self->UpdateCustomFields( $T::Tickets{$template_id}, $ticketargs );
RT::Logger->debug('Result 5: '.scalar(@results));
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 );
RT::Logger->debug('Result 6: '.scalar(@results));
} 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 );
RT::Logger->debug('Result 7: '.scalar(@results));
} else {
push(
@results,
$T::Tickets{$template_id}->loc(
"Update type was neither correspondence nor comment.")
. " "
. $T::Tickets{$template_id}->loc("Update not recorded.")
);
RT::Logger->debug('Result 8: '.scalar(@results));
}
}
$self->PostProcess( \@links, \@postponed );
RT::Logger->debug('Works till here');
RT::Logger->debug('Size: '.scalar(@results));
return @results;
}
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);
} else {
RT->Logger->error("Invalid Template Content (Couldn't find ===, and is not a csv/tsv template) - unable to parse: $args{Content}");
}
}
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 );
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";
# }
push @{ $args{content} }, $defContent;
} 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)(group)?$/i
or grep {lc $_ eq $tag} keys %RT::Link::TYPEMAP)
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 not $dateobj->IsSet) {
$dateobj->Set( Format => 'unknown', Value => $args{$date} );
}
}
$args{$date} = $dateobj->ISO;
}
foreach my $role (qw(requestor cc admincc)) {
next unless my $value = $args{ $role . 'group' };
my $group = RT::Group->new( $self->CurrentUser );
$group->LoadUserDefinedGroup( $value );
unless ( $group->id ) {
$RT::Logger->error("Couldn't load group '$value'");
next;
}
$args{ $role } = $args{ $role } ? [$args{ $role }] : []
unless ref $args{ $role };
push @{ $args{ $role } }, $group->PrincipalObj->id;
}
$args{'requestor'} ||= $self->TicketObj->Requestors->MemberEmailAddresses
if $self->TicketObj;
$args{'type'} ||= 'ticket';
my %ticketargs = (
Queue => $subQueue,
Subject => $customSubject,
Status => $args{'status'} || 'new',
Due => $args{'due'},
Starts => $args{'starts'},
Started => $args{'started'},
Resolved => $args{'resolved'},
Owner => $currentOwner,
Requestor => $customRequestor,
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'},
);
if ( $args{content} ) {
my $mimeobj = MIME::Entity->build(
Type => $args{'contenttype'} || 'text/plain',
Charset => 'UTF-8',
Data => [ map {Encode::encode( "UTF-8", $_ )} @{$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,
LookupType => RT::Ticket->CustomFieldLookupType,
ObjectId => $ticketargs{Queue},
IncludeGlobal => 1,
);
next unless $cf->id;
$ticketargs{ "CustomField-" . $cf->id } = $args{$tag};
} elsif ($orig_tag) {
my $cf = RT::CustomField->new( $self->CurrentUser );
$cf->LoadByName(
Name => $orig_tag,
LookupType => RT::Ticket->CustomFieldLookupType,
ObjectId => $ticketargs{Queue},
IncludeGlobal => 1,
);
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
L</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;
# Unify the aliases for child/parent
$args->{$_} = [$args->{$_}]
for grep {$args->{$_} and not ref $args->{$_}} qw/members hasmember memberof/;
push @{$args->{'children'}}, @{delete $args->{'members'}} if $args->{'members'};
push @{$args->{'children'}}, @{delete $args->{'hasmember'}} if $args->{'hasmember'};
push @{$args->{'parents'}}, @{delete $args->{'memberof'}} if $args->{'memberof'};
# Deferred processing
push @$links,
(
$id,
{ DependsOn => $args->{'dependson'},
DependedOnBy => $dependTicket,
RefersTo => $dependTicket,
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 ( RT::Link->DisplayTypes ) {
$string .= "$type: ";
my $mode = $RT::Link::TYPEMAP{$type}->{Mode};
my $method = $RT::Link::TYPEMAP{$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 .= "$defContent \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 ( RT::Link->DisplayTypes ) {
$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->SetContextObject( $ticket );
$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 if $ticket->CustomFieldValueIsEmpty(
Field => $CustomFieldObj,
Value => $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 %RT::Link::TYPEMAP ) {
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 => $RT::Link::TYPEMAP{$type}->{'Type'},
$RT::Link::TYPEMAP{$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};
}
}
RT::Base->_ImportOverlays();
1;