[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