[Rt-commit] rtir branch, 2.9-trunk, updated. 2.6.1-532-g9949df2

Ruslan Zakirov ruz at bestpractical.com
Tue Oct 25 20:03:35 EDT 2011


The branch, 2.9-trunk has been updated
       via  9949df2b752fb979f846ff3b0f47eddf4149e08c (commit)
       via  81ac632adfdcd55e1b8e87d070cd1828bc11ebce (commit)
       via  28d5661cd85e2a99d7900f142d2f92720c9d8402 (commit)
       via  c45e5b6247e07c3fedcc72f9c2c79891e06b01c4 (commit)
       via  144c0a71302bfc96e716d22b5e4842670bdf828b (commit)
       via  ee0a80345374710ad651b1856e3237dd7f5a2cb2 (commit)
       via  0c4dac280e413dd62b956e63decad6d4b9010f3f (commit)
       via  fccac10f425064942296e9fa6d235415aadf87aa (commit)
       via  5cf3e5b3aa706585fca1ebb4b1ef1b9953b47674 (commit)
       via  d7198e76bbf953dfe0cb2a0abc65e95046e8f3da (commit)
       via  d56f63a53ece8a70a62977027f82c9fb9bb91ab3 (commit)
       via  687617e35fbd29c12732735125a3cb5d1a6dab5b (commit)
       via  9e5d73d048c177e84a3280f4d1e68ce890104a7c (commit)
       via  5bc5f7b604e4caa4de017a4eda25c232bcdf3a9b (commit)
       via  064a660e745a7fcf518cfd8670297e9bc613eb8d (commit)
      from  39c07f10cad1f52354b8f53ed76a22be2d6ed5b6 (commit)

Summary of changes:
 CHANGES                                         |    9 +
 etc/upgrade/2.6.2/content                       |   21 ++
 html/Callbacks/RTIR/Elements/MakeClicky/Default |    4 +-
 lib/RT/Action/RTIR_FindIP.pm                    |   73 ++++--
 lib/RT/IR.pm                                    |    3 +-
 t/custom-fields/{ip.t => ipv6.t}                |  321 +++++++++--------------
 6 files changed, 214 insertions(+), 217 deletions(-)
 create mode 100644 etc/upgrade/2.6.2/content
 copy t/custom-fields/{ip.t => ipv6.t} (61%)

- Log -----------------------------------------------------------------
commit 81ac632adfdcd55e1b8e87d070cd1828bc11ebce
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Oct 26 02:16:24 2011 +0400

    update change log

diff --git a/CHANGES b/CHANGES
index c635205..c623782 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,15 @@ CHANGES IN 2.6.1
 FEATURES
 ========
 
+* IPv6 support in IP custom field. Extraction from emails, ranges,
+  searches, everything that applies to IPv4 support.
+
+CHANGES IN 2.6.1
+----------------
+
+FEATURES
+========
+
 * allow local customization of research tools, see @RTIRResearchTools
   in the config
 * new Iframe research tool, see $RTIRIframeResearchToolConfig

commit 9949df2b752fb979f846ff3b0f47eddf4149e08c
Merge: 39c07f1 81ac632
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Oct 26 04:00:22 2011 +0400

    Merge branch '2.6-trunk' into 2.9-trunk
    
    IPv6 support, mostly it's in RT, but RTIR still has special
    things.
    
    Conflicts:
    	etc/initialdata
    	html/RTIR/index.html
    	lib/RT/Action/RTIR_FindIP.pm
    	lib/RT/IR.pm

diff --cc lib/RT/Action/RTIR_FindIP.pm
index ad218fc,37701db..570cbb6
--- a/lib/RT/Action/RTIR_FindIP.pm
+++ b/lib/RT/Action/RTIR_FindIP.pm
@@@ -6,8 -7,45 +6,37 @@@ use base qw(RT::Action::RTIR)
  
  use Regexp::Common qw(net);
  use Regexp::Common::net::CIDR ();
+ use Regexp::IPv6 qw();
  use Net::CIDR ();
  
+ my $IPv4_mask_re = qr{3[0-2]|[1-2]?[0-9]};
+ my $IPv4_prefix_check_re = qr{(?<![0-9.])};
+ my $IPv4_sufix_check_re = qr{(?!\.?[0-9])};
+ my $IPv4_CIDR_re = qr{
+     $IPv4_prefix_check_re
+     $RE{net}{CIDR}{IPv4}{-keep}
+     $IPv4_sufix_check_re
+ }x;
+ my $IPv4_re = qr[
+     $IPv4_prefix_check_re
+     (?!0\.0\.0\.0)
+     ($RE{net}{IPv4})
+     (?!/$IPv4_mask_re)
+     $IPv4_sufix_check_re
+ ]x;
+ 
+ my $IPv6_mask_re = qr{12[0-8]|1[01][0-9]|[1-9]?[0-9]};
+ my $IPv6_prefix_check_re = qr{(?<![0-9a-fA-F:.])};
+ my $IPv6_sufix_check_re = qr{(?!(?:\:{0,2}|\.)[0-9a-fA-F])};
+ my $IPv6_re = qr[
+     $IPv6_prefix_check_re
+     ($Regexp::IPv6::IPv6_re)
+     (?:/($IPv6_mask_re))?
+     $IPv6_sufix_check_re
+ ]x;
+ 
+ my $IP_re = qr{$IPv6_re|$IPv4_re|$IPv4_CIDR_re};
+ 
 -=head2 Prepare
 -
 -Always run this.
 -
 -=cut
 -
 -sub Prepare { return 1 }
 -
  =head2 Commit
  
  Search for IP addresses in the transaction's content.
diff --cc lib/RT/IR.pm
index c2a750b,658958e..7ac5dc8
--- a/lib/RT/IR.pm
+++ b/lib/RT/IR.pm
@@@ -181,290 -218,8 +181,291 @@@ sub Statuses 
      }
  
      my %seen = ();
 -    @states = sort grep !$seen{$_}++, @states;
 -    return @states;
 +    return grep !$seen{$_}++, @initial, @active, @inactive;
 +}
 +
 +sub ActiveQuery {
 +    return (shift)->Query( Initial => 1, Active => 1, @_ );
 +}
 +
 +sub Query {
 +    my $self = shift;
 +    my %args = (
 +        Queue        => undef,
 +        Status       => undef,
 +        Active       => undef,
 +        Inactive     => undef,
 +        Exclude      => undef,
 +        HasMember    => undef,
 +        HasNoMember  => undef,
 +        MemberOf     => undef,
 +        NotMemberOf  => undef,
 +        Constituency => undef,
 +        And          => undef,
 +        @_
 +    );
 +
 +    my @res;
 +    if ( $args{'Queue'} ) {
 +        push @res, map "($_)", join ' OR ', map "Queue = '$_'",
 +            $flat->( $args{'Queue'}, 'Name' );
 +    }
 +    if ( !$args{'Status'} && ( $args{'Initial'} || $args{'Active'} || $args{'Inactive'} ) ) {
 +        $args{'Status'} = [ $self->Statuses( %args ) ];
 +    }
 +    if ( my $s = $args{'Status'} ) {
 +        push @res, join ' OR ', map "Status = '$_'", $flat->( $s );
 +    }
 +    if ( my $t = $args{'Exclude'} ) {
 +        push @res, join ' AND ', map "id != '$_'", map int $_, $flat->( $t, 'id' );
 +    }
 +    if ( my $t = $args{'HasMember'} ) {
 +        push @res, join ' OR ', map "HasMember = $_", map int $_, $flat->( $t, 'id' );
 +    }
 +    if ( my $t = $args{'HasNoMember'} ) {
 +        push @res, join ' AND ', map "HasMember != $_", map int $_, $flat->( $t, 'id' );
 +    }
 +    if ( my $t = $args{'MemberOf'} ) {
 +        push @res, join ' OR ', map "MemberOf = $_", map int $_, $flat->( $t, 'id' );
 +    }
 +    if ( my $t = $args{'NotMemberOf'} ) {
 +        push @res, join ' AND ', map "MemberOf != $_", map int $_, $flat->( $t, 'id' );
 +    }
 +    if (
 +        my $t = $args{'Constituency'}
 +        and RT->Config->Get('_RTIR_Constituency_Propagation') eq 'reject'
 +    ) {
 +        unless ( ref $t ) {
 +            my $tmp = RT::Ticket->new( RT->SystemUser );
 +            $tmp->Load( $t );
 +            $t = $tmp;
 +        }
 +        push @res, "CustomField.{Constituency} = '". $t->FirstCustomFieldValue('Constituency') ."'";
 +    }
 +    if ( my $c = $args{'And'} ) {
 +        push @res, ref $c? @$c : ($c);
 +    }
 +    return join ' AND ', map { /\b(?:AND|OR)\b/? "( $_ )" : $_ } @res;
 +}
 +
 +use Regexp::Common qw(RE_net_IPv4);
++use Regexp::IPv6 qw($IPv6_re);
 +our @SIMPLE_SEARCH_GUESS = (
 +    [ 11 => sub { return "rtirrequestor" if /\@/ } ],
 +    [ 12 => sub {
-         return "Rtirip" if /^\s*$RE{net}{IPv4}\s*$/o
++        return "Rtirip" if /^\s*(?:$RE{net}{IPv4}|$IPv6_re)\s*$/o
 +            && RT::IR->CustomFields('IP')
 +    } ],
 +);
 +sub ParseSimpleSearch {
 +    my $self = shift;
 +    my %args = @_;
 +
 +    local @RT::Search::Googleish::GUESS = (
 +        @RT::Search::Googleish::GUESS,
 +        @SIMPLE_SEARCH_GUESS,
 +    );
 +
 +    my $search = RT::Search::Googleish->new(
 +        Argument => $args{'Query'},
 +        TicketsObj => RT::Tickets->new( $args{'CurrentUser'} ),
 +    );
 +    my $res = $search->QueryToSQL;
 +    if ( $res && $res !~ /\bQueue\b/ ) {
 +        $res = "Queue = 'Incidents' AND ($res)";
 +    }
 +    return $res;
 +}
 +
 +sub OurQuery {
 +    my $self = shift;
 +    my $query = shift;
 +
 +    my ($has_our, $has_other, @queues) = (0, 0);
 +    $ticket_sql_parser->walk(
 +        RT::SQL::ParseToArray( $query ),
 +        { operand => sub {
 +            return undef unless $_[0]->{'key'} =~ /^Queue(?:\z|\.)/;
 +            my $queue = RT::Queue->new( RT->SystemUser );
 +            $queue->Load( $_[0]->{'value'} );
 +            my $our = $self->OurQueue( $queue );
 +            my ($negative) = RT::Tickets->ClassifySQLOperation( $_[0]->{'op'} );
 +            if ( $our && !$negative ) {
 +                $has_our = 1;
 +                push @queues, $queue->Name;
 +            } else {
 +                $has_other = 1;
 +            }
 +        } },
 +    );
 +    return unless $has_our && !$has_other;
 +    return 1 unless wantarray;
 +
 +    my %seen;
 +    @queues = grep !$seen{ lc $_ }++, @queues;
 +
 +    return (1, @queues);
 +}
 +
 +=head2 Incidents
 +
 +Takes a ticket and returns collection of all incidents this ticket
 +is member of.
 +
 +=cut
 +
 +sub Incidents {
 +    my $self = shift;
 +    my $ticket = shift;
 +
 +    my $res = RT::Tickets->new( $ticket->CurrentUser );
 +    $res->FromSQL( $self->Query( Queue => 'Incidents', HasMember => $ticket ) );
 +    return $res;
 +}
 +
 +=head2 RelevantIncidents
 +
 +Takes a ticket and returns collection of incidents this ticket
 +is member of excluding abandoned incidents.
 +
 +=cut
 +
 +sub RelevantIncidentsQuery {
 +    my $self = shift;
 +    my $ticket = shift;
 +
 +    return "Queue = 'Incidents' AND HasMember = ". $ticket->id
 +        ." AND Status != 'abandoned'"
 +    ;
 +}
 +
 +sub RelevantIncidents {
 +    my $self = shift;
 +    my $ticket = shift;
 +
 +    my $res = RT::Tickets->new( $ticket->CurrentUser );
 +    $res->FromSQL( $self->RelevantIncidentsQuery( $ticket, @_ ) );
 +    return $res;
 +}
 +
 +sub IncidentChildren {
 +    my $self = shift;
 +    my $ticket = shift;
 +    my %args = (Queue => \@QUEUES, @_);
 +
 +    my $res = RT::Tickets->new( $ticket->CurrentUser );
 +    $res->FromSQL( $self->Query( %args, MemberOf => $ticket->id ) );
 +    return $res;
 +}
 +
 +=head2 IncidentHasActiveChildren
 +
 +=cut
 +
 +sub IncidentHasActiveChildren {
 +    my $self = shift;
 +    my $incident = shift;
 +
 +    my $children = RT::Tickets->new( $incident->CurrentUser );
 +    $children->FromSQL( $self->ActiveQuery( Queue => \@QUEUES, MemberOf => $incident->id ) );
 +    while ( my $child = $children->Next ) {
 +        next if $self->IsLinkedToActiveIncidents( $child, $incident );
 +        return 1;
 +    }
 +    return 0;
 +}
 +
 +=head2 IsLinkedToActiveIncidents $ChildObj [$IncidentObj]
 +
 +Returns number of active incidents linked to child ticket
 +(IR, Investigation, Block or other). If second argument provided
 +then it's excluded from count.
 +
 +When function return zero that means that object has no active
 +parent incidents.
 +
 +=cut
 +
 +sub IsLinkedToActiveIncidents {
 +    my $self = shift;
 +    my $child = shift;
 +    my $parent = shift;
 +
 +    my $tickets = RT::Tickets->new( $child->CurrentUser );
 +    $tickets->FromSQL( $self->ActiveQuery(
 +        Queue     => 'Incidents',
 +        HasMember => $child,
 +        Exclude   => $parent->id,
 +    ) );
 +    return $tickets->Count;
 +}
 +
 +sub MapStatus {
 +    my $self = shift;
 +    my ($status, $from, $to) = @_;
 +    return unless $status;
 +
 +    foreach my $e ($from, $to) {
 +        if ( blessed $e ) {
 +            if ( $e->isa('RT::Queue') ) {
 +                $e = $e->Lifecycle;
 +            }
 +            elsif ( $e->isa('RT::Ticket') ) {
 +                $e = $e->QueueObj->Lifecycle;
 +            }
 +            elsif ( !$e->isa('RT::Lifecycle') ) {
 +                $e = undef;
 +            }
 +        }
 +        else {
 +            my $queue = RT::Queue->new( RT->SystemUser );
 +            $queue->Load( $e );
 +            $e = $queue->Lifecycle;
 +        }
 +        return unless $e;
 +    }
 +    my $res = $from->MoveMap( $to )->{ $status };
 +    unless ( $res ) {
 +        RT->Logger->warning(
 +            "No mapping for $status in ". $from->Name .' lifecycle'
 +            .' to status in '. $to->Name .' lifecycle'
 +        );
 +    }
 +    return $res;
 +}
 +
 +sub FirstWhoisServer {
 +    my $self = shift;
 +    my $servers = RT->Config->Get('whois');
 +    my ($res) = map ref $servers->{$_}? $servers->{$_}->{'Host'}: $servers->{$_},
 +        (sort keys %$servers)[0];
 +    return $res;
 +}
 +
 +sub WhoisLookup {
 +    my $self = shift;
 +    my %args = (
 +        Server => undef,
 +        Query  => undef,
 +        @_
 +    );
 +
 +    my $server = $args{'Server'} || $self->FirstWhoisServer;
 +    return (undef, $args{'CurrentUser'}->loc("No whois servers configured"))
 +        unless $server;
 +
 +    my ($host, $port) = split /\s*:\s*/, $server, 2;
 +    $port = 43 unless ($port || '') =~ /^\d+$/;
 +
 +    use Net::Whois::RIPE;
 +    my $whois = Net::Whois::RIPE->new( $host, Port => $port, Debug => 1 );
 +    my $iterator;
 +    $iterator = $whois->query_iterator( $args{'Query'} )
 +        if $whois;
 +    return (undef, $args{'CurrentUser'}->loc("Unable to connect to WHOIS server '[_1]'", $server) )
 +        unless $iterator;
 +
 +    return $iterator;
  }
  
  sub GetCustomField {
diff --cc t/custom-fields/ipv6.t
index 0000000,38df66a..768ebe1
mode 000000,100644..100644
--- a/t/custom-fields/ipv6.t
+++ b/t/custom-fields/ipv6.t
@@@ -1,0 -1,557 +1,557 @@@
+ #!/usr/bin/perl
+ 
+ use strict;
+ use warnings;
+ 
 -use RT::IR::Test tests => 772;
++use RT::IR::Test tests => 698;
+ 
+ RT::Test->started_ok;
+ my $agent = default_agent();
+ 
+ use_ok('RT::IR');
+ 
+ my %valid = (
+     'abcd:' x 7 . 'abcd' => 'abcd:' x 7 . 'abcd',
+     '034:' x 7 . '034'   => '0034:' x 7 . '0034',
+     'abcd::'             => 'abcd:' . '0000:' x 6 . '0000',
+     '::abcd'             => '0000:' x 7 . 'abcd',
+     'abcd::034'          => 'abcd:' . '0000:' x 6 . '0034',
+     'abcd::192.168.1.1'  => 'abcd:' . '0000:' x 5 . 'c0a8:0101',
+     '::192.168.1.1'      => '0000:' x 6 . 'c0a8:0101',
+ );
+ 
+ my %test_set = (
+     'abcd:' x 7 . 'abcd' => 'abcd:' x 7 . 'abcd',
+     'abcd::034'          => 'abcd:' . '0000:' x 6 . '0034',
+     '::192.168.1.1'      => '0000:' x 6 . 'c0a8:0101',
+ );
+ my %test_cidr = (
+     'abcd:' x 7 . 'abcd/32' => 'abcd:abcd'. ':0000' x 6 .'-'. 'abcd:abcd'. ':ffff' x 6,
+     '::192.168.1.1/120'     => '0000:' x 6 . 'c0a8:0100' .'-'. '0000:' x 6 . 'c0a8:01ff',
+ );
+ 
+ my $cf;
+ diag "load and check basic properties of the IP CF" if $ENV{'TEST_VERBOSE'};
+ {
+     my $cfs = RT::CustomFields->new( $RT::SystemUser );
+     $cfs->Limit( FIELD => 'Name', VALUE => 'IP' );
+     is( $cfs->Count, 1, "found one CF with name 'IP'" );
+ 
+     $cf = $cfs->First;
 -    is( $cf->Type, 'Freeform', 'type check' );
++    is( $cf->Type, 'IPAddressRange', 'type check' );
+     is( $cf->LookupType, 'RT::Queue-RT::Ticket', 'lookup type check' );
+     ok( !$cf->MaxValues, "unlimited number of values" );
+     ok( !$cf->Disabled, "not disabled" );
+ }
+ 
+ diag "check that CF applies to all RTIR's queues" if $ENV{'TEST_VERBOSE'};
+ {
+     foreach ( 'Incidents', 'Incident Reports', 'Investigations', 'Blocks' ) {
+         my $queue = RT::Queue->new( $RT::SystemUser );
+         $queue->Load( $_ );
+         ok( $queue->id, 'loaded queue '. $_ );
+         my $cfs = $queue->TicketCustomFields;
+         $cfs->Limit( FIELD => 'id', VALUE => $cf->id, ENTRYAGGREGATOR => 'AND' );
+         is( $cfs->Count, 1, 'field applies to queue' );
+     }
+ }
+ my $rtir_user = RT::CurrentUser->new( rtir_user() );
+ 
+ diag "create a ticket via web and set IP" if $ENV{'TEST_VERBOSE'};
+ while ( my ($short, $full) = each %valid ) {
+     my $incident_id; # block couldn't be created without incident id
+     foreach my $queue( 'Incidents', 'Incident Reports', 'Investigations', 'Blocks' ) {
+         diag "create a ticket in the '$queue' queue" if $ENV{'TEST_VERBOSE'};
+ 
+         my $id = $agent->create_rtir_ticket_ok(
+             $queue,
+             {
+                 Subject => "test ip",
+                 ( $queue eq 'Blocks' ? ( Incident => $incident_id ) : () ),
+             },
+             { IP => $short },
+         );
+         $incident_id = $id if $queue eq 'Incidents';
+ 
+         $agent->display_ticket( $id);
+         $agent->content_like( qr/\Q$full/, "IP on the page" );
+ 
+         my $ticket = RT::Ticket->new( $RT::SystemUser );
+         $ticket->Load( $id );
+         ok( $ticket->id, 'loaded ticket' );
+         is( $ticket->FirstCustomFieldValue('IP'), $full, 'correct value' );
+     }
+ }
+ 
+ diag "create a ticket via web with IP in message" if $ENV{'TEST_VERBOSE'};
+ while ( my ($short, $full) = each %test_set ) {
+     my $incident_id; # block couldn't be created without incident id
+     foreach my $queue( 'Incidents', 'Incident Reports', 'Investigations', 'Blocks' ) {
+         diag "create a ticket in the '$queue' queue" if $ENV{'TEST_VERBOSE'};
+ 
+         my $id = $agent->create_rtir_ticket_ok(
+             $queue,
+             {
+                 Subject => "test ip in message",
+                 ($queue eq 'Blocks'? (Incident => $incident_id): ()),
+                 Content => "$short",
+             },
+         );
+         $incident_id = $id if $queue eq 'Incidents';
+ 
+         $agent->display_ticket( $id );
+         $agent->content_like( qr/\Q$full/, "IP on the page" );
+ 
+         my $ticket = RT::Ticket->new( $RT::SystemUser );
+         $ticket->Load( $id );
+         ok( $ticket->id, 'loaded ticket' );
+         is( $ticket->FirstCustomFieldValue('IP'), $full, 'correct value' );
+     }
+ }
+ 
+ diag "create a ticket via web with CIDR" if $ENV{'TEST_VERBOSE'};
+ while ( my ($short, $full) = each %test_cidr ) {
+     my $incident_id; # block couldn't be created without incident id
+     foreach my $queue( 'Incidents', 'Incident Reports', 'Investigations', 'Blocks' ) {
+         diag "create a ticket in the '$queue' queue" if $ENV{'TEST_VERBOSE'};
+ 
+         my $id = $agent->create_rtir_ticket_ok(
+             $queue,
+             {
+                 Subject => "test ip",
+                 ($queue eq 'Blocks'? (Incident => $incident_id): ()),
+             },
+             { IP => $short },
+         );
+         $incident_id = $id if $queue eq 'Incidents';
+ 
+         $agent->display_ticket( $id);
+         $agent->content_like( qr/\Q$full/, "IP range on the page" );
+ 
+         my $ticket = RT::Ticket->new( $RT::SystemUser );
+         $ticket->Load( $id );
+         ok( $ticket->id, 'loaded ticket' );
+         my $values = $ticket->CustomFieldValues('IP');
+         my %has = map { $_->Content => 1 } @{ $values->ItemsArrayRef };
+         ok( $has{ $full }, "has value" )
+             or diag "but has values ". join ", ", keys %has;
+     }
+ }
+ 
+ diag "create a ticket via web with CIDR in message" if $ENV{'TEST_VERBOSE'};
+ while ( my ($short, $full) = each %test_cidr ) {
+     my $incident_id; # block couldn't be created without incident id
+     foreach my $queue( 'Incidents', 'Incident Reports', 'Investigations', 'Blocks' ) {
+         diag "create a ticket in the '$queue' queue" if $ENV{'TEST_VERBOSE'};
+ 
+         my $id = $agent->create_rtir_ticket_ok(
+             $queue,
+             {
+                 Subject => "test ip in message",
+                 ($queue eq 'Blocks'? (Incident => $incident_id): ()),
+                 Content => "$short",
+             },
+         );
+         $incident_id = $id if $queue eq 'Incidents';
+ 
+         $agent->display_ticket( $id);
+         $agent->content_like( qr/\Q$full/, "IP range on the page" );
+ 
+         my $ticket = RT::Ticket->new( $RT::SystemUser );
+         $ticket->Load( $id );
+         ok( $ticket->id, 'loaded ticket' );
+         my $values = $ticket->CustomFieldValues('IP');
+         my %has = map { $_->Content => 1 } @{ $values->ItemsArrayRef };
+         ok( $has{ $full }, "has value" )
+             or diag "but has values ". join ", ", keys %has;
+     }
+ }
+ 
+ diag "create a ticket and edit IP field using Edit page" if $ENV{'TEST_VERBOSE'};
+ {
+     my $i = 0;
+     my $incident_id; # block couldn't be created without incident id
+     foreach my $queue( 'Incidents', 'Incident Reports', 'Investigations', 'Blocks' ) {
+         diag "create a ticket in the '$queue' queue" if $ENV{'TEST_VERBOSE'};
+ 
+         my $id = $agent->create_rtir_ticket_ok(
+             $queue,
+             {
+                 Subject => "test ip in message",
+                 ($queue eq 'Blocks'? (Incident => $incident_id): ()),
+             },
+         );
+         $incident_id = $id if $queue eq 'Incidents';
+         $agent->display_ticket( $id);
+ 
+         my $field_name = "Object-RT::Ticket-$id-CustomField-". $cf->id ."-Values";
+ 
+ diag "set IP" if $ENV{'TEST_VERBOSE'};
+         my $val = 'abcd::192.168.1.1';
+         $agent->follow_link_ok({text => 'Edit', n => "1"}, "Followed 'Edit' link");
+         $agent->form_number(3);
+         like( $agent->value($field_name), qr/^\s*$/, 'IP is empty' );
+         $agent->field( $field_name => $val );
+         $agent->click('SaveChanges');
+ 
+         $agent->content_like( qr/\Q$valid{$val}/, "IP on the page" );
+ 
+         my $ticket = RT::Ticket->new( $RT::SystemUser );
+         $ticket->Load( $id );
+         ok( $ticket->id, 'loaded ticket' );
+         my $values = $ticket->CustomFieldValues('IP');
+         my %has = map { $_->Content => 1 } @{ $values->ItemsArrayRef };
+         is( scalar values %has, 1, "one IP were added");
+         ok( $has{ $valid{ $val } }, "has value" )
+             or diag "but has values ". join ", ", keys %has;
+ 
+ diag "set IP with spaces around" if $ENV{'TEST_VERBOSE'};
+         $val = "  ::192.168.1.1  \n  ";
+         $agent->follow_link_ok({text => 'Edit', n => "1"}, "Followed 'Edit' link");
+         $agent->form_number(3);
+         like( $agent->value($field_name), qr/^\s*\Q$valid{'abcd::192.168.1.1'}\E\s*$/, 'IP is in input box' );
+         $agent->field( $field_name => $val );
+         $agent->click('SaveChanges');
+ 
+         $agent->content_like( qr/\Q$valid{'::192.168.1.1'}/, "IP on the page" );
+ 
+         $ticket = RT::Ticket->new( $RT::SystemUser );
+         $ticket->Load( $id );
+         ok( $ticket->id, 'loaded ticket' );
+         $values = $ticket->CustomFieldValues('IP');
+         %has = map { $_->Content => 1 } @{ $values->ItemsArrayRef };
+         is( scalar values %has, 1, "one IP were added");
+         ok( $has{ $valid{'::192.168.1.1'} }, "has value" )
+             or diag "but has values ". join ", ", keys %has;
+ 
+ diag "replace IP with a range" if $ENV{'TEST_VERBOSE'};
+         $val = '::192.168.1.1/120';
+         $agent->follow_link_ok({text => 'Edit', n => "1"}, "Followed 'Edit' link");
+         $agent->form_number(3);
+         like( $agent->value($field_name), qr/^\s*\Q$valid{'::192.168.1.1'}\E\s*$/, 'IP is in input box' );
+         $agent->field( $field_name => $val );
+         $agent->click('SaveChanges');
+ 
+         $agent->content_like( qr/\Q$test_cidr{ $val }/, "IP on the page" );
+ 
+         $ticket = RT::Ticket->new( $RT::SystemUser );
+         $ticket->Load( $id );
+         ok( $ticket->id, 'loaded ticket' );
+         $values = $ticket->CustomFieldValues('IP');
+         %has = map { $_->Content => 1 } @{ $values->ItemsArrayRef };
+         is( scalar values %has, 1, "one IP were added");
+         ok( $has{ $test_cidr{ $val } }, "has value" )
+             or diag "but has values ". join ", ", keys %has;
+     }
+ }
+ 
+ #diag "check that we parse correct IPs only" if $ENV{'TEST_VERBOSE'};
+ # XXX: waiting for regressions
+ 
+ diag "check that IPs in messages don't add duplicates" if $ENV{'TEST_VERBOSE'};
+ {
+     my $id = $agent->create_ir( {
+         Subject => "test ip",
+         Content => 'abcd::192.168.1.1 abcd::192.168.1.1 abcd::192.168.1.1/128'
+     } );
+     ok($id, "created first ticket");
+ 
+     my $ticket = RT::Ticket->new( $RT::SystemUser );
+     $ticket->Load( $id );
+     ok( $ticket->id, 'loaded ticket' );
+ 
+     my $values = $ticket->CustomFieldValues('IP');
+     my %has;
+     $has{ $_->Content }++ foreach @{ $values->ItemsArrayRef };
+     is(scalar values %has, 1, "one IP were added");
+     ok(!grep( $_ != 1, values %has ), "no duplicated values")
+         or diag "duplicates: ". join ',', grep $has{$_}>1, keys %has;
+     ok($has{ $valid{ 'abcd::192.168.1.1' } }, "IP is there")
+             or diag "but has values ". join ", ", keys %has;
+ }
+ 
+ diag "search tickets by IP" if $ENV{'TEST_VERBOSE'};
+ {
+     my $id = $agent->create_ir( {
+         Subject => "test ip",
+         Content => '::192.168.1.1/120',
+     } );
+     ok($id, "created first ticket");
+ 
+     my $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("id = $id AND CF.{IP} = '::192.168.1.1'");
+     ok( $tickets->Count, "found tickets" );
+ 
+     my $flag = 1;
+     while ( my $ticket = $tickets->Next ) {
+         my %has = map { $_->Content => 1 } @{ $ticket->CustomFieldValues('IP')->ItemsArrayRef };
+         next if $has{ $test_cidr{'::192.168.1.1/120'} };
+         $flag = 0;
+         ok(0, "ticket #". $ticket->id ." has no range ::192.168.1.1/120, but should")
+             or diag "but has values ". join ", ", keys %has;
+         last;
+     }
+     ok(1, "all tickets has IP ::192.168.1.1/120") if $flag;
+ }
+ 
+ diag "search tickets by IP range" if $ENV{'TEST_VERBOSE'};
+ {
+     my $id = $agent->create_ir( {
+         Subject => "test ip",
+         Content => '::c0a8:01a0'
+     } );
+     ok($id, "created first ticket");
+ 
+     my $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("id = $id AND CF.{IP} = '::c0a8:0101-::c0a8:01ff'");
+     ok( $tickets->Count, "found tickets" );
+ 
+     my $flag = 1;
+     while ( my $ticket = $tickets->Next ) {
+         my %has = map { $_->Content => 1 } @{ $ticket->CustomFieldValues('IP')->ItemsArrayRef };
+         next if grep /^0000(:0000){5}:c0a8:01/, keys %has;
+         $flag = 0;
+         ok(0, "ticket #". $ticket->id ." has no IP from '::c0a8::-::c0a8:01ff', but should");
+         last;
+     }
+     ok(1, "all tickets have at least one IP from the range") if $flag;
+ }
+ 
+ diag "create two tickets with different IPs and check several searches" if $ENV{'TEST_VERBOSE'};
+ {
+     my $id1 = $agent->create_ir( { Subject => "test ip" }, { IP => '::c0a8:3310' } );
+     ok($id1, "created first ticket");
+     my $id2 = $agent->create_ir( { Subject => "test ip" }, { IP => '::c0a8:aa10' } );
+     ok($id2, "created second ticket");
+ 
+     my $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("id = $id1 OR id = $id2");
+     is( $tickets->Count, 2, "found both tickets by 'id = x OR y'" );
+ 
+     # IP
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:3310'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id1, "correct value" );
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:aa10'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id2, "correct value" );
+ 
+     # IP/32 - one address
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:3310/128'");
+     is( $tickets->Count, 1, "found one ticket" ) or diag $tickets->BuildSelectQuery;
+     is( $tickets->First->id, $id1, "correct value" );
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:aa10/128'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id2, "correct value" );
+ 
+     # IP range
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:3300-::c0a8:33ff'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id1, "correct value" );
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:aa00-::c0a8:aaff'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id2, "correct value" );
+ 
+     # IP range, with start IP greater than end
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:33ff-::c0a8:3300'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id1, "correct value" );
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:aaff-::c0a8:aa00'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id2, "correct value" );
+ 
+     # CIDR/120
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:3300/120'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id1, "correct value" );
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:aa00/120'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id2, "correct value" );
+ 
+     # IP is not in CIDR/120
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} != '::c0a8:3300/120'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id2, "correct value" );
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} != '::c0a8:aa00/120'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id1, "correct value" );
+ 
+     # CIDR or CIDR
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND "
+         ."(CF.{IP} = '::c0a8:3300/120' OR CF.{IP} = '::c0a8:aa00/120')");
+     is( $tickets->Count, 2, "found both tickets" );
+ 
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:0000/0'");
+     is( $tickets->Count, 2, "found both tickets" ) or diag $tickets->BuildSelectQuery;
+ }
+ 
+ diag "create two tickets with different IP ranges and check several searches" if $ENV{'TEST_VERBOSE'};
+ {
+     my $id1 = $agent->create_ir( { Subject => "test ip" }, { IP => '::192.168.21.0-::192.168.21.127' } );
+     ok($id1, "created first ticket");
+     my $id2 = $agent->create_ir( { Subject => "test ip" }, { IP => '::192.168.21.128-::192.168.21.255' } );
+     ok($id2, "created second ticket");
+ 
+     my $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("id = $id1 OR id = $id2");
+     is( $tickets->Count, 2, "found both tickets by 'id = x OR y'" );
+ 
+     # IP
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.0'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id1, "correct value" );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.64'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id1, "correct value" );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.127'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id1, "correct value" );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.128'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id2, "correct value" );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.191'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id2, "correct value" );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.255'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id2, "correct value" );
+ 
+     # IP/32 - one address
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.63/128'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id1, "correct value" );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.191/128'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id2, "correct value" );
+ 
+     # IP range, lower than both
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.20.0-::192.168.20.255'");
+     is( $tickets->Count, 0, "didn't finnd ticket" ) or diag "but found ". $tickets->First->id;
+ 
+     # IP range, intersect with the first range
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.20.0-::192.168.21.63'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id1, "correct value" );
+ 
+     # IP range, equal to the first range
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.0-::192.168.21.127'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id1, "correct value" );
+ 
+     # IP range, lay inside the first range
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.31-::192.168.21.63'");
+     is( $tickets->Count, 1, "found one ticket" );
+     is( $tickets->First->id, $id1, "correct value" );
+ 
+     # IP range, intersect with the ranges
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.31-::192.168.21.191'");
+     is( $tickets->Count, 2, "found both tickets" );
+ 
+     # IP range, equal to range from the starting IP of the first ticket to the ending IP of the second
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.0-::192.168.21.255'");
+     is( $tickets->Count, 2, "found both tickets" );
+ 
+     # IP range, has the both ranges inside it
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.0.0/112'");
+     is( $tickets->Count, 2, "found both tickets" );
+ 
+     # IP range, greater than both
+     $tickets = RT::Tickets->new( $rtir_user );
+     $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.22.0/120'");
+     is( $tickets->Count, 0, "didn't finnd ticket" ) or diag "but found ". $tickets->First->id;
+ }
+ 
+ diag "merge ticket, IPs should be merged";
+ {
+     my $incident_id = $agent->create_rtir_ticket_ok(
+         'Incidents',
+         { Subject => "test" },
+     );
+     my $b1_id = $agent->create_block(
+         {
+             Subject => "test ip",
+             Incident => $incident_id,
+         },
+         { IP => '::172.16.0.1' },
+     );
+     my $b2_id = $agent->create_block(
+         {
+             Subject => "test ip",
+             Incident => $incident_id,
+         },
+         { IP => '::172.16.0.2' },
+     );
+ 
+     $agent->display_ticket( $b1_id);
+     $agent->follow_link_ok({ text => 'Merge' }, "Followed merge link");
+     $agent->form_number(3);
+     $agent->field('SelectedTicket', $b2_id);
+     $agent->submit;
+     $agent->ok_and_content_like( qr{Merge Successful}, 'Merge Successful');
+ 
+     my $ticket = RT::Ticket->new( $RT::SystemUser );
+     $ticket->Load( $b1_id );
+     ok $ticket->id, 'loaded ticket';
+     my $values = $ticket->CustomFieldValues('IP');
+     my %has = map { $_->Content => 1 } @{ $values->ItemsArrayRef };
+     is( scalar values %has, 2, "both IPs are there");
+     ok( $has{ '0000:'x6 .'ac10:0001' }, "has value" )
+         or diag "but has values ". join ", ", keys %has;
+     ok( $has{ '0000:'x6 .'ac10:0002' }, "has value" )
+         or diag "but has values ". join ", ", keys %has;
+ }
+ 
+ diag "merge ticket with the same IP";
+ {
+     my $incident_id = $agent->create_rtir_ticket_ok(
+         'Incidents',
+         { Subject => "test" },
+     );
+     my $b1_id = $agent->create_block(
+         {
+             Subject => "test ip",
+             Incident => $incident_id,
+         },
+         { IP => '::172.16.0.1' },
+     );
+     my $b2_id = $agent->create_block(
+         {
+             Subject => "test ip",
+             Incident => $incident_id,
+         },
+         { IP => '::172.16.0.1' },
+     );
+ 
+     $agent->display_ticket( $b1_id);
+     $agent->follow_link_ok({ text => 'Merge' }, "Followed merge link");
+     $agent->form_number(3);
+     $agent->field('SelectedTicket', $b2_id);
+     $agent->submit;
+     $agent->ok_and_content_like( qr{Merge Successful}, 'Merge Successful');
+ 
+     my $ticket = RT::Ticket->new( $RT::SystemUser );
+     $ticket->Load( $b1_id );
+     ok $ticket->id, 'loaded ticket';
+     my $values = $ticket->CustomFieldValues('IP');
+     my @has = map $_->Content, @{ $values->ItemsArrayRef };
+     is( scalar @has, 1, "only one IP") or diag "values: @has";
+     is( $has[0], '0000:'x6 .'ac10:0001', "has value" );
+ }
+ 

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


More information about the Rt-commit mailing list