[Bps-public-commit] rt-extension-assetsql branch, master, updated. da02117736d37c99757b49e313b853809a829e20

Shawn Moore shawn at bestpractical.com
Wed Jun 15 16:57:07 EDT 2016


The branch, master has been updated
       via  da02117736d37c99757b49e313b853809a829e20 (commit)
       via  42185f0e8efb9aa9204d1f7fec5b7aeecfad49bb (commit)
       via  9695e3ee700d4f3eeb8f026942679038e09a5758 (commit)
       via  21957ddabda50dedc4940c48f973bdd22cc04801 (commit)
       via  3c9d476eb8c18abc438ed7e188f6a2a211cefad0 (commit)
       via  a5392b9dc96526a6590f0b6e094a3b7264bfd10f (commit)
       via  adb004b38d140325a737c1609ab64aace6a871e0 (commit)
       via  e3a00474b2677e2e1c0a76247d082c3ecdf09b62 (commit)
      from  10383f4948d03493f225bf068008a2389e4bc407 (commit)

Summary of changes:
 html/Asset/Search/Build.html                     |  21 +-
 html/Asset/Search/Edit.html                      |   2 +-
 html/Asset/Search/Results.tsv                    |   2 +-
 html/Callbacks/AssetSQL/Elements/Tabs/Privileged |   2 +-
 lib/RT/Extension/AssetSQL.pm                     |  31 +--
 lib/RT/Extension/AssetSQL/Assets.pm              | 265 +++++++++++++++--------
 patches/assetsql.patch                           |   2 +-
 7 files changed, 184 insertions(+), 141 deletions(-)

- Log -----------------------------------------------------------------
commit e3a00474b2677e2e1c0a76247d082c3ecdf09b62
Author: Shawn M Moore <shawn at bestpractical.com>
Date:   Wed Jun 15 19:54:32 2016 +0000

    Consistently order by name rather than id

diff --git a/html/Asset/Search/Build.html b/html/Asset/Search/Build.html
index 86744d7..cec6e56 100644
--- a/html/Asset/Search/Build.html
+++ b/html/Asset/Search/Build.html
@@ -91,7 +91,7 @@ if ( $NewQuery ) {
     my $current = $session{'CurrentAssetSearchHash'};
     my $default = { Query => '',
                     Format => '',
-                    OrderBy => 'id',
+                    OrderBy => 'Name',
                     Order => 'ASC',
                     RowsPerPage => 50 };
 
diff --git a/html/Asset/Search/Edit.html b/html/Asset/Search/Edit.html
index 8c1f7ff..7f9eedb 100644
--- a/html/Asset/Search/Edit.html
+++ b/html/Asset/Search/Edit.html
@@ -33,7 +33,7 @@ $SavedSearchId => 'new'
 $Query         => ''
 $Format        => ''
 $Rows          => '50'
-$OrderBy       => 'id'
+$OrderBy       => 'Name'
 $Order         => 'ASC'
 
 @actions       => ()
diff --git a/html/Asset/Search/Results.tsv b/html/Asset/Search/Results.tsv
index 3f0eac2..d49244a 100644
--- a/html/Asset/Search/Results.tsv
+++ b/html/Asset/Search/Results.tsv
@@ -1,7 +1,7 @@
 <%ARGS>
 $Format => undef
 $Query => ''
-$OrderBy => 'id'
+$OrderBy => 'Name'
 $Order => 'ASC'
 $PreserveNewLines => 0
 </%ARGS>

commit adb004b38d140325a737c1609ab64aace6a871e0
Author: Shawn M Moore <shawn at bestpractical.com>
Date:   Wed Jun 15 19:55:46 2016 +0000

    Consistently set up a new query in the top menu

diff --git a/html/Callbacks/AssetSQL/Elements/Tabs/Privileged b/html/Callbacks/AssetSQL/Elements/Tabs/Privileged
index 13c7486..2072842 100644
--- a/html/Callbacks/AssetSQL/Elements/Tabs/Privileged
+++ b/html/Callbacks/AssetSQL/Elements/Tabs/Privileged
@@ -5,7 +5,7 @@ $ARGSRef
 <%INIT>
 # replace Search -> Assets with a submenu (if the user has ShowAssetsMenu)
 if (my $search_assets = Menu()->child("search")->child("assets")) {
-    $search_assets->path('/Asset/Search/Build.html');
+    $search_assets->path('/Asset/Search/Build.html?NewQuery=1');
     if (!RT->Config->Get('AssetSQL_HideSimpleSearch')) {
         $search_assets->child("asset_simple", title => loc("Simple Search"), path => "/Asset/Search/");
         $search_assets->child("assetsql", title => loc("New Search"), path => "/Asset/Search/Build.html?NewQuery=1");

commit a5392b9dc96526a6590f0b6e094a3b7264bfd10f
Author: Shawn M Moore <shawn at bestpractical.com>
Date:   Wed Jun 15 20:42:10 2016 +0000

    Avoid undef warning for ticket searches

diff --git a/patches/assetsql.patch b/patches/assetsql.patch
index 7346229..40f4ae0 100644
--- a/patches/assetsql.patch
+++ b/patches/assetsql.patch
@@ -22,7 +22,7 @@ index 15b7b75..4234387 100644
      titleright_href => $customize,
      hideable => $hideable &>
 -<& $query_display_component, hideable => $hideable, %$ProcessedSearchArg, ShowNavigation => 0, Class => 'RT::Tickets', HasResults => $HasResults, PreferOrderBy => 1 &>
-+<& $query_display_component, hideable => $hideable, %$ProcessedSearchArg, ShowNavigation => 0, Class => $SearchArg && $SearchArg->{SearchType} eq 'Asset' ? 'RT::Assets' : 'RT::Tickets', HasResults => $HasResults, PreferOrderBy => 1 &>
++<& $query_display_component, hideable => $hideable, %$ProcessedSearchArg, ShowNavigation => 0, Class => $SearchArg && ($SearchArg->{SearchType}'') eq 'Asset' ? 'RT::Assets' : 'RT::Tickets', HasResults => $HasResults, PreferOrderBy => 1 &>
  </&>
  <%init>
  my $search;

commit 3c9d476eb8c18abc438ed7e188f6a2a211cefad0
Author: Shawn M Moore <shawn at bestpractical.com>
Date:   Wed Jun 15 20:40:36 2016 +0000

    Add the ability to search for assets based on catalog lifecycle
    
        See also RT's 6876523b8d7a889575bf61d304db6cb2ba9bc47f

diff --git a/lib/RT/Extension/AssetSQL/Assets.pm b/lib/RT/Extension/AssetSQL/Assets.pm
index 09a0a08..90d5ee7 100644
--- a/lib/RT/Extension/AssetSQL/Assets.pm
+++ b/lib/RT/Extension/AssetSQL/Assets.pm
@@ -475,6 +475,8 @@ our %FIELD_METADATA = (
     CustomFieldValue => [ 'CUSTOMFIELD' => 'Asset' ], #loc_left_pair
     CustomField      => [ 'CUSTOMFIELD' => 'Asset' ], #loc_left_pair
     CF               => [ 'CUSTOMFIELD' => 'Asset' ], #loc_left_pair
+
+    Lifecycle        => [ 'LIFECYCLE' ], #loc_left_pair
 );
 
 # Lower Case version of FIELDS, for case insensitivity
@@ -498,8 +500,8 @@ our %dispatch = (
     WATCHERFIELD    => \&_WatcherLimit,
     MEMBERSHIPFIELD => \&_WatcherMembershipLimit,
     CUSTOMFIELD     => \&_CustomFieldLimit,
+    LIFECYCLE       => \&_LifecycleLimit,
 #    HASATTRIBUTE    => \&_HasAttributeLimit,
-#    LIFECYCLE       => \&_LifecycleLimit,
 );
 
 # Default EntryAggregator per type
@@ -1197,6 +1199,26 @@ sub _CustomFieldJoinByName {
     return ($ocfvalias, $CFs, $ocfalias);
 }
 
+sub _LifecycleLimit {
+    my ( $self, $field, $op, $value, %rest ) = @_;
+
+    die "Invalid Operator $op for $field" if $op =~ /^(IS|IS NOT)$/io;
+    my $catalog = $self->{_sql_aliases}{catalogs} ||= $_[0]->Join(
+        ALIAS1 => 'main',
+        FIELD1 => 'Catalog',
+        TABLE2 => 'Catalogs',
+        FIELD2 => 'id',
+    );
+
+    $self->Limit(
+        ALIAS    => $catalog,
+        FIELD    => 'Lifecycle',
+        OPERATOR => $op,
+        VALUE    => $value,
+        %rest,
+    );
+}
+
 =head2 PrepForSerialization
 
 You don't want to serialize a big assets object, as

commit 21957ddabda50dedc4940c48f973bdd22cc04801
Author: Shawn M Moore <shawn at bestpractical.com>
Date:   Wed Jun 15 20:23:05 2016 +0000

    Apply RT's "Temporarily remove bundling code" to AssetSQL
    
        See RT's 25bba4bd533944f4311371188f65d7fa2daed374

diff --git a/lib/RT/Extension/AssetSQL/Assets.pm b/lib/RT/Extension/AssetSQL/Assets.pm
index 90d5ee7..61f3c41 100644
--- a/lib/RT/Extension/AssetSQL/Assets.pm
+++ b/lib/RT/Extension/AssetSQL/Assets.pm
@@ -1247,38 +1247,19 @@ sub _parser {
     my ($self,$string) = @_;
     my $ea = '';
 
-    my %sub_tree;
-    my $depth = 0;
-
     my %callback;
     $callback{'OpenParen'} = sub {
       $self->_OpenParen;
-      $depth++;
-      push @$_, '(' foreach values %sub_tree;
     };
     $callback{'CloseParen'} = sub {
       $self->_CloseParen;
-      $depth--;
-      foreach my $list ( values %sub_tree ) {
-          if ( $list->[-1] eq '(' ) {
-              pop @$list;
-              pop @$list if $list->[-1] =~ /^(?:AND|OR)$/i;
-          }
-          else {
-              pop @$list while $list->[-2] ne '(';
-              $list->[-1] = pop @$list;
-          }
-      }
     };
     $callback{'EntryAggregator'} = sub {
       $ea = $_[0] || '';
-      push @$_, $ea foreach grep @$_ && $_->[-1] ne '(', values %sub_tree;
     };
     $callback{'Condition'} = sub {
         my ($key, $op, $value) = @_;
 
-        my $negative_op = ($op eq '!=' || $op =~ /\bNOT\b/i);
-        my $null_op = ( 'is not' eq lc($op) || 'is' eq lc($op) );
         # key has dot then it's compound variant and we have subkey
         my $subkey = '';
         ($key, $subkey) = ($1, $2) if $key =~ /^([^\.]+)\.(.+)$/;
@@ -1300,28 +1281,12 @@ sub _parser {
         }
         my $sub = $dispatch{ $class };
 
-        my @res; my $bundle_with;
-        if ( $class eq 'WATCHERFIELD' && $key ne 'Owner' && !$negative_op && (!$null_op || $subkey) ) {
-            if ( !$sub_tree{$key} ) {
-              $sub_tree{$key} = [ ('(')x$depth, \@res ];
-            } else {
-              $bundle_with = $self->_check_bundling_possibility( $string, @{ $sub_tree{$key} } );
-              if ( $sub_tree{$key}[-1] eq '(' ) {
-                    push @{ $sub_tree{$key} }, \@res;
-              }
-            }
-        }
-
-        # Remove our aggregator from subtrees where our condition didn't get added
-        pop @$_ foreach grep @$_ && $_->[-1] =~ /^(?:AND|OR)$/i, values %sub_tree;
-
         # A reference to @res may be pushed onto $sub_tree{$key} from
         # above, and we fill it here.
-        @res = $sub->( $self, $key, $op, $value,
+        $sub->( $self, $key, $op, $value,
                 SUBCLAUSE       => '',  # don't need anymore
                 ENTRYAGGREGATOR => $ea,
                 SUBKEY          => $subkey,
-                BUNDLE          => $bundle_with,
               );
         $ea = '';
     };
@@ -1539,28 +1504,5 @@ sub _ProcessRestrictions {
 
 }
 
-sub _check_bundling_possibility {
-    my $self = shift;
-    my $string = shift;
-    my @list = reverse @_;
-    while (my $e = shift @list) {
-        next if $e eq '(';
-        if ( lc($e) eq 'and' ) {
-            return undef;
-        }
-        elsif ( lc($e) eq 'or' ) {
-            return shift @list;
-        }
-        else {
-            # should not happen
-            $RT::Logger->error(
-                "Joins optimization failed when parsing '$string'. It's bug in RT, contact Best Practical"
-            );
-            die "Internal error. Contact your system administrator.";
-        }
-    }
-    return undef;
-}
-
 1;
 

commit 9695e3ee700d4f3eeb8f026942679038e09a5758
Author: Shawn M Moore <shawn at bestpractical.com>
Date:   Wed Jun 15 20:29:02 2016 +0000

    Apply RT's "Switch to parsing into a parse tree as an IR" to AssetSQL
    
        See RT's b68c84f0c915e558cbd127f94ef7740c1ec3c359

diff --git a/html/Asset/Search/Build.html b/html/Asset/Search/Build.html
index cec6e56..baf543b 100644
--- a/html/Asset/Search/Build.html
+++ b/html/Asset/Search/Build.html
@@ -177,30 +177,11 @@ foreach my $arg ( keys %ARGS ) {
     for ( my $i = 0; $i < @ops; $i++ ) {
         my ( $op, $value ) = ( $ops[$i], $values[$i] );
         next if !defined $value || $value eq '';
-        my $rawvalue = $value;
-
-        if ( $value =~ /^NULL$/i && $op =~ /=/ ) {
-            if ( $op eq '=' ) {
-                $op = "IS";
-            }
-            elsif ( $op eq '!=' ) {
-                $op = "IS NOT";
-            }
-        }
-        elsif ($value =~ /\D/) {
-            $value =~ s/(['\\])/\\$1/g;
-            $value = "'$value'";
-        }
-
-        if ($keyword =~ s/(['\\])/\\$1/g or $keyword =~ /[^{}\w\.]/) {
-            $keyword = "'$keyword'";
-        }
 
         my $clause = {
             Key   => $keyword,
             Op    => $op,
             Value => $value,
-            RawValue => $rawvalue,
         };
 
         push @new_values, RT::Interface::Web::QueryBuilder::Tree->new($clause);
diff --git a/lib/RT/Extension/AssetSQL.pm b/lib/RT/Extension/AssetSQL.pm
index a00ce8a..b5b8d1a 100644
--- a/lib/RT/Extension/AssetSQL.pm
+++ b/lib/RT/Extension/AssetSQL.pm
@@ -25,7 +25,7 @@ sub RT::Interface::Web::QueryBuilder::Tree::GetReferencedCatalogs {
             return unless $clause->{ Key } eq 'Catalog';
             return unless $clause->{ Op } eq '=';
 
-            $catalogs->{ $clause->{ RawValue } } = 1;
+            $catalogs->{ $clause->{ Value } } = 1;
         }
     );
 
@@ -56,33 +56,20 @@ sub RT::Interface::Web::QueryBuilder::Tree::ParseAssetSQL {
     $callback{ 'EntryAggregator' } = sub { $node->setNodeValue( $_[ 0 ] ) };
     $callback{ 'Condition' } = sub {
         my ( $key, $op, $value ) = @_;
-        my $rawvalue = $value;
 
-        my ( $main_key ) = split /[.]/, $key;
+        my ($main_key, $subkey) = split /[.]/, $key, 2;
 
-        my $class;
-        if ( exists $lcfield{ lc $main_key } ) {
-            $key =~ s/^[^.]+/ $lcfield{ lc $main_key } /e;
-            ( $main_key ) = split /[.]/, $key;    # make the case right
-            $class = $field{ $main_key }->[ 0 ];
-        }
-        unless ( $class ) {
+        unless( $lcfield{ lc $main_key} ) {
             push @results, [ $args{ 'CurrentUser' }->loc( "Unknown field: [_1]", $key ), -1 ];
         }
+        $main_key = $lcfield{ lc $main_key };
 
-        if ( lc $op eq 'is' || lc $op eq 'is not' ) {
-            $value = 'NULL';                      # just fix possible mistakes here
-        }
-        elsif ( $value !~ /^[+-]?[0-9]+$/ ) {
-            $value =~ s/(['\\])/\\$1/g;
-            $value = "'$value'";
-        }
-
-        if ( $key =~ s/(['\\])/\\$1/g or $key =~ /[^{}\w\.]/ ) {
-            $key = "'$key'";
-        }
+        # Hardcode value for IS / IS NOT
+        $value = 'NULL' if $op =~ /^IS( NOT)?$/i;
 
-        my $clause = { Key => $key, Op => $op, Value => $value, RawValue => $rawvalue };
+        my $clause = { Key => $main_key, Subkey => $subkey,
+                       Meta => $field{ $main_key },
+                       Op => $op, Value => $value };
         $node->addChild( RT::Interface::Web::QueryBuilder::Tree->new( $clause ) );
     };
     $callback{ 'Error' } = sub { push @results, @_ };
diff --git a/lib/RT/Extension/AssetSQL/Assets.pm b/lib/RT/Extension/AssetSQL/Assets.pm
index 61f3c41..e327635 100644
--- a/lib/RT/Extension/AssetSQL/Assets.pm
+++ b/lib/RT/Extension/AssetSQL/Assets.pm
@@ -1245,52 +1245,45 @@ failure.
 
 sub _parser {
     my ($self,$string) = @_;
+
+    require RT::Interface::Web::QueryBuilder::Tree;
+    my $tree = RT::Interface::Web::QueryBuilder::Tree->new;
+    $tree->ParseAssetSQL(
+        Query => $string,
+        CurrentUser => $self->CurrentUser,
+    );
+
     my $ea = '';
+    $tree->traverse(
+        sub {
+            my $node = shift;
+            $ea = $node->getParent->getNodeValue if $node->getIndex > 0;
+            return $self->_OpenParen unless $node->isLeaf;
 
-    my %callback;
-    $callback{'OpenParen'} = sub {
-      $self->_OpenParen;
-    };
-    $callback{'CloseParen'} = sub {
-      $self->_CloseParen;
-    };
-    $callback{'EntryAggregator'} = sub {
-      $ea = $_[0] || '';
-    };
-    $callback{'Condition'} = sub {
-        my ($key, $op, $value) = @_;
-
-        # key has dot then it's compound variant and we have subkey
-        my $subkey = '';
-        ($key, $subkey) = ($1, $2) if $key =~ /^([^\.]+)\.(.+)$/;
-
-        # normalize key and get class (type)
-        my $class;
-        if (exists $LOWER_CASE_FIELDS{lc $key}) {
-            $key = $LOWER_CASE_FIELDS{lc $key};
-            $class = $FIELD_METADATA{$key}->[0];
-        }
-        die "Unknown field '$key' in '$string'" unless $class;
+            my ($key, $subkey, $meta, $op, $value)
+                = @{$node->getNodeValue}{qw/Key Subkey Meta Op Value/};
 
-        # replace __CurrentUser__ with id
-        $value = $self->CurrentUser->id if $value eq '__CurrentUser__';
+            # normalize key and get class (type)
+            my $class = $meta->[0];
 
+            # replace __CurrentUser__ with id
+            $value = $self->CurrentUser->id if $value eq '__CurrentUser__';
 
-        unless( $dispatch{ $class } ) {
-            die "No dispatch method for class '$class'"
-        }
-        my $sub = $dispatch{ $class };
+            my $sub = $dispatch{ $class }
+                or die "No dispatch method for class '$class'";
 
-        # A reference to @res may be pushed onto $sub_tree{$key} from
-        # above, and we fill it here.
-        $sub->( $self, $key, $op, $value,
-                SUBCLAUSE       => '',  # don't need anymore
-                ENTRYAGGREGATOR => $ea,
-                SUBKEY          => $subkey,
-              );
-        $ea = '';
-    };
-    RT::SQL::Parse($string, \%callback);
+            # A reference to @res may be pushed onto $sub_tree{$key} from
+            # above, and we fill it here.
+            $sub->( $self, $key, $op, $value,
+                    ENTRYAGGREGATOR => $ea,
+                    SUBKEY          => $subkey,
+                  );
+        },
+        sub {
+            my $node = shift;
+            return $self->_CloseParen unless $node->isLeaf;
+        }
+    );
 }
 
 sub FromSQL {

commit 42185f0e8efb9aa9204d1f7fec5b7aeecfad49bb
Author: Shawn M Moore <shawn at bestpractical.com>
Date:   Wed Jun 15 20:31:37 2016 +0000

    Apply RT's "Bundling as an optimization pass" to AssetSQL
    
        See RT's 9541bb94e83a97f03f29e73970d0dad86adb6764

diff --git a/lib/RT/Extension/AssetSQL/Assets.pm b/lib/RT/Extension/AssetSQL/Assets.pm
index e327635..03bcfbf 100644
--- a/lib/RT/Extension/AssetSQL/Assets.pm
+++ b/lib/RT/Extension/AssetSQL/Assets.pm
@@ -1253,6 +1253,27 @@ sub _parser {
         CurrentUser => $self->CurrentUser,
     );
 
+    # Perform an optimization pass looking for watcher bundling
+    $tree->traverse(
+        sub {
+            my $node = shift;
+            return if $node->isLeaf;
+            return unless ($node->getNodeValue||'') eq "OR";
+            my %refs;
+            my @kids = grep {$_->{Meta}[0] eq "WATCHERFIELD"}
+                map {$_->getNodeValue}
+                grep {$_->isLeaf} $node->getAllChildren;
+            for (@kids) {
+                my $node = $_;
+                my ($key, $subkey, $op) = @{$node}{qw/Key Subkey Op/};
+                next if $node->{Meta}[1] and RT::Asset->Role($node->{Meta}[1])->{Column};
+                next if $op =~ /^!=$|\bNOT\b/i;
+                next if $op =~ /^IS( NOT)?$/i and not $subkey;
+                $node->{Bundle} = $refs{$node->{Meta}[1] || ''} ||= [];
+            }
+        }
+    );
+
     my $ea = '';
     $tree->traverse(
         sub {
@@ -1260,8 +1281,8 @@ sub _parser {
             $ea = $node->getParent->getNodeValue if $node->getIndex > 0;
             return $self->_OpenParen unless $node->isLeaf;
 
-            my ($key, $subkey, $meta, $op, $value)
-                = @{$node->getNodeValue}{qw/Key Subkey Meta Op Value/};
+            my ($key, $subkey, $meta, $op, $value, $bundle)
+                = @{$node->getNodeValue}{qw/Key Subkey Meta Op Value Bundle/};
 
             # normalize key and get class (type)
             my $class = $meta->[0];
@@ -1277,6 +1298,7 @@ sub _parser {
             $sub->( $self, $key, $op, $value,
                     ENTRYAGGREGATOR => $ea,
                     SUBKEY          => $subkey,
+                    BUNDLE          => $bundle,
                   );
         },
         sub {

commit da02117736d37c99757b49e313b853809a829e20
Author: Shawn M Moore <shawn at bestpractical.com>
Date:   Wed Jun 15 20:34:43 2016 +0000

    Apply RT's "support __Active__ and __Inactive__ status in sql" to AssetSQL
    
        See RT's 3f7258d0e6f6788d987f3f9a363c7c812a7f5b59
        and 85a34ae57bfa36b7f72d1383097f7bcb5a1f220e

diff --git a/lib/RT/Extension/AssetSQL/Assets.pm b/lib/RT/Extension/AssetSQL/Assets.pm
index 03bcfbf..c3e71ff 100644
--- a/lib/RT/Extension/AssetSQL/Assets.pm
+++ b/lib/RT/Extension/AssetSQL/Assets.pm
@@ -1,5 +1,6 @@
 use strict;
 use warnings;
+use 5.010;
 
 package RT::Assets;
 
@@ -1253,6 +1254,101 @@ sub _parser {
         CurrentUser => $self->CurrentUser,
     );
 
+    my $escape_quotes = sub {
+        my $text = shift;
+        $text =~ s{(['\\])}{\\$1}g;
+        return $text;
+    };
+
+    state ( $active_status_node, $inactive_status_node );
+
+    $tree->traverse(
+        sub {
+            my $node = shift;
+            return unless $node->isLeaf and $node->getNodeValue;
+            my ($key, $subkey, $meta, $op, $value, $bundle)
+                = @{$node->getNodeValue}{qw/Key Subkey Meta Op Value Bundle/};
+            return unless $key eq "Status" && $value =~ /^(?:__(?:in)?active__)$/i;
+
+            my $parent = $node->getParent;
+            my $index = $node->getIndex;
+
+            if ( ( lc $value eq '__inactive__' && $op eq '=' ) || ( lc $value eq '__active__' && $op eq '!=' ) ) {
+                unless ( $inactive_status_node ) {
+                    my %lifecycle =
+                      map { $_ => $RT::Lifecycle::LIFECYCLES{ $_ }{ inactive } }
+                      grep { @{ $RT::Lifecycle::LIFECYCLES{ $_ }{ inactive } || [] } }
+                      keys %RT::Lifecycle::LIFECYCLES;
+                    return unless %lifecycle;
+
+                    my $sql;
+                    if ( keys %lifecycle == 1 ) {
+                        $sql = join ' OR ', map { qq{ Status = '$_' } } map { $escape_quotes->($_) } map { @$_ } values %lifecycle;
+                    }
+                    else {
+                        my @inactive_sql;
+                        for my $name ( keys %lifecycle ) {
+                            my $escaped_name = $escape_quotes->($name);
+                            my $inactive_sql =
+                                qq{Lifecycle = '$escaped_name'}
+                              . ' AND ('
+                              . join( ' OR ', map { qq{ Status = '$_' } } map { $escape_quotes->($_) } @{ $lifecycle{ $name } } ) . ')';
+                            push @inactive_sql, qq{($inactive_sql)};
+                        }
+                        $sql = join ' OR ', @inactive_sql;
+                    }
+                    $inactive_status_node = RT::Interface::Web::QueryBuilder::Tree->new;
+                    $inactive_status_node->ParseAssetSQL(
+                        Query       => $sql,
+                        CurrentUser => $self->CurrentUser,
+                    );
+                }
+                $parent->removeChild( $node );
+                $parent->insertChild( $index, $inactive_status_node );
+            }
+            else {
+                unless ( $active_status_node ) {
+                    my %lifecycle =
+                      map {
+                        $_ => [
+                            @{ $RT::Lifecycle::LIFECYCLES{ $_ }{ initial } || [] },
+                            @{ $RT::Lifecycle::LIFECYCLES{ $_ }{ active }  || [] },
+                          ]
+                      }
+                      grep {
+                             @{ $RT::Lifecycle::LIFECYCLES{ $_ }{ initial } || [] }
+                          || @{ $RT::Lifecycle::LIFECYCLES{ $_ }{ active }  || [] }
+                      } keys %RT::Lifecycle::LIFECYCLES;
+                    return unless %lifecycle;
+
+                    my $sql;
+                    if ( keys %lifecycle == 1 ) {
+                        $sql = join ' OR ', map { qq{ Status = '$_' } } map { $escape_quotes->($_) } map { @$_ } values %lifecycle;
+                    }
+                    else {
+                        my @active_sql;
+                        for my $name ( keys %lifecycle ) {
+                            my $escaped_name = $escape_quotes->($name);
+                            my $active_sql =
+                                qq{Lifecycle = '$escaped_name'}
+                              . ' AND ('
+                              . join( ' OR ', map { qq{ Status = '$_' } } map { $escape_quotes->($_) } @{ $lifecycle{ $name } } ) . ')';
+                            push @active_sql, qq{($active_sql)};
+                        }
+                        $sql = join ' OR ', @active_sql;
+                    }
+                    $active_status_node = RT::Interface::Web::QueryBuilder::Tree->new;
+                    $active_status_node->ParseAssetSQL(
+                        Query       => $sql,
+                        CurrentUser => $self->CurrentUser,
+                    );
+                }
+                $parent->removeChild( $node );
+                $parent->insertChild( $index, $active_status_node );
+            }
+        }
+    );
+
     # Perform an optimization pass looking for watcher bundling
     $tree->traverse(
         sub {

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


More information about the Bps-public-commit mailing list