[Bps-public-commit] RT-Extension-ACNS branch, master, created. 31fd986a0a78a5c0ee92191614d523615071c6a0

Ruslan Zakirov ruz at bestpractical.com
Thu Jan 27 08:19:12 EST 2011


The branch, master has been created
        at  31fd986a0a78a5c0ee92191614d523615071c6a0 (commit)

- Log -----------------------------------------------------------------
commit 31fd986a0a78a5c0ee92191614d523615071c6a0
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Jan 27 16:18:44 2011 +0300

    initial commit

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..067e656
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+Makefile
+blib/
+pm_to_blib
+*.old
+*.bak
+*.swp
diff --git a/etc/RT_ACNSConfig.pm b/etc/RT_ACNSConfig.pm
new file mode 100644
index 0000000..46dcb66
--- /dev/null
+++ b/etc/RT_ACNSConfig.pm
@@ -0,0 +1,10 @@
+Set( %ACNS => 
+    Defaults => {
+        
+    },
+    Map => {
+        Boo => [qw(Source IP_Address)],
+        Boo => [qw(Content Item * URL)],
+    },
+
+);
diff --git a/lib/RT/Action/ParseACNS.pm b/lib/RT/Action/ParseACNS.pm
new file mode 100644
index 0000000..859ae2e
--- /dev/null
+++ b/lib/RT/Action/ParseACNS.pm
@@ -0,0 +1,209 @@
+use strict;
+use warnings;
+
+package RT::Condition::ParseACNS;
+use base 'RT::Action';
+
+use XML::LibXML;
+use Parse::ACNS;
+
+sub Prepare {
+    my $self = shift;
+
+    my $content = $self->TransactionObj->Content;
+    $content =~ s/^.*Start ACNS XML\n//s
+        or $RT::Logger->warn("No 'Start ACNS XML' marker");
+    $content =~ s/- -+End ACNS XML.*$//s
+        or $RT::Logger->warn("No 'End ACNS XML' marker");
+
+    my $xml = XML::LibXML->new->parse_string( $content );
+    my $data = Parse::ACNS->new->parse( $xml );
+    $self->{'ACNS'} = $self->MapDataOverCFs( $data );
+    return 1;
+}
+
+sub Commit {
+    my $self = shift;
+    
+    $self->UpdateCustomFields( $self->{'ACNS'} );
+    return 1;
+}
+
+sub UpdateCustomFields {
+    my $self = shift;
+    my $values = shift;
+    while ( my ($name, $value) = each %$values ) {
+        my $cf = $self->TicketObj->LoadCustomFieldByIdentifier( $name );
+        unless ( $cf && $cf->id ) {
+            $RT::Logger->error( "Ticket #". $self->TicketObj->id . "has no custom field '$name'");
+            next;
+        }
+        $self->UpdateCustomField( $cf, $value);
+    }
+}
+
+sub UpdateCustomField {
+    my $self = shift;
+    my $cf = shift;
+    my $value = shift;
+
+    my $ticket = $self->TicketObj;
+
+    if ( $cf->MaxValues == 1 ) {
+        if ( $value ) {
+            if ( ref $value ) {
+                $RT::Logger->debug(
+                    "Custom Field can have only one value, but we got"
+                    ." several values from ACNSS data. Joining with newlines."
+                );
+                $value = join "\n", @$value;
+            }
+            my ($status, $msg) = $ticket->AddCustomFieldValue(
+                Field => $cf, Value => $value,
+            );
+            $RT::Logger->error("Couldn't set CF: $msg") unless $status;
+        }
+        else {
+            my ($status, $msg) = $ticket->DeleteCustomFieldValue(
+                Field => $cf,
+                Value => $ticket->FirstCustomFieldValue( $cf ),
+            );
+            $RT::Logger->error("Couldn't delete CF value: $msg")
+                unless $status;
+        }
+    }
+    else {
+        unless ( $value  ) {
+            foreach my $value ( @{ $ticket->CustomFieldValues($cf)->ItemsArrayRef } ) {
+                my ($status, $msg) = $ticket->DeleteCustomFieldValue(
+                    Field   => $cf, ValueId => $value->id,
+                );
+                $RT::Logger->error("Couldn't delete CF value: $msg")
+                    unless $status;
+            }
+        }
+        else {
+            my @new = ref $value? (@$value) : ($value);
+            my @old = @{ $ticket->CustomFieldValues($cf)->ItemsArrayRef };
+
+            my @tmp;
+            foreach my $new ( @new ) {
+                next if grep lc $_->Content eq $new, @old;
+                push @tmp, $new;
+            }
+            foreach my $old ( splice @old ) {
+                my $oldv = lc $old->Content;
+                next unless grep $oldv eq lc $_, @new;
+                push @old, $old;
+            }
+            @new = @tmp;
+
+            foreach my $value ( @old ) {
+                my ($status, $msg) = $ticket->DeleteCustomFieldValue(
+                    Field   => $cf, ValueId => $value->id,
+                );
+                $RT::Logger->error("Couldn't delete CF value: $msg")
+                    unless $status;
+            }
+            foreach my $value ( @new ) {
+                my ($status, $msg) = $ticket->AddCustomFieldValue(
+                    Field   => $cf, Value => $value,
+                );
+                $RT::Logger->error("Couldn't add CF value: $msg")
+                    unless $status;
+            }
+        }
+    }
+}
+
+sub MapDataOverCFs {
+    my $self = shift;
+    my $data = shift;
+
+    my %config = RT->Config->Get('ACNS');
+
+    my %res;
+    %res = %{ $config{'Defaults'} };
+    while ( my ($cf, $path) = each %{ $config{'Map'} } ) {
+        my @tmp = grep defined && length, $self->ResolveMapEntry(
+            Data => $data,
+            Path => $path,
+            CustomField => $cf,
+        );
+        $res{ $cf } = @tmp > 1 ? [ @tmp ] : @tmp? $tmp[0] : undef;
+    }
+    return \%res;
+}
+
+sub ResolveMapEntry {
+    my $self = shift;
+    my %args = @_;
+
+    my $data = $args{'Data'};
+    my @path = @{ $args{'Path'} };
+    my @done = @{ $args{'Done'} || [] };
+
+    $RT::Logger->debug("Searching for '". join('.', @path) ."' in ACNS data" )
+        unless @done; # log once
+
+    while ( my $e = shift @path ) {
+        unless ( ref $data ) {
+            $RT::Logger->error("Reached terminal element in data");
+            return ();
+        }
+        elsif ( 'HASH' eq ref $data ) {
+            unless ( exists $data->{ $e } ) {
+                $RT::Logger->debug(
+                    "No entry for '". join('.', @done, $e)
+                    ."' in ACNS data. Ignoring"
+                );
+                return ();
+            }
+            else {
+                push @done, $e;
+                $data = $data->{ $e };
+            }
+        }
+        elsif ( 'ARRAY' eq ref $data ) {
+            if ( $e eq '*' ) {
+                push @done, $e;
+                my @res;
+                foreach my $data_point ( @{$data} ) {
+                    push @res, $self->ResolveMapEntry(
+                        Data => $data_point,
+                        Path => [ splice @path ],
+                        Done => \@done,
+                    );
+                }
+                return @res;
+            }
+            elsif ( $e eq '1' || $e eq '-1' ) {
+                push @done, $e;
+                $data = $data->[ $e > 0? 0 : -1 ];
+            }
+            else {
+                $RT::Logger->error(
+                    "Reached list '". join('.', @done)
+                    ."', but selector ($e) is not *, 1 or -1"
+                );
+                return ();
+            }
+        }
+    }
+
+    unless ( ref $data ) {
+        return ($data);
+    }
+    elsif ( 'HASH' eq ref $data && exists $data->{'_'} ) {
+        return ($data->{'_'});
+    }
+    else {
+        $RT::Logger->error(
+            "Found '". join('.', @done)
+            ."', but it's not an end of the ACNS data"
+        );
+        return ();
+    }
+}
+
+1;
diff --git a/lib/RT/Condition/ACNSMessage.pm b/lib/RT/Condition/ACNSMessage.pm
new file mode 100644
index 0000000..615ae44
--- /dev/null
+++ b/lib/RT/Condition/ACNSMessage.pm
@@ -0,0 +1,12 @@
+use strict;
+use warnings;
+
+package RT::Condition::ACNSMessage;
+use base 'RT::Condition';
+
+sub IsApplicable {
+    my $self = shift;
+    return $self->TransactionObj->Content =~ /Start ACNS XML/;
+}
+
+1;
diff --git a/lib/RT/Extension/ACNS.pm b/lib/RT/Extension/ACNS.pm
new file mode 100644
index 0000000..d6f0d3f
--- /dev/null
+++ b/lib/RT/Extension/ACNS.pm
@@ -0,0 +1,28 @@
+use 5.008003;
+use strict;
+use warnings;
+
+package RT::Extension::ACNS;
+
+our $VERSION = '0.01';
+
+=head1 NAME
+
+RT::Extension::ACNS - parse ACNS messages and extract info
+
+=head1 DESCRIPTION
+
+=cut
+
+
+=head1 AUTHOR
+
+Ruslan Zakirov E<lt>ruz at bestpractical.comE<gt>
+
+=head1 LICENSE
+
+Under the same terms as perl itself.
+
+=cut
+
+1;

-----------------------------------------------------------------------



More information about the Bps-public-commit mailing list