[Rt-commit] r4722 - in rt/branches/QUEBEC-EXPERIMENTAL: .
alexmv at bestpractical.com
alexmv at bestpractical.com
Thu Mar 9 18:13:24 EST 2006
Author: alexmv
Date: Thu Mar 9 18:13:22 2006
New Revision: 4722
Modified:
rt/branches/QUEBEC-EXPERIMENTAL/ (props changed)
rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Tickets_Overlay.pm
Log:
r8473 at zoq-fot-pik: chmrr | 2006-03-09 18:13:13 -0500
* Backport from 3.7 for CustomFields fixes
Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Tickets_Overlay.pm
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Tickets_Overlay.pm (original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Tickets_Overlay.pm Thu Mar 9 18:13:22 2006
@@ -160,7 +160,7 @@
LINKFIELD => \&_LinkFieldLimit,
CUSTOMFIELD => \&_CustomFieldLimit,
);
-my %can_bundle = ( WATCHERFIELD => "yes", );
+my %can_bundle = ();# WATCHERFIELD => "yes", );
# Default EntryAggregator per type
# if you specify OP, you must specify all valid OPs
@@ -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();
}
}
@@ -871,8 +890,8 @@
# we cache joins chain per watcher type
# if we limit by requestor then we shouldn't join requestors again
# for sort or limit on other requestors
- if ( $self->{'_watcher_join_users_alias'}{ $type || 'any' } ) {
- return $self->{'_watcher_join_users_alias'}{ $type || 'any' };
+ if ( $self->{'_sql_watcher_join_users_alias'}{ $type || 'any' } ) {
+ return $self->{'_sql_watcher_join_users_alias'}{ $type || 'any' };
}
# we always have watcher groups for ticket
@@ -919,7 +938,7 @@
# RT doesn't allow to add groups as members of the
# ticket roles, so we just hide entries in CGM table
# with MemberId == GroupId from results
- my $groupmembers = $self->SUPER::Limit(
+ $self->SUPER::Limit(
LEFTJOIN => $groupmembers,
FIELD => 'GroupId',
OPERATOR => '!=',
@@ -933,7 +952,7 @@
TABLE2 => 'Users',
FIELD2 => 'id'
);
- return $self->{'_watcher_join_users_alias'}{ $type || 'any' } = $users;
+ return $self->{'_sql_watcher_join_users_alias'}{ $type || 'any' } = $users;
}
=head2 _WatcherMembershipLimit
@@ -1142,66 +1161,59 @@
}
}
-=head2 KeywordLimit
-Limit based on Keywords
+=head2 _CustomFieldDecipher
-Meta Data:
- none
+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
+sub _CustomFieldDecipher {
+ my ($self, $field) = @_;
+
my $queue = 0;
-
if ( $field =~ /^(.+?)\.{(.+)}$/ ) {
- $queue = $1;
- $field = $2;
+ ($queue, $field) = ($1, $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 $cfid;
+ if ( $queue ) {
my $q = RT::Queue->new( $self->CurrentUser );
- $q->Load($queue) if ($queue);
+ $q->Load( $queue ) if $queue;
my $cf;
if ( $q->id ) {
- $cf = $q->CustomField($field);
+ # $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 );
+ $cf->LoadByNameAndQueue( Queue => 0, Name => $field );
}
+ $cfid = $cf->id if $cf;
+ }
+
+ return ($queue, $field, $cfid);
+
+}
+
+=head2 _CustomFieldJoin
- $cfid = $cf->id;
+Factor out the Join of custom fields so we can use it for sorting too
- }
+=cut
+sub _CustomFieldJoin {
+ my ($self, $cfkey, $cfid, $field) = @_;
+
my $TicketCFs;
my $CFs;
- my $cfkey = $cfid ? $cfid : "$queue.$field";
-
# Perform one Join per CustomField
+
if ( $self->{_sql_object_cf_alias}{$cfkey} ) {
$TicketCFs = $self->{_sql_object_cf_alias}{$cfkey};
+ $CFs = $self->{_sql_cf_alias}{$cfkey};
}
else {
if ($cfid) {
@@ -1226,7 +1238,17 @@
TABLE2 => 'ObjectCustomFields',
FIELD2 => 'ObjectId',
);
- $CFs = $self->Join(
+
+ $self->SUPER::Limit(
+ LEFTJOIN => $ocfalias,
+ ENTRYAGGREGATOR => 'OR',
+ FIELD => 'ObjectId',
+ VALUE => '0',
+
+ );
+
+
+ $CFs = $self->{_sql_cf_alias}{$cfkey} = $self->Join(
TYPE => 'left',
ALIAS1 => $ocfalias,
FIELD1 => 'CustomField',
@@ -1264,16 +1286,55 @@
);
}
- $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, $cfid);
+ ($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;
+
+ unless ($cfid) {
+ $self->SUPER::Limit(
+ ALIAS => $CFs,
+ FIELD => 'name',
+ VALUE => $field,
+ ENTRYAGGREGATOR => 'AND',
+ );
+ }
+
$self->_OpenParen if $null_columns_ok;
+
$self->_SQLLimit(
ALIAS => $TicketCFs,
FIELD => 'Content',
@@ -1292,8 +1353,8 @@
QUOTEVALUE => 0,
ENTRYAGGREGATOR => 'OR',
);
+ $self->_CloseParen;
}
- $self->_CloseParen if $null_columns_ok;
$self->_CloseParen;
@@ -1324,15 +1385,69 @@
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 };
- }
- else {
- push @res, $row;
- }
+
+
+ } 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;
+ }
}
return $self->SUPER::OrderByCols(@res);
}
@@ -2035,11 +2150,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 +2163,8 @@
sub LimitHasMember {
my $self = shift;
my $ticket_id = shift;
- $self->LimitLinkedFrom(
+ return $self->LimitLinkedFrom(
+ @_,
BASE => "$ticket_id",
TYPE => 'HasMember',
);
@@ -2062,8 +2178,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 +2193,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 +2208,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 +2223,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