diff options
| author | ivan <ivan> | 2008-03-02 04:11:51 +0000 | 
|---|---|---|
| committer | ivan <ivan> | 2008-03-02 04:11:51 +0000 | 
| commit | c648976f0b7975f2328ebd7ba8c711fad0ca4195 (patch) | |
| tree | f3d176ec300a46c253ba25a988b897bce02fe174 /rt/lib/RT/Action/CreateTickets.pm | |
| parent | 5e05724a635a22776f1b973f5d7e77989da4e048 (diff) | |
| parent | 8103c1fc1b2c27a6855feadf26f91b980a54bc52 (diff) | |
This commit was generated by cvs2svn to compensate for changes in r6255,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'rt/lib/RT/Action/CreateTickets.pm')
| -rw-r--r-- | rt/lib/RT/Action/CreateTickets.pm | 655 | 
1 files changed, 395 insertions, 260 deletions
| diff --git a/rt/lib/RT/Action/CreateTickets.pm b/rt/lib/RT/Action/CreateTickets.pm index b708f2ea5..4e72e1151 100644 --- a/rt/lib/RT/Action/CreateTickets.pm +++ b/rt/lib/RT/Action/CreateTickets.pm @@ -2,7 +2,7 @@  #   # COPYRIGHT:  #   -# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC  +# This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC   #                                          <jesse@bestpractical.com>  #   # (Except where explicitly superseded by other copyright notices) @@ -22,7 +22,9 @@  #   # 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/copyleft/gpl.html.  #   #   # CONTRIBUTION SUBMISSION POLICY: @@ -188,7 +190,7 @@ A complete list of acceptable fields for this beastie:         Started         =>          Resolved        =>          Owner           => Username or id of an RT user who can and should own  -                          this ticket +                          this ticket; forces the owner if necessary     +   Requestor       => Email address     +   Cc              => Email address      +   AdminCc         => Email address  @@ -208,8 +210,15 @@ A complete list of acceptable fields for this beastie:                            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 +       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. @@ -545,7 +554,10 @@ sub Prepare {      } -    $self->Parse( Content => $self->TemplateObj->Content, _ActiveContent => 1); +    $self->Parse( +        Content        => $self->TemplateObj->Content, +        _ActiveContent => 1 +    );      return 1;  } @@ -566,43 +578,41 @@ sub CreateByTemplate {      use bytes;      local %T::Tickets = %T::Tickets; -    local $T::TOP = $T::TOP; -    local $T::ID = $T::ID; +    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; +            if $T::TOP;          $T::ID    = $template_id;          @T::AllID = @{ $self->{'create_tickets'} }; -        ( $T::Tickets{$template_id}, $ticketargs ) = -          $self->ParseLines( $template_id, \@links, \@postponed ); +        ( $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); +        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; +                $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 related ticket $template_id for " +                    . $self->TicketObj->Id . " " +                    . $msg; +            } else {                  $msg = "Couldn't create ticket $template_id " . $msg;              } @@ -612,8 +622,8 @@ sub CreateByTemplate {          $RT::Logger->debug("Assigned $template_id with $id");          $T::Tickets{$template_id}->SetOriginObj( $self->TicketObj ) -          if $self->TicketObj -          && $T::Tickets{$template_id}->can('SetOriginObj'); +            if $self->TicketObj +            && $T::Tickets{$template_id}->can('SetOriginObj');      } @@ -631,7 +641,7 @@ sub UpdateByTemplate {      my @results;      local %T::Tickets = %T::Tickets; -    local $T::ID = $T::ID; +    local $T::ID      = $T::ID;      my $ticketargs;      my ( @links, @postponed ); @@ -641,37 +651,35 @@ sub UpdateByTemplate {          $T::ID    = $template_id;          @T::AllID = @{ $self->{'update_tickets'} }; -        ( $T::Tickets{$template_id}, $ticketargs ) = -          $self->ParseLines( $template_id, \@links, \@postponed ); +        ( $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 +            Subject +            FinalPriority +            Priority +            TimeEstimated +            TimeWorked +            TimeLeft +            Status +            Queue +            Due +            Starts +            Started +            Resolved          );          my $id = $template_id;          $id =~ s/update-(\d+).*/$1/; -        $T::Tickets{$template_id}->Load($id); - -        my $msg; -        if ( !$T::Tickets{$template_id}->Id ) { -            $msg = "Couldn't update ticket $template_id " . $msg; +        my ($loaded, $msg) = $T::Tickets{$template_id}->LoadById($id); -            $RT::Logger->error($msg); +        unless ( $loaded ) { +            $RT::Logger->error("Couldn't update ticket $template_id: " . $msg); +            push @results, $self->loc( "Couldn't load ticket '[_1]'", $id );              next;          } @@ -681,60 +689,68 @@ sub UpdateByTemplate {          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; -        } +            $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 ); +            $self->UpdateWatchers( $T::Tickets{$template_id}, $ticketargs ); -        next unless exists $ticketargs->{'UpdateType'}; -        if ( $ticketargs->{'UpdateType'} =~ /^(private|public)$/ ) { -            my ( $Transaction, $Description, $Object ) = -              $T::Tickets{$template_id}->Comment( -                CcMessageTo  => $ticketargs->{'Cc'}, +        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'} eq 'response' ) { -            my ( $Transaction, $Description, $Object ) = -              $T::Tickets{$template_id}->Correspond( -                CcMessageTo  => $ticketargs->{'Cc'}, +                    ->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.") ); +                    ->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.") +            );          }      } @@ -753,35 +769,58 @@ 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; +    my $self = shift; +    my %args = ( +        Content        => undef, +        Queue          => undef, +        Requestor      => undef, +        _ActiveContent => undef, +        @_ +    ); + +    if ( $args{'_ActiveContent'} ) { +        $self->{'UsePerlTextTemplate'} = 1;      } else {          $self->{'UsePerlTextTemplate'} = 0;      } -    my @template_order; +    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 ); -    if ( substr( $args{'Content'}, 0, 3 ) eq '===' ) {          $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"; +                    $self->{'templates'}->{$template_id} +                        .= "Queue: $args{'Queue'}\n";                  }                  if ( $template_id && !$requestor && $args{'Requestor'} ) { -                    $self->{'templates'}->{$template_id} .= -                      "Requestor: $args{'Requestor'}\n"; +                    $self->{'templates'}->{$template_id} +                        .= "Requestor: $args{'Requestor'}\n";                  }                  $queue     = 0;                  $requestor = 0; @@ -790,37 +829,33 @@ sub Parse {                  $template_id = "create-$1";                  $RT::Logger->debug("****  Create ticket: $template_id");                  push @{ $self->{'create_tickets'} }, $template_id; -            } -            elsif ( $line =~ /^===Update-Ticket: (.*)$/ ) { +            } 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: (.*)$/ ) { +            } 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 +            } elsif ( $line =~ /^===#.*$/ ) {    # a comment                  next; -            } -            else { +            } else {                  if ( $line =~ /^Queue:(.*)/i ) {                      $queue = 1;                      my $value = $1;                      $value =~ s/^\s//;                      $value =~ s/\s$//; -                    if ( !$value && $args{'Queue'}) { +                    if ( !$value && $args{'Queue'} ) {                          $value = $args{'Queue'};                          $line  = "Queue: $value";                      }                  } -                if ( $line =~ /^Requestor:(.*)/i ) { +                if ( $line =~ /^Requestors?:(.*)/i ) {                      $requestor = 1;                      my $value = $1;                      $value =~ s/^\s//;                      $value =~ s/\s$//; -                    if ( !$value && $args{'Requestor'}) { +                    if ( !$value && $args{'Requestor'} ) {                          $value = $args{'Requestor'};                          $line  = "Requestor: $value";                      } @@ -828,118 +863,10 @@ sub Parse {                  $self->{'templates'}->{$template_id} .= $line . "\n";              }          } -	if ( $template_id && !$queue && $args{'Queue'} ) { -	    $self->{'templates'}->{$template_id} .= "Queue: $args{'Queue'}\n"; -	} -    } -    elsif ( substr( $args{'Content'}, 0, 2 ) =~ /^id$/i ) { -        $RT::Logger->debug("Line: id"); -        use Regexp::Common qw(delimited); -        my $first = substr( $args{'Content'}, 0, index( $args{'Content'}, "\n" ) ); -        $first =~ s/\r$//; - -        my $delimiter; -        if ( $first =~ /\t/ ) { -            $delimiter = "\t"; -        } -        else { -            $delimiter = ','; -        } -        my @fields    = split( /$delimiter/, $first ); -         - -        my $delimiter_re = qr[$delimiter]; - -        my $delimited = qr[[^$delimiter]+]; -        my $empty     = qr[^[$delimiter](?=[$delimiter])]; -        my $justquoted = qr[$RE{quoted}]; - -        $args{'Content'} = substr( $args{'Content'}, index( $args{'Content'}, "\n" ) + 1 ); -        $RT::Logger->debug("First: $first"); - -        my $queue; -        foreach my $line ( split( /\n/, $args{'Content'} ) ) { -            next unless $line; -            $RT::Logger->debug("Line: $line"); - -            # first item is $template_id -            my $i = 0; -            my $template_id; -            while ($line && $line =~ s/^($justquoted|.*?)(?:$delimiter_re|$)//ix) { -                if ( $i == 0 ) { -                    $queue     = 0; -                    $requestor = 0; -                    my $tid = $1; -                    $tid =~ s/^\s//; -                    $tid =~ s/\s$//; -                    next unless $tid; -                    -                      -                    if ($tid =~ /^\d+$/) { -                        $template_id = 'update-' . $tid; -                        push @{ $self->{'update_tickets'} }, $template_id; - -                    } elsif ($tid =~ /^#base-(\d+)$/) { - -                        $template_id = 'base-' . $1; -                        push @{ $self->{'base_tickets'} }, $template_id; - -                    } else { -                        $template_id = 'create-' . $tid; -                        push @{ $self->{'create_tickets'} }, $template_id; -                    } -                    $RT::Logger->debug("template_id: $tid"); -                } -                else { -                    my $value = $1; -                    $value = '' if ( $value =~ /^$delimiter$/ ); -                    if ($value =~ /^$RE{delimited}{-delim=>qq{\'\"}}$/) { -                        substr($value,0,1) = ""; -                    substr($value,-1,1) = ""; -                    } -                    my $field = $fields[$i]; -                    next unless $field; -                    $field =~ s/^\s//; -                    $field =~ s/\s$//; -                    if (   $field =~ /Body/i -                        || $field =~ /Data/i -                        || $field =~ /Message/i ) -                    { -                        $field = 'Content'; -                    } -                    if ( $field =~ /Summary/i ) { -                        $field = 'Subject'; -                    } -                    if ( $field =~ /Queue/i ) { -                        $queue = 1; -                        if ( !$value && $args{'Queue'} ) { -                            $value = $args{'Queue'}; -                        } -                    } -                    if ( $field =~ /Requestor/i ) { -                        $requestor = 1; -                        if ( !$value && $args{'Requestor'} ) { -                            $value = $args{'Requestor'}; -                        } -                    } -                    $self->{'templates'}->{$template_id} .= $field . ": "; -                    $self->{'templates'}->{$template_id} .= $value || ""; -                    $self->{'templates'}->{$template_id} .= "\n"; -                    $self->{'templates'}->{$template_id} .= "ENDOFCONTENT\n" -                      if $field =~ /content/i; -                } -                $i++; -            } -            if ( !$queue && $args{'Queue'} ) { -                $self->{'templates'}->{$template_id} .= "Queue: $args{'Queue'}\n"; -            } -            if ( !$requestor && $args{'Requestor'} ) { -                $self->{'templates'}->{$template_id} .= -                  "Requestor: $args{'Requestor'}\n"; -            } +        if ( $template_id && !$queue && $args{'Queue'} ) { +            $self->{'templates'}->{$template_id} .= "Queue: $args{'Queue'}\n";          }      } -}  sub ParseLines {      my $self        = shift; @@ -947,7 +874,6 @@ sub ParseLines {      my $links       = shift;      my $postponed   = shift; -      my $content = $self->{'templates'}->{$template_id};      if ( $self->{'UsePerlTextTemplate'} ) { @@ -980,69 +906,77 @@ sub ParseLines {              next;          }      } -     -    my $TicketObj ||= RT::Ticket->new($self->CurrentUser); + +    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 $tag   = lc($1); +            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} ) ) +            } 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 +            } else {    #if there's nothing there, just set the value                  $args{$tag} = $value;              } -            if ( $tag eq 'content' ) {    #just build up the content +            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 { - +            } 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); +        my $dateobj = RT::Date->new( $self->CurrentUser );          next unless $args{$date};          if ( $args{$date} =~ /^\d+$/ ) {              $dateobj->Set( Format => 'unix', Value => $args{$date} ); -        } -        else { -            $dateobj->Set( Format => 'unknown', 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; +        if $self->TicketObj;      $args{'type'} ||= 'ticket';      my %ticketargs = (          Queue           => $args{'queue'},          Subject         => $args{'subject'}, -        Status          => 'new', +        Status          => $args{'status'} || 'new',          Due             => $args{'due'},          Starts          => $args{'starts'},          Started         => $args{'started'}, @@ -1059,19 +993,32 @@ sub ParseLines {          Type            => $args{'type'},      ); -    if ($args{content}) { +    if ( $args{content} ) {          my $mimeobj = MIME::Entity->new();          $mimeobj->build( -            Type => $args{'contenttype'}, +            Type => $args{'contenttype'} || 'text/plain',              Data => $args{'content'}          );          $ticketargs{MIMEObj} = $mimeobj; -        $ticketargs{UpdateType} = $args{'updatetype'} if $args{'updatetype'}; +        $ticketargs{UpdateType} = $args{'updatetype'} || 'correspond';      } -    foreach my $key ( keys(%args) ) { -        $key =~ /^customfield(\d+)$/ or next; -        $ticketargs{ "CustomField-" . $1 } = $args{$key}; +    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 ); @@ -1079,6 +1026,137 @@ sub ParseLines {      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; @@ -1088,17 +1166,16 @@ sub GetDeferred {      # Deferred processing      push @$links, -      ( +        (          $id, -        { -            DependsOn    => $args->{'dependson'}, +        {   DependsOn    => $args->{'dependson'},              DependedOnBy => $args->{'dependedonby'},              RefersTo     => $args->{'refersto'},              ReferredToBy => $args->{'referredtoby'},              Children     => $args->{'children'},              Parents      => $args->{'parents'},          } -      ); +        );      push @$postponed, ( @@ -1115,7 +1192,7 @@ sub GetUpdateTemplate {      $string .= "Queue: " . $t->QueueObj->Name . "\n";      $string .= "Subject: " . $t->Subject . "\n";      $string .= "Status: " . $t->Status . "\n"; -    $string .= "UpdateType: response\n"; +    $string .= "UpdateType: correspond\n";      $string .= "Content: \n";      $string .= "ENDOFCONTENT\n";      $string .= "Due: " . $t->DueObj->AsString . "\n"; @@ -1234,14 +1311,31 @@ sub UpdateWatchers {      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( ', ', $oldaddr ); -        my @new = split( ', ', $newaddr ); +        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; @@ -1255,7 +1349,7 @@ sub UpdateWatchers {              );              push @results, -              $ticket->loc( "Ticket [_1]", $ticket->Id ) . ': ' . $msg; +                $ticket->loc( "Ticket [_1]", $ticket->Id ) . ': ' . $msg;          }          foreach (@delete) { @@ -1264,7 +1358,47 @@ sub UpdateWatchers {                  Email => $_              );              push @results, -              $ticket->loc( "Ticket [_1]", $ticket->Id ) . ': ' . $msg; +                $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; @@ -1289,21 +1423,22 @@ sub PostProcess {              {                  next unless $link; -                if ($link =~ /^TOP$/i) { -                    $RT::Logger->debug( "Building $type link for $link: " . $T::Tickets{TOP}->Id ); +                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+$/ ) { +                } elsif ( $link !~ m/^\d+$/ ) {                      my $key = "create-$link";                      if ( !exists $T::Tickets{$key} ) { -                        $RT::Logger->debug( "Skipping $type link for $key (non-existent)"); +                        $RT::Logger->debug( +                            "Skipping $type link for $key (non-existent)");                          next;                      } -                    $RT::Logger->debug( "Building $type link for $link: " . $T::Tickets{$key}->Id ); +                    $RT::Logger->debug( "Building $type link for $link: " +                            . $T::Tickets{$key}->Id );                      $link = $T::Tickets{$key}->Id; -                } -                else { +                } else {                      $RT::Logger->debug("Building $type link for $link");                  } @@ -1314,7 +1449,7 @@ sub PostProcess {                  );                  $RT::Logger->warning("AddLink thru $link failed: $wmsg") -                  unless $wval; +                    unless $wval;                  # push @non_fatal_errors, $wmsg unless ($wval);              } @@ -1325,7 +1460,7 @@ sub PostProcess {      # 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); +        $RT::Logger->debug( "Handling postponed actions for " . $ticket->id );          my %args = %{ shift(@$postponed) };          $ticket->SetStatus( $args{Status} ) if defined $args{Status};      } | 
