[Rt-commit] r4551 - in rt/branches/CHALDEA-EXPERIMENTAL: lib/RT
jesse at bestpractical.com
jesse at bestpractical.com
Thu Feb 16 21:29:48 EST 2006
Author: jesse
Date: Thu Feb 16 21:29:47 2006
New Revision: 4551
Modified:
rt/branches/CHALDEA-EXPERIMENTAL/ (props changed)
rt/branches/CHALDEA-EXPERIMENTAL/lib/RT/Tickets_Overlay.pm
Log:
r23826 at truegrounds: jesse | 2006-02-16 18:25:05 -0800
* Backport tickets_overlay from 3.5. Fix a bug that stopped search on global custom fields
Modified: rt/branches/CHALDEA-EXPERIMENTAL/lib/RT/Tickets_Overlay.pm
==============================================================================
--- rt/branches/CHALDEA-EXPERIMENTAL/lib/RT/Tickets_Overlay.pm (original)
+++ rt/branches/CHALDEA-EXPERIMENTAL/lib/RT/Tickets_Overlay.pm Thu Feb 16 21:29:47 2006
@@ -316,8 +316,8 @@
Handle fields which deal with links between tickets. (MemberOf, DependsOn)
Meta Data:
- 1: Direction (From,To)
- 2: Link Type (MemberOf, DependsOn,RefersTo)
+ 1: Direction (From, To)
+ 2: Link Type (MemberOf, DependsOn, RefersTo)
=cut
@@ -325,17 +325,15 @@
my ( $sb, $field, $op, $value, @rest ) = @_;
my $meta = $FIELD_METADATA{$field};
- die "Invalid Operator $op for $field" unless $op =~ /^(=|!=|IS)/io;
-
die "Incorrect Metadata for $field"
- unless ( defined $meta->[1] and defined $meta->[2] );
+ unless defined $meta->[1] && defined $meta->[2];
+
+ die "Invalid Operator $op for $field" unless $op =~ /^(=|!=|IS|IS NOT)$/io;
my $direction = $meta->[1];
my $matchfield;
my $linkfield;
- my $is_local = 1;
- my $is_null = 0;
if ( $direction eq 'To' ) {
$matchfield = "Target";
$linkfield = "Base";
@@ -350,84 +348,105 @@
die "Invalid link direction '$meta->[1]' for $field\n";
}
- if ( $op eq '=' || $op =~ /^is/oi ) {
- if ( $value eq '' || $value =~ /^null$/io ) {
- $is_null = 1;
- }
- elsif ( $value =~ /\D/o ) {
- $is_local = 0;
- }
- else {
- $is_local = 1;
- }
+ my ($is_local, $is_null) = (1, 0);
+ if ( !$value || $value =~ /^null$/io ) {
+ $is_null = 1;
+ $op = ($op =~ /^(=|IS)$/)? 'IS': 'IS NOT';
+ }
+ elsif ( $value =~ /\D/o ) {
+ $is_local = 0;
+ }
+ $matchfield = "Local$matchfield" if $is_local;
+
+ my $is_negative = 0;
+ if ( $op eq '!=' ) {
+ $is_negative = 1;
+ $op = '=';
}
#For doing a left join to find "unlinked tickets" we want to generate a query that looks like this
# SELECT main.* FROM Tickets main
# LEFT JOIN Links Links_1 ON ( (Links_1.Type = 'MemberOf')
# AND(main.id = Links_1.LocalTarget))
-# WHERE ((main.EffectiveId = main.id))
-# AND ((main.Status != 'deleted'))
-# AND (Links_1.LocalBase IS NULL);
+# WHERE Links_1.LocalBase IS NULL;
if ($is_null) {
my $linkalias = $sb->Join(
- TYPE => 'left',
+ TYPE => 'LEFT',
ALIAS1 => 'main',
FIELD1 => 'id',
TABLE2 => 'Links',
FIELD2 => 'Local' . $linkfield
);
-
$sb->SUPER::Limit(
LEFTJOIN => $linkalias,
FIELD => 'Type',
OPERATOR => '=',
VALUE => $meta->[2],
+ );
+ $sb->_SQLLimit(
@rest,
+ ALIAS => $linkalias,
+ FIELD => $matchfield,
+ OPERATOR => $op,
+ VALUE => 'NULL',
+ QUOTEVALUE => 0,
+ );
+ }
+ elsif ( $is_negative ) {
+ my $linkalias = $sb->Join(
+ TYPE => 'LEFT',
+ ALIAS1 => 'main',
+ FIELD1 => 'id',
+ TABLE2 => 'Links',
+ FIELD2 => 'Local' . $linkfield
+ );
+ $sb->SUPER::Limit(
+ LEFTJOIN => $linkalias,
+ FIELD => 'Type',
+ OPERATOR => '=',
+ VALUE => $meta->[2],
+ );
+ $sb->SUPER::Limit(
+ LEFTJOIN => $linkalias,
+ FIELD => $matchfield,
+ OPERATOR => $op,
+ VALUE => $value,
);
-
$sb->_SQLLimit(
- ALIAS => $linkalias,
- ENTRYAGGREGATOR => 'AND',
- FIELD => ( $is_local ? "Local$matchfield" : $matchfield ),
+ @rest,
+ ALIAS => $linkalias,
+ FIELD => $matchfield,
OPERATOR => 'IS',
VALUE => 'NULL',
- QUOTEVALUE => '0',
+ QUOTEVALUE => 0,
);
-
}
else {
-
- $sb->{_sql_linkalias} = $sb->NewAlias('Links')
- unless defined $sb->{_sql_linkalias};
-
+ my $linkalias = $sb->NewAlias('Links');
$sb->_OpenParen();
-
$sb->_SQLLimit(
- ALIAS => $sb->{_sql_linkalias},
+ @rest,
+ ALIAS => $linkalias,
FIELD => 'Type',
OPERATOR => '=',
VALUE => $meta->[2],
- @rest,
);
-
$sb->_SQLLimit(
- ALIAS => $sb->{_sql_linkalias},
+ ALIAS => $linkalias,
+ FIELD => 'Local' . $linkfield,
+ OPERATOR => '=',
+ VALUE => 'main.id',
+ QUOTEVALUE => 0,
ENTRYAGGREGATOR => 'AND',
- FIELD => ( $is_local ? "Local$matchfield" : $matchfield ),
- OPERATOR => '=',
- VALUE => $value,
);
-
- #If we're searching on target, join the base to ticket.id
- $sb->_SQLJoin(
- ALIAS1 => 'main',
- FIELD1 => $sb->{'primary_key'},
- ALIAS2 => $sb->{_sql_linkalias},
- FIELD2 => 'Local' . $linkfield
+ $sb->_SQLLimit(
+ ALIAS => $linkalias,
+ FIELD => $matchfield,
+ OPERATOR => $op,
+ VALUE => $value,
+ ENTRYAGGREGATOR => 'AND',
);
-
$sb->_CloseParen();
}
}
@@ -1142,64 +1161,62 @@
}
}
-=head2 KeywordLimit
-Limit based on Keywords
-Meta Data:
- none
+=head2 _CustomFieldDecipher
+
+Try and turn a CF descriptor into (cfid, cfname) object pair.
+
=cut
-sub _CustomFieldLimit {
- my ( $self, $_field, $op, $value, @rest ) = @_;
-
- my %rest = @rest;
- my $field = $rest{SUBKEY} || die "No field specified";
-
- # For our sanity, we can only limit on one queue at a time
- my $queue = 0;
-
- if ( $field =~ /^(.+?)\.{(.+)}$/ ) {
- $queue = $1;
- $field = $2;
- }
- $field = $1 if $field =~ /^{(.+)}$/; # trim { }
-
- # If we're trying to find custom fields that don't match something, we
- # want tickets where the custom field has no value at all. Note that
- # we explicitly don't include the "IS NULL" case, since we would
- # otherwise end up with a redundant clause.
-
- my $null_columns_ok;
- if ( ( $op =~ /^NOT LIKE$/i ) or ( $op eq '!=' ) ) {
- $null_columns_ok = 1;
- }
-
- my $cfid = 0;
- if ($queue) {
-
- my $q = RT::Queue->new( $self->CurrentUser );
- $q->Load($queue) if ($queue);
-
- my $cf;
- if ( $q->id ) {
- $cf = $q->CustomField($field);
- }
- else {
- $cf = RT::CustomField->new( $self->CurrentUser );
- $cf->LoadByNameAndQueue( Queue => '0', Name => $field );
- }
-
- $cfid = $cf->id;
-
+sub _CustomFieldDecipher {
+ my ($self, $field) = @_;
+
+ my $queue = 0;
+ if ( $field =~ /^(.+?)\.{(.+)}$/ ) {
+ $queue = $1;
+ $field = $2;
+ }
+ $field = $1 if $field =~ /^{(.+)}$/; # trim { }
+
+ my $cfid;
+
+ if ($queue) {
+ my $q = RT::Queue->new( $self->CurrentUser );
+ $q->Load($queue) if ($queue);
+
+ my $cf;
+ if ( $q->id ) {
+ # $queue = $q->Name; # should we normalize the queue?
+ $cf = $q->CustomField($field);
}
+ else {
+ $cf = RT::CustomField->new( $self->CurrentUser );
+ $cf->LoadByNameAndQueue( Queue => '0', Name => $field );
+ }
+ $cfid = $cf->id if $cf;
+ }
+
+ return ($queue, $field, $cfid);
+
+}
+
+
+
+=head2 _CustomFieldJoin
+
+Factor out the Join of custom fields so we can use it for sorting too
- my $TicketCFs;
- my $CFs;
- my $cfkey = $cfid ? $cfid : "$queue.$field";
+=cut
+sub _CustomFieldJoin {
+ my ($self, $cfkey, $cfid, $field) = @_;
+
+ my $TicketCFs;
+ my $CFs;
# Perform one Join per CustomField
+
if ( $self->{_sql_object_cf_alias}{$cfkey} ) {
$TicketCFs = $self->{_sql_object_cf_alias}{$cfkey};
}
@@ -1226,6 +1243,16 @@
TABLE2 => 'ObjectCustomFields',
FIELD2 => 'ObjectId',
);
+
+ $self->SUPER::Limit(
+ LEFTJOIN => $ocfalias,
+ ENTRYAGGREGATOR => 'OR',
+ FIELD => 'ObjectId',
+ VALUE => '0',
+
+ );
+
+
$CFs = $self->Join(
TYPE => 'left',
ALIAS1 => $ocfalias,
@@ -1264,16 +1291,52 @@
);
}
- $self->_OpenParen;
+ return ($TicketCFs, $CFs);
+}
- $self->SUPER::Limit(
- ALIAS => $CFs,
- FIELD => 'name',
- VALUE => $field,
- ENTRYAGGREGATOR => 'AND',
- );
+=head2 _CustomFieldLimit
+
+Limit based on CustomFields
+
+Meta Data:
+ none
+
+=cut
+
+sub _CustomFieldLimit {
+ my ( $self, $_field, $op, $value, @rest ) = @_;
+
+ my %rest = @rest;
+ my $field = $rest{SUBKEY} || die "No field specified";
+
+ # For our sanity, we can only limit on one queue at a time
+
+ my ($queue, $field, $cfid ) = $self->_CustomFieldDecipher( $field );
+
+# If we're trying to find custom fields that don't match something, we
+# want tickets where the custom field has no value at all. Note that
+# we explicitly don't include the "IS NULL" case, since we would
+# otherwise end up with a redundant clause.
+
+ my $null_columns_ok;
+ if ( ( $op =~ /^NOT LIKE$/i ) or ( $op eq '!=' ) ) {
+ $null_columns_ok = 1;
+ }
+
+ my $cfkey = $cfid ? $cfid : "$queue.$field";
+ my ($TicketCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field );
+
+ $self->_OpenParen;
+
+ $self->SUPER::Limit(
+ ALIAS => $CFs,
+ FIELD => 'name',
+ VALUE => $field,
+ ENTRYAGGREGATOR => 'AND',
+ );
+
+ $self->_OpenParen if $null_columns_ok;
- $self->_OpenParen if $null_columns_ok;
$self->_SQLLimit(
ALIAS => $TicketCFs,
FIELD => 'Content',
@@ -1324,12 +1387,66 @@
push @res, $row;
next;
}
- my ( $field, $subkey ) = split /\./, $row->{FIELD};
+ my ( $field, $subkey ) = split /\./, $row->{FIELD}, 2;
my $meta = $self->FIELDS->{$field};
if ( $meta->[0] eq 'WATCHERFIELD' ) {
my $users = $self->_WatcherJoin( $meta->[1], "order" . $order++ );
push @res, { %$row, ALIAS => $users, FIELD => $subkey };
- }
+
+
+ } elsif ( $meta->[0] eq 'CUSTOMFIELD' ) {
+ my ($queue, $field, $cfid ) = $self->_CustomFieldDecipher( $subkey );
+ my $cfkey = $cfid ? $cfid : "$queue.$field";
+ my ($TicketCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field );
+ unless ($cfid) {
+ # For those cases where we are doing a join against the
+ # CF name, and don't have a CFid, use Unique to make sure
+ # we don't show duplicate tickets. NOTE: I'm pretty sure
+ # this will stay mixed in for the life of the
+ # class/package, and not just for the life of the object.
+ # Potential performance issue.
+ require DBIx::SearchBuilder::Unique;
+ DBIx::SearchBuilder::Unique->import;
+ }
+ my $CFvs = $self->Join(
+ TYPE => 'left',
+ ALIAS1 => $TicketCFs,
+ FIELD1 => 'CustomField',
+ TABLE2 => 'CustomFieldValues',
+ FIELD2 => 'CustomField',
+ );
+ $self->SUPER::Limit(
+ LEFTJOIN => $CFvs,
+ FIELD => 'Name',
+ QUOTEVALUE => 0,
+ VALUE => $TicketCFs . ".Content",
+ ENTRYAGGREGATOR => 'AND'
+ );
+
+ push @res, { %$row, ALIAS => $CFvs, FIELD => 'SortOrder' };
+ push @res, { %$row, ALIAS => $TicketCFs, FIELD => 'Content' };
+ } elsif ( $field eq "Custom" && $subkey eq "Ownership") {
+ # PAW logic is "reversed"
+ my $order = "ASC";
+ if (exists $row->{ORDER} ) {
+ my $o = $row->{ORDER};
+ delete $row->{ORDER};
+ $order = "DESC" if $o =~ /asc/i;
+ }
+
+ # Unowned
+ # Else
+
+ # Ticket.Owner 1 0 0
+ my $ownerId = $self->CurrentUser->Id;
+ push @res, { %$row, FIELD => "Owner=$ownerId", ORDER => $order } ;
+
+ # Unowned Tickets 0 1 0
+ my $nobodyId = $RT::Nobody->Id;
+ push @res, { %$row, FIELD => "Owner=$nobodyId", ORDER => $order } ;
+
+ push @res, { %$row, FIELD => "Priority", ORDER => $order } ;
+ }
else {
push @res, $row;
}
@@ -1964,9 +2081,10 @@
sub LimitLinkedTo {
my $self = shift;
my %args = (
- TICKET => undef,
- TARGET => undef,
- TYPE => undef,
+ TICKET => undef,
+ TARGET => undef,
+ TYPE => undef,
+ OPERATOR => '=',
@_
);
@@ -1980,6 +2098,7 @@
$self->loc( $args{'TYPE'} ),
( $args{'TARGET'} || $args{'TICKET'} )
),
+ OPERATOR => $args{'OPERATOR'},
);
}
@@ -2002,9 +2121,10 @@
sub LimitLinkedFrom {
my $self = shift;
my %args = (
- BASE => undef,
- TICKET => undef,
- TYPE => undef,
+ BASE => undef,
+ TICKET => undef,
+ TYPE => undef,
+ OPERATOR => '=',
@_
);
@@ -2026,6 +2146,7 @@
$self->loc( $args{'TYPE'} ),
( $args{'BASE'} || $args{'TICKET'} )
),
+ OPERATOR => $args{'OPERATOR'},
);
}
@@ -2035,11 +2156,11 @@
sub LimitMemberOf {
my $self = shift;
my $ticket_id = shift;
- $self->LimitLinkedTo(
- TARGET => "$ticket_id",
+ return $self->LimitLinkedTo(
+ @_,
+ TARGET => $ticket_id,
TYPE => 'MemberOf',
);
-
}
# }}}
@@ -2048,7 +2169,8 @@
sub LimitHasMember {
my $self = shift;
my $ticket_id = shift;
- $self->LimitLinkedFrom(
+ return $self->LimitLinkedFrom(
+ @_,
BASE => "$ticket_id",
TYPE => 'HasMember',
);
@@ -2062,8 +2184,9 @@
sub LimitDependsOn {
my $self = shift;
my $ticket_id = shift;
- $self->LimitLinkedTo(
- TARGET => "$ticket_id",
+ return $self->LimitLinkedTo(
+ @_,
+ TARGET => $ticket_id,
TYPE => 'DependsOn',
);
@@ -2076,8 +2199,9 @@
sub LimitDependedOnBy {
my $self = shift;
my $ticket_id = shift;
- $self->LimitLinkedFrom(
- BASE => "$ticket_id",
+ return $self->LimitLinkedFrom(
+ @_,
+ BASE => $ticket_id,
TYPE => 'DependentOn',
);
@@ -2090,8 +2214,9 @@
sub LimitRefersTo {
my $self = shift;
my $ticket_id = shift;
- $self->LimitLinkedTo(
- TARGET => "$ticket_id",
+ return $self->LimitLinkedTo(
+ @_,
+ TARGET => $ticket_id,
TYPE => 'RefersTo',
);
@@ -2104,11 +2229,11 @@
sub LimitReferredToBy {
my $self = shift;
my $ticket_id = shift;
- $self->LimitLinkedFrom(
- BASE => "$ticket_id",
+ return $self->LimitLinkedFrom(
+ @_,
+ BASE => $ticket_id,
TYPE => 'ReferredToBy',
);
-
}
# }}}
More information about the Rt-commit
mailing list