diff options
Diffstat (limited to 'rt/lib/RT/Action/ExtractCustomFieldValues.pm')
| -rw-r--r-- | rt/lib/RT/Action/ExtractCustomFieldValues.pm | 234 | 
1 files changed, 234 insertions, 0 deletions
| diff --git a/rt/lib/RT/Action/ExtractCustomFieldValues.pm b/rt/lib/RT/Action/ExtractCustomFieldValues.pm new file mode 100644 index 000000000..15aa469f0 --- /dev/null +++ b/rt/lib/RT/Action/ExtractCustomFieldValues.pm @@ -0,0 +1,234 @@ +package RT::Action::ExtractCustomFieldValues; +require RT::Action; + +use strict; +use warnings; + +use base qw(RT::Action); + +our $VERSION = 2.99_01; + +sub Describe { +    my $self = shift; +    return ( ref $self ); +} + +sub Prepare { +    return (1); +} + +sub FirstAttachment { +    my $self = shift; +    return $self->TransactionObj->Attachments->First; +} + +sub Queue { +    my $self = shift; +    return $self->TicketObj->QueueObj->Id; +} + +sub TemplateContent { +    my $self = shift; +    return $self->TemplateObj->Content; +} + +sub TemplateConfig { +    my $self = shift; + +    my ($content, $error) = $self->TemplateContent; +    if (!defined($content)) { +        return (undef, $error); +    } + +    my $Separator = '\|'; +    my @lines = split( /[\n\r]+/, $content); +    my @results; +    for (@lines) { +        chomp; +        next if /^#/; +        next if /^\s*$/; +        if (/^Separator=(.+)$/) { +            $Separator = $1; +            next; +        } +        my %line; +        @line{qw/CFName Field Match PostEdit Options/} +            = split(/$Separator/); +        $_ = '' for grep !defined, values %line; +        push @results, \%line; +    } +    return \@results; +} + +sub Commit { +    my $self            = shift; +    return 1 unless $self->FirstAttachment; + +    my ($config_lines, $error) = $self->TemplateConfig; + +    return 0 if $error; + +    for my $config (@$config_lines) { +        my %config = %{$config}; +        $RT::Logger->debug( "Looking to extract: " +                . join( " ", map {"$_=$config{$_}"} sort keys %config ) ); + +        if ( $config{Options} =~ /\*/ ) { +            $self->FindContent( +                %config, +                Callback    => sub { +                    my $content = shift; +                    my $found = 0; +                    while ( $content =~ /$config{Match}/mg ) { +                        my ( $cf, $value ) = ( $1, $2 ); +                        $cf = $self->LoadCF( Name => $cf, Quiet => 1 ); +                        next unless $cf; +                        $found++; +                        $self->ProcessCF( +                            %config, +                            CustomField => $cf, +                            Value       => $value +                        ); +                    } +                    return $found; +                }, +            ); +        } else { +            my $cf; +            $cf = $self->LoadCF( Name => $config{CFName} ) +                if $config{CFName}; + +            $self->FindContent( +                %config, +                Callback    => sub { +                    my $content = shift; +                    return 0 unless $content =~ /($config{Match})/m; +                    $self->ProcessCF( +                        %config, +                        CustomField => $cf, +                        Value       => $2 || $1, +                    ); +                    return 1; +                } +            ); +        } +    } +    return (1); +} + +sub LoadCF { +    my $self = shift; +    my %args            = @_; +    my $CustomFieldName = $args{Name}; +    $RT::Logger->debug( "Looking for CF $CustomFieldName"); + +    # We do this by hand instead of using LoadByNameAndQueue because +    # that can find disabled queues +    my $cfs = RT::CustomFields->new($RT::SystemUser); +    $cfs->LimitToGlobalOrQueue($self->Queue); +    $cfs->Limit( +        FIELD         => 'Name', +        VALUE         => $CustomFieldName, +        CASESENSITIVE => 0 +    ); +    $cfs->RowsPerPage(1); + +    my $cf = $cfs->First; +    if ( $cf && $cf->id ) { +        $RT::Logger->debug( "Found CF id " . $cf->id ); +    } elsif ( not $args{Quiet} ) { +        $RT::Logger->error( "Couldn't load CF $CustomFieldName!"); +    } + +    return $cf; +} + +sub FindContent { +    my $self = shift; +    my %args = @_; +    if ( lc $args{Field} eq "body" ) { +        my $Attachments  = $self->TransactionObj->Attachments; +        my $LastContent  = ''; +        my $AttachmentCount = 0; + +        my @list = @{ $Attachments->ItemsArrayRef }; +        while ( my $Message = shift @list ) { +            $AttachmentCount++; +            $RT::Logger->debug( "Looking at attachment $AttachmentCount, content-type " +                                    . $Message->ContentType ); +            my $ct = $Message->ContentType; +            unless ( $ct =~ m!^(text/plain|message|text$)!i ) { +                # don't skip one attachment that is text/* +                next if @list > 1 || $ct !~ m!^text/!; +            } + +            my $content = $Message->Content; +            next unless $content; +            next if $LastContent eq $content; +            $RT::Logger->debug( "Examining content of body" ); +            $LastContent = $content; +            $args{Callback}->( $content ); +        } +    } elsif ( lc $args{Field} eq 'headers' ) { +        my $attachment = $self->FirstAttachment; +        $RT::Logger->debug( "Looking at the headers of the first attachment" ); +        my $content = $attachment->Headers; +        return unless $content; +        $RT::Logger->debug( "Examining content of headers" ); +        $args{Callback}->( $content ); +    } else { +        my $attachment = $self->FirstAttachment; +        $RT::Logger->debug( "Looking at $args{Field} header of first attachment" ); +        my $content = $attachment->GetHeader( $args{Field} ); +        return unless defined $content; +        $RT::Logger->debug( "Examining content of header" ); +        $args{Callback}->( $content ); +    } +} + +sub ProcessCF { +    my $self = shift; +    my %args = @_; + +    return $self->PostEdit(%args) +        unless $args{CustomField}; + +    my @values = (); +    if ( $args{CustomField}->SingleValue() ) { +        push @values, $args{Value}; +    } else { +        @values = split( ',', $args{Value} ); +    } + +    foreach my $value ( grep defined && length, @values ) { +        $value = $self->PostEdit(%args, Value => $value ); +        next unless defined $value && length $value; + +        $RT::Logger->debug( "Found value for CF: $value"); +        my ( $id, $msg ) = $self->TicketObj->AddCustomFieldValue( +            Field             => $args{CustomField}, +            Value             => $value, +            RecordTransaction => $args{Options} =~ /q/ ? 0 : 1 +        ); +        $RT::Logger->info( "CustomFieldValue (" +                . $args{CustomField}->Name +                . ",$value) added: $id $msg" ); +    } +} + +sub PostEdit { +    my $self = shift; +    my %args = @_; + +    return $args{Value} unless $args{Value} && $args{PostEdit}; + +    $RT::Logger->debug( "Running PostEdit for '$args{Value}'"); +    my $value = $args{Value}; +    local $_  = $value;    # backwards compatibility +    local $@; +    eval( $args{PostEdit} ); +    $RT::Logger->error("$@") if $@; +    return $value; +} + +1; | 
