[Rt-commit] rt branch, 4.0/extensible-ticketsql-cf-limits, created. rt-4.0.13-98-g628aaba
Thomas Sibley
trs at bestpractical.com
Fri Jun 28 16:49:34 EDT 2013
The branch, 4.0/extensible-ticketsql-cf-limits has been created
at 628aabaeba4741dbc0897be6e4d878d7eabf10b8 (commit)
- Log -----------------------------------------------------------------
commit 1ea10ce041b71633d1c7b5bcfe2ed109b977a05e
Author: Thomas Sibley <trs at bestpractical.com>
Date: Wed Feb 6 17:25:22 2013 -0800
Allow CustomFieldLookupType to be called as a class method
(cherry picked from commit 1ff3f2b0a97d1e336ced7542ce2b0201ff5309fc)
diff --git a/lib/RT/Record.pm b/lib/RT/Record.pm
index 61b66d5..1597784 100644
--- a/lib/RT/Record.pm
+++ b/lib/RT/Record.pm
@@ -1616,7 +1616,7 @@ Returns the path RT uses to figure out which custom fields apply to this object.
sub CustomFieldLookupType {
my $self = shift;
- return ref($self);
+ return ref($self) || $self;
}
commit 93b4f27f47c51f4dcec0338ea8afcb76fc62b1a5
Author: Kevin Falcone <falcone at bestpractical.com>
Date: Mon Jan 30 17:27:49 2012 -0500
Add an ObjectTypeFromlookupType method and document RecordClassFromLookupType
RecordClassFromLookupType is useful when joining to ObjectCustomFields,
but there wasn't an existing method for code that wants to join to
ObjectCustomFieldValues, so we can borrow the code and tweak the regex a
bit.
diff --git a/lib/RT/CustomField.pm b/lib/RT/CustomField.pm
index a69c6f4..11701b9 100644
--- a/lib/RT/CustomField.pm
+++ b/lib/RT/CustomField.pm
@@ -1205,12 +1205,37 @@ sub FriendlyLookupType {
return ( $self->loc( $FriendlyObjectTypes[$#types], @types ) );
}
+=head1 RecordClassFromLookupType
+
+Returns the type of Object referred to by ObjectCustomFields' ObjectId column
+
+=cut
+
sub RecordClassFromLookupType {
my $self = shift;
my ($class) = ($self->LookupType =~ /^([^-]+)/);
unless ( $class ) {
$RT::Logger->error(
- "Custom Field #". $self->id
+ "Custom Field #". $self->id
+ ." has incorrect LookupType '". $self->LookupType ."'"
+ );
+ return undef;
+ }
+ return $class;
+}
+
+=head1 ObjectTypeFromLookupType
+
+Returns the ObjectType used in ObjectCustomFieldValues rows for this CF
+
+=cut
+
+sub ObjectTypeFromLookupType {
+ my $self = shift;
+ my ($class) = ($self->LookupType =~ /([^-]+)$/);
+ unless ( $class ) {
+ $RT::Logger->error(
+ "Custom Field #". $self->id
." has incorrect LookupType '". $self->LookupType ."'"
);
return undef;
commit 8031dcf0d8d4e630e8ee4d69478b933aa78d78cf
Author: Thomas Sibley <trs at bestpractical.com>
Date: Wed Jun 26 16:06:31 2013 -0700
ObjectType/RecordTypeFromLookupType as class methods
Where LookupType must be passed as an argument.
diff --git a/lib/RT/CustomField.pm b/lib/RT/CustomField.pm
index 11701b9..0211815 100644
--- a/lib/RT/CustomField.pm
+++ b/lib/RT/CustomField.pm
@@ -51,7 +51,7 @@ package RT::CustomField;
use strict;
use warnings;
-
+use Scalar::Util 'blessed';
use base 'RT::Record';
@@ -1209,16 +1209,25 @@ sub FriendlyLookupType {
Returns the type of Object referred to by ObjectCustomFields' ObjectId column
+Optionally takes a LookupType to use instead of using the value on the loaded
+record. In this case, the method may be called on the class instead of an
+object.
+
=cut
sub RecordClassFromLookupType {
my $self = shift;
- my ($class) = ($self->LookupType =~ /^([^-]+)/);
+ my $type = shift || $self->LookupType;
+ my ($class) = ($type =~ /^([^-]+)/);
unless ( $class ) {
- $RT::Logger->error(
- "Custom Field #". $self->id
- ." has incorrect LookupType '". $self->LookupType ."'"
- );
+ if (blessed($self) and $self->LookupType eq $type) {
+ $RT::Logger->error(
+ "Custom Field #". $self->id
+ ." has incorrect LookupType '$type'"
+ );
+ } else {
+ RT->Logger->error("Invalid LookupType passed as argument: $type");
+ }
return undef;
}
return $class;
@@ -1228,16 +1237,25 @@ sub RecordClassFromLookupType {
Returns the ObjectType used in ObjectCustomFieldValues rows for this CF
+Optionally takes a LookupType to use instead of using the value on the loaded
+record. In this case, the method may be called on the class instead of an
+object.
+
=cut
sub ObjectTypeFromLookupType {
my $self = shift;
- my ($class) = ($self->LookupType =~ /([^-]+)$/);
+ my $type = shift || $self->LookupType;
+ my ($class) = ($type =~ /([^-]+)$/);
unless ( $class ) {
- $RT::Logger->error(
- "Custom Field #". $self->id
- ." has incorrect LookupType '". $self->LookupType ."'"
- );
+ if (blessed($self) and $self->LookupType eq $type) {
+ $RT::Logger->error(
+ "Custom Field #". $self->id
+ ." has incorrect LookupType '$type'"
+ );
+ } else {
+ RT->Logger->error("Invalid LookupType passed as argument: $type");
+ }
return undef;
}
return $class;
commit 5b6f9b9513114ce2aee99f495996b2f333b956b8
Author: Thomas Sibley <trs at bestpractical.com>
Date: Wed Jun 26 22:56:11 2013 -0700
Refactor part of LimitToGlobalOrObjectId into LimitToObjectId
Useful when you only want to find CFs applied to a certain object and
not global ones too.
diff --git a/lib/RT/CustomFields.pm b/lib/RT/CustomFields.pm
index 017018e..1ea75da 100644
--- a/lib/RT/CustomFields.pm
+++ b/lib/RT/CustomFields.pm
@@ -141,6 +141,25 @@ sub LimitToParentType {
$self->Limit( FIELD => 'LookupType', STARTSWITH => "$lookup" );
}
+=head2 LimitToObjectId
+
+Takes an ObjectId and limits the collection to CFs applied to said object.
+
+When called multiple times the ObjectId limits are joined with OR.
+
+=cut
+
+sub LimitToObjectId {
+ my $self = shift;
+ my $id = shift;
+ $self->Limit(
+ ALIAS => $self->_OCFAlias,
+ FIELD => 'ObjectId',
+ OPERATOR => '=',
+ VALUE => $id || 0,
+ ENTRYAGGREGATOR => 'OR'
+ );
+}
=head2 LimitToGlobalOrObjectId
@@ -155,19 +174,11 @@ sub LimitToGlobalOrObjectId {
foreach my $id (@_) {
- $self->Limit( ALIAS => $self->_OCFAlias,
- FIELD => 'ObjectId',
- OPERATOR => '=',
- VALUE => $id || 0,
- ENTRYAGGREGATOR => 'OR' );
- $global_only = 0 if $id;
+ $self->LimitToObjectId($id);
+ $global_only = 0 if $id;
}
- $self->Limit( ALIAS => $self->_OCFAlias,
- FIELD => 'ObjectId',
- OPERATOR => '=',
- VALUE => 0,
- ENTRYAGGREGATOR => 'OR' ) unless $global_only;
+ $self->LimitToObjectId(0) unless $global_only;
}
sub _LimitToOCFs {
commit 5a2c4002c0aa30111890b2f8dcef395886eedd76
Author: Kevin Falcone <falcone at bestpractical.com>
Date: Mon Jan 30 17:31:47 2012 -0500
Rename some variables that will become confusing.
As these join aliases start to refer to transaction cfs and not just
ticket cfs, it is really weird to have everything named TicketCFs
diff --git a/lib/RT/Tickets.pm b/lib/RT/Tickets.pm
index 41aa313..679186b 100644
--- a/lib/RT/Tickets.pm
+++ b/lib/RT/Tickets.pm
@@ -1374,9 +1374,9 @@ sub _CustomFieldJoin {
$self->{_sql_cf_alias}{$cfkey} );
}
- my ($TicketCFs, $CFs);
+ my ($ObjectCFs, $CFs);
if ( $cfid ) {
- $TicketCFs = $self->{_sql_object_cfv_alias}{$cfkey} = $self->Join(
+ $ObjectCFs = $self->{_sql_object_cfv_alias}{$cfkey} = $self->Join(
TYPE => 'LEFT',
ALIAS1 => 'main',
FIELD1 => 'id',
@@ -1384,7 +1384,7 @@ sub _CustomFieldJoin {
FIELD2 => 'ObjectId',
);
$self->SUPER::Limit(
- LEFTJOIN => $TicketCFs,
+ LEFTJOIN => $ObjectCFs,
FIELD => 'CustomField',
VALUE => $cfid,
ENTRYAGGREGATOR => 'AND'
@@ -1425,7 +1425,7 @@ sub _CustomFieldJoin {
VALUE => $field,
);
- $TicketCFs = $self->{_sql_object_cfv_alias}{$cfkey} = $self->Join(
+ $ObjectCFs = $self->{_sql_object_cfv_alias}{$cfkey} = $self->Join(
TYPE => 'LEFT',
ALIAS1 => $CFs,
FIELD1 => 'id',
@@ -1433,7 +1433,7 @@ sub _CustomFieldJoin {
FIELD2 => 'CustomField',
);
$self->SUPER::Limit(
- LEFTJOIN => $TicketCFs,
+ LEFTJOIN => $ObjectCFs,
FIELD => 'ObjectId',
VALUE => 'main.id',
QUOTEVALUE => 0,
@@ -1441,20 +1441,20 @@ sub _CustomFieldJoin {
);
}
$self->SUPER::Limit(
- LEFTJOIN => $TicketCFs,
+ LEFTJOIN => $ObjectCFs,
FIELD => 'ObjectType',
VALUE => 'RT::Ticket',
ENTRYAGGREGATOR => 'AND'
);
$self->SUPER::Limit(
- LEFTJOIN => $TicketCFs,
+ LEFTJOIN => $ObjectCFs,
FIELD => 'Disabled',
OPERATOR => '=',
VALUE => '0',
ENTRYAGGREGATOR => 'AND'
);
- return ($TicketCFs, $CFs);
+ return ($ObjectCFs, $CFs);
}
=head2 _CustomFieldLimit
@@ -1580,10 +1580,10 @@ sub _CustomFieldLimit {
# IS[ NOT] NULL without column is the same as has[ no] any CF value,
# we can reuse our default joins for this operation
# with column specified we have different situation
- my ($TicketCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field );
+ my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field );
$self->_OpenParen;
$self->_SQLLimit(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'id',
OPERATOR => $op,
VALUE => $value,
@@ -1643,7 +1643,7 @@ sub _CustomFieldLimit {
}
elsif ( !$negative_op || $single_value ) {
$cfkey .= '.'. $self->{'_sql_multiple_cfs_index'}++ if !$single_value && !$range_op;
- my ($TicketCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field );
+ my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field );
$self->_OpenParen;
@@ -1654,7 +1654,7 @@ sub _CustomFieldLimit {
# otherwise search in Content and in LargeContent
if ( $column ) {
$self->_SQLLimit( $fix_op->(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => $column,
OPERATOR => $op,
VALUE => $value,
@@ -1680,7 +1680,7 @@ sub _CustomFieldLimit {
$self->_OpenParen;
$self->_SQLLimit(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'Content',
OPERATOR => ">=",
VALUE => $daystart,
@@ -1688,7 +1688,7 @@ sub _CustomFieldLimit {
);
$self->_SQLLimit(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'Content',
OPERATOR => "<",
VALUE => $dayend,
@@ -1701,7 +1701,7 @@ sub _CustomFieldLimit {
elsif ( $op eq '=' || $op eq '!=' || $op eq '<>' ) {
if ( length( Encode::encode_utf8($value) ) < 256 ) {
$self->_SQLLimit(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'Content',
OPERATOR => $op,
VALUE => $value,
@@ -1712,14 +1712,14 @@ sub _CustomFieldLimit {
else {
$self->_OpenParen;
$self->_SQLLimit(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'Content',
OPERATOR => '=',
VALUE => '',
ENTRYAGGREGATOR => 'OR'
);
$self->_SQLLimit(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'Content',
OPERATOR => 'IS',
VALUE => 'NULL',
@@ -1727,7 +1727,7 @@ sub _CustomFieldLimit {
);
$self->_CloseParen;
$self->_SQLLimit( $fix_op->(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'LargeContent',
OPERATOR => $op,
VALUE => $value,
@@ -1738,7 +1738,7 @@ sub _CustomFieldLimit {
}
else {
$self->_SQLLimit(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'Content',
OPERATOR => $op,
VALUE => $value,
@@ -1749,14 +1749,14 @@ sub _CustomFieldLimit {
$self->_OpenParen;
$self->_OpenParen;
$self->_SQLLimit(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'Content',
OPERATOR => '=',
VALUE => '',
ENTRYAGGREGATOR => 'OR'
);
$self->_SQLLimit(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'Content',
OPERATOR => 'IS',
VALUE => 'NULL',
@@ -1764,7 +1764,7 @@ sub _CustomFieldLimit {
);
$self->_CloseParen;
$self->_SQLLimit( $fix_op->(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'LargeContent',
OPERATOR => $op,
VALUE => $value,
@@ -1798,7 +1798,7 @@ sub _CustomFieldLimit {
if ($negative_op) {
$self->_SQLLimit(
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => $column || 'Content',
OPERATOR => 'IS',
VALUE => 'NULL',
@@ -1812,7 +1812,7 @@ sub _CustomFieldLimit {
}
else {
$cfkey .= '.'. $self->{'_sql_multiple_cfs_index'}++;
- my ($TicketCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field );
+ my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field );
# reverse operation
$op =~ s/!|NOT\s+//i;
@@ -1821,8 +1821,8 @@ sub _CustomFieldLimit {
# otherwise search in Content and in LargeContent
if ( $column ) {
$self->SUPER::Limit( $fix_op->(
- LEFTJOIN => $TicketCFs,
- ALIAS => $TicketCFs,
+ LEFTJOIN => $ObjectCFs,
+ ALIAS => $ObjectCFs,
FIELD => $column,
OPERATOR => $op,
VALUE => $value,
@@ -1831,8 +1831,8 @@ sub _CustomFieldLimit {
}
else {
$self->SUPER::Limit(
- LEFTJOIN => $TicketCFs,
- ALIAS => $TicketCFs,
+ LEFTJOIN => $ObjectCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'Content',
OPERATOR => $op,
VALUE => $value,
@@ -1841,7 +1841,7 @@ sub _CustomFieldLimit {
}
$self->_SQLLimit(
%rest,
- ALIAS => $TicketCFs,
+ ALIAS => $ObjectCFs,
FIELD => 'id',
OPERATOR => 'IS',
VALUE => 'NULL',
@@ -1955,7 +1955,7 @@ sub OrderByCols {
my ($queue, $field, $cf_obj, $column) = $self->_CustomFieldDecipher( $subkey );
my $cfkey = $cf_obj ? $cf_obj->id : "$queue.$field";
$cfkey .= ".ordering" if !$cf_obj || ($cf_obj->MaxValues||0) != 1;
- my ($TicketCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, ($cf_obj ?$cf_obj->id :0) , $field );
+ my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, ($cf_obj ?$cf_obj->id :0) , $field );
# this is described in _CustomFieldLimit
$self->_SQLLimit(
ALIAS => $CFs,
@@ -1977,7 +1977,7 @@ sub OrderByCols {
}
my $CFvs = $self->Join(
TYPE => 'LEFT',
- ALIAS1 => $TicketCFs,
+ ALIAS1 => $ObjectCFs,
FIELD1 => 'CustomField',
TABLE2 => 'CustomFieldValues',
FIELD2 => 'CustomField',
@@ -1986,12 +1986,12 @@ sub OrderByCols {
LEFTJOIN => $CFvs,
FIELD => 'Name',
QUOTEVALUE => 0,
- VALUE => $TicketCFs . ".Content",
+ VALUE => $ObjectCFs . ".Content",
ENTRYAGGREGATOR => 'AND'
);
push @res, { %$row, ALIAS => $CFvs, FIELD => 'SortOrder' };
- push @res, { %$row, ALIAS => $TicketCFs, FIELD => 'Content' };
+ push @res, { %$row, ALIAS => $ObjectCFs, FIELD => 'Content' };
} elsif ( $field eq "Custom" && $subkey eq "Ownership") {
# PAW logic is "reversed"
my $order = "ASC";
commit 05840351010103a861e883a76ff863bb1cfb3ae3
Author: Thomas Sibley <trs at bestpractical.com>
Date: Thu Jun 27 15:25:46 2013 -0700
Decipher TicketSQL CF identifiers using a passed in LookupType
The LookupType is necessary to find the correct CF by name, as well as
to support the arcane CF.ObjectId.{CFName} syntax, for arbitrary object
types (not just ticket CFs on RT::Queue).
Potential syntax made possible, for example:
TxnCF.{CFName}
TxnCF.Queue.{CFName}
ArticleCF.Class.{CFName}
The CF lookup behaviour of CF.Queue.{CFName} changes slightly due to
changes in which custom fields API is used. Most notably, such syntax
previously exhibited the following behaviour but no longer does:
⢠CF names were searched case insensitively.
⢠Disabled CFs could be found if no enabled CFs matched.
⢠The existence of multiple matching CFs with the same name (& within
the same queue) was ignored; the first was the only one used.
As CF.Queue.{CFName} is fairly arcane syntax, these changes shouldn't
affect most usage of TicketSQL. It is unlikely that anyone using the
extended syntax is intentionally relying on any of the discontinued
behaviour noted above.
diff --git a/lib/RT/Tickets.pm b/lib/RT/Tickets.pm
index 679186b..102b38d 100644
--- a/lib/RT/Tickets.pm
+++ b/lib/RT/Tickets.pm
@@ -1314,33 +1314,49 @@ sub _WatcherMembershipLimit {
Try and turn a CF descriptor into (cfid, cfname) object pair.
+Takes an optional second parameter of the CF LookupType, defaults to Ticket CFs.
+
=cut
sub _CustomFieldDecipher {
- my ($self, $string) = @_;
+ my ($self, $string, $lookuptype) = @_;
+ $lookuptype ||= $self->_SingularClass->CustomFieldLookupType;
- my ($queue, $field, $column) = ($string =~ /^(?:(.+?)\.)?{(.+)}(?:\.(Content|LargeContent))?$/);
+ my ($object, $field, $column) = ($string =~ /^(?:(.+?)\.)?{(.+)}(?:\.(Content|LargeContent))?$/);
$field ||= ($string =~ /^{(.*?)}$/)[0] || $string;
- my $cf;
- if ( $queue ) {
- my $q = RT::Queue->new( $self->CurrentUser );
- $q->Load( $queue );
+ my ($cf, $applied_to);
+
+ if ( $object ) {
+ my $record_class = RT::CustomField->RecordClassFromLookupType($lookuptype);
+ $applied_to = $record_class->new( $self->CurrentUser );
+ $applied_to->Load( $object );
- if ( $q->id ) {
- # $queue = $q->Name; # should we normalize the queue?
- $cf = $q->CustomField( $field );
+ if ( $applied_to->id ) {
+ RT->Logger->debug("Limiting to CFs identified by '$field' applied to $record_class #@{[$applied_to->id]} (loaded via '$object')");
}
else {
- $RT::Logger->warning("Queue '$queue' doesn't exist, parsed from '$string'");
- $queue = 0;
+ RT->Logger->warning("$record_class '$object' doesn't exist, parsed from '$string'");
+ $object = 0;
+ undef $applied_to;
}
}
- elsif ( $field =~ /\D/ ) {
- $queue = '';
+
+ if ( $field =~ /\D/ ) {
+ $object ||= '';
my $cfs = RT::CustomFields->new( $self->CurrentUser );
$cfs->Limit( FIELD => 'Name', VALUE => $field );
- $cfs->LimitToLookupType('RT::Queue-RT::Ticket');
+ $cfs->LimitToLookupType($lookuptype);
+ # XXX Compare to RT::CustomField::LoadByNameAndQueue, previously used
+ # when a specific applied to object (queue) was specified.
+ # - Explicit case insensitivity
+ # - Disabled OK
+ # - No duplicate check
+
+ if ($applied_to) {
+ $cfs->SetContextObject($applied_to);
+ $cfs->LimitToObjectId($applied_to->id);
+ }
# if there is more then one field the current user can
# see with the same name then we shouldn't return cf object
@@ -1353,9 +1369,11 @@ sub _CustomFieldDecipher {
else {
$cf = RT::CustomField->new( $self->CurrentUser );
$cf->Load( $field );
+ $cf->SetContextObject($applied_to)
+ if $cf->id and $applied_to;
}
- return ($queue, $field, $cf, $column);
+ return ($object, $field, $cf, $column);
}
=head2 _CustomFieldJoin
@@ -1477,8 +1495,8 @@ sub _CustomFieldLimit {
# For our sanity, we can only limit on one queue at a time
- my ($queue, $cfid, $cf, $column);
- ($queue, $field, $cf, $column) = $self->_CustomFieldDecipher( $field );
+ my ($object, $cfid, $cf, $column);
+ ($object, $field, $cf, $column) = $self->_CustomFieldDecipher( $field );
$cfid = $cf ? $cf->id : 0 ;
# If we're trying to find custom fields that don't match something, we
@@ -1574,7 +1592,7 @@ sub _CustomFieldLimit {
my $single_value = !$cf || !$cfid || $cf->SingleValue;
- my $cfkey = $cfid ? $cfid : "$queue.$field";
+ my $cfkey = $cfid ? $cfid : "$object.$field";
if ( $null_op && !$column ) {
# IS[ NOT] NULL without column is the same as has[ no] any CF value,
@@ -1952,8 +1970,8 @@ sub OrderByCols {
}
push @res, { %$row, ALIAS => $users, FIELD => $subkey };
} elsif ( defined $meta->[0] && $meta->[0] eq 'CUSTOMFIELD' ) {
- my ($queue, $field, $cf_obj, $column) = $self->_CustomFieldDecipher( $subkey );
- my $cfkey = $cf_obj ? $cf_obj->id : "$queue.$field";
+ my ($object, $field, $cf_obj, $column) = $self->_CustomFieldDecipher( $subkey );
+ my $cfkey = $cf_obj ? $cf_obj->id : "$object.$field";
$cfkey .= ".ordering" if !$cf_obj || ($cf_obj->MaxValues||0) != 1;
my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, ($cf_obj ?$cf_obj->id :0) , $field );
# this is described in _CustomFieldLimit
commit 333337eb7269ed0e3dbc348c6a7e251a45a9bef4
Author: Thomas Sibley <trs at bestpractical.com>
Date: Wed Jun 26 16:47:43 2013 -0700
Refactor _CustomFieldJoin to take a LookupType
⦠so that we can join to the correct table if not Tickets. An
extensible data structure is introduced to determine how to join CFs to
applied objects.
This lets _CustomFieldJoin handle joining for transaction CFs or other
CFs which may want to be searched.
diff --git a/lib/RT/Tickets.pm b/lib/RT/Tickets.pm
index 102b38d..709f985 100644
--- a/lib/RT/Tickets.pm
+++ b/lib/RT/Tickets.pm
@@ -1382,8 +1382,14 @@ Factor out the Join of custom fields so we can use it for sorting too
=cut
+our %JOIN_ALIAS_FOR_LOOKUP_TYPE = (
+ RT::Ticket->CustomFieldLookupType => sub { "main" },
+);
+
sub _CustomFieldJoin {
- my ($self, $cfkey, $cfid, $field) = @_;
+ my ($self, $cfkey, $cfid, $field, $type) = @_;
+ $type ||= RT::Ticket->CustomFieldLookupType;
+
# Perform one Join per CustomField
if ( $self->{_sql_object_cfv_alias}{$cfkey} ||
$self->{_sql_cf_alias}{$cfkey} )
@@ -1392,11 +1398,15 @@ sub _CustomFieldJoin {
$self->{_sql_cf_alias}{$cfkey} );
}
+ my $ObjectAlias = $JOIN_ALIAS_FOR_LOOKUP_TYPE{$type}
+ ? $JOIN_ALIAS_FOR_LOOKUP_TYPE{$type}->($self)
+ : die "We don't know how to join on $type";
+
my ($ObjectCFs, $CFs);
if ( $cfid ) {
$ObjectCFs = $self->{_sql_object_cfv_alias}{$cfkey} = $self->Join(
TYPE => 'LEFT',
- ALIAS1 => 'main',
+ ALIAS1 => $ObjectAlias,
FIELD1 => 'id',
TABLE2 => 'ObjectCustomFieldValues',
FIELD2 => 'ObjectId',
@@ -1434,7 +1444,7 @@ sub _CustomFieldJoin {
LEFTJOIN => $CFs,
ENTRYAGGREGATOR => 'AND',
FIELD => 'LookupType',
- VALUE => 'RT::Queue-RT::Ticket',
+ VALUE => $type,
);
$self->SUPER::Limit(
LEFTJOIN => $CFs,
@@ -1453,15 +1463,16 @@ sub _CustomFieldJoin {
$self->SUPER::Limit(
LEFTJOIN => $ObjectCFs,
FIELD => 'ObjectId',
- VALUE => 'main.id',
+ VALUE => "$ObjectAlias.id",
QUOTEVALUE => 0,
ENTRYAGGREGATOR => 'AND',
);
}
+
$self->SUPER::Limit(
LEFTJOIN => $ObjectCFs,
FIELD => 'ObjectType',
- VALUE => 'RT::Ticket',
+ VALUE => RT::CustomField->ObjectTypeFromLookupType($type),
ENTRYAGGREGATOR => 'AND'
);
$self->SUPER::Limit(
commit bc1ae7c681ea8d979a49ecfcd1ec7edf591014db
Author: Thomas Sibley <trs at bestpractical.com>
Date: Thu Jun 27 15:50:34 2013 -0700
Refactor _CustomFieldLimit to use a LookupType in %FIELD_METADATA
Potential new search clauses, such as searching transaction CFs, want to
match all the different ways that ticket CFs can. It makes sense to
just wrap the limits in a LookupType change (especially since
_CustomFieldLimit happens to be recursive for IP and Date searches).
diff --git a/lib/RT/Tickets.pm b/lib/RT/Tickets.pm
index 709f985..5855798 100644
--- a/lib/RT/Tickets.pm
+++ b/lib/RT/Tickets.pm
@@ -142,9 +142,9 @@ our %FIELD_METADATA = (
QueueCc => [ 'WATCHERFIELD' => 'Cc' => 'Queue', ], #loc_left_pair
QueueAdminCc => [ 'WATCHERFIELD' => 'AdminCc' => 'Queue', ], #loc_left_pair
QueueWatcher => [ 'WATCHERFIELD' => undef => 'Queue', ], #loc_left_pair
- CustomFieldValue => [ 'CUSTOMFIELD', ], #loc_left_pair
- CustomField => [ 'CUSTOMFIELD', ], #loc_left_pair
- CF => [ 'CUSTOMFIELD', ], #loc_left_pair
+ CustomFieldValue => [ 'CUSTOMFIELD' => 'Ticket' ], #loc_left_pair
+ CustomField => [ 'CUSTOMFIELD' => 'Ticket' ], #loc_left_pair
+ CF => [ 'CUSTOMFIELD' => 'Ticket' ], #loc_left_pair
Updated => [ 'TRANSDATE', ], #loc_left_pair
RequestorGroup => [ 'MEMBERSHIPFIELD' => 'Requestor', ], #loc_left_pair
CCGroup => [ 'MEMBERSHIPFIELD' => 'Cc', ], #loc_left_pair
@@ -1502,12 +1502,16 @@ use Regexp::Common::net::CIDR;
sub _CustomFieldLimit {
my ( $self, $_field, $op, $value, %rest ) = @_;
+ my $meta = $FIELD_METADATA{ $_field };
+ my $class = $meta->[1] || 'Ticket';
+ my $type = "RT::$class"->CustomFieldLookupType;
+
my $field = $rest{'SUBKEY'} || die "No field specified";
# For our sanity, we can only limit on one queue at a time
my ($object, $cfid, $cf, $column);
- ($object, $field, $cf, $column) = $self->_CustomFieldDecipher( $field );
+ ($object, $field, $cf, $column) = $self->_CustomFieldDecipher( $field, $type );
$cfid = $cf ? $cf->id : 0 ;
# If we're trying to find custom fields that don't match something, we
@@ -1603,13 +1607,13 @@ sub _CustomFieldLimit {
my $single_value = !$cf || !$cfid || $cf->SingleValue;
- my $cfkey = $cfid ? $cfid : "$object.$field";
+ my $cfkey = $cfid ? $cfid : "$type-$object.$field";
if ( $null_op && !$column ) {
# IS[ NOT] NULL without column is the same as has[ no] any CF value,
# we can reuse our default joins for this operation
# with column specified we have different situation
- my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field );
+ my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field, $type );
$self->_OpenParen;
$self->_SQLLimit(
ALIAS => $ObjectCFs,
@@ -1635,11 +1639,11 @@ sub _CustomFieldLimit {
$self->_OpenParen;
if ( $op !~ /NOT|!=|<>/i ) { # positive equation
$self->_CustomFieldLimit(
- 'CF', '<=', $end_ip, %rest,
+ $_field, '<=', $end_ip, $type, %rest,
SUBKEY => $rest{'SUBKEY'}. '.Content',
);
$self->_CustomFieldLimit(
- 'CF', '>=', $start_ip, %rest,
+ $_field, '>=', $start_ip, $type, %rest,
SUBKEY => $rest{'SUBKEY'}. '.LargeContent',
ENTRYAGGREGATOR => 'AND',
);
@@ -1647,20 +1651,20 @@ sub _CustomFieldLimit {
# estimations and scan less rows
# have to disable this tweak because of ipv6
# $self->_CustomFieldLimit(
-# $field, '>=', '000.000.000.000', %rest,
+# $_field, '>=', '000.000.000.000', $type, %rest,
# SUBKEY => $rest{'SUBKEY'}. '.Content',
# ENTRYAGGREGATOR => 'AND',
# );
# $self->_CustomFieldLimit(
-# $field, '<=', '255.255.255.255', %rest,
+# $_field, '<=', '255.255.255.255', $type, %rest,
# SUBKEY => $rest{'SUBKEY'}. '.LargeContent',
# ENTRYAGGREGATOR => 'AND',
# );
}
else { # negative equation
- $self->_CustomFieldLimit($field, '>', $end_ip, %rest);
+ $self->_CustomFieldLimit($_field, '>', $end_ip, $type, %rest);
$self->_CustomFieldLimit(
- $field, '<', $start_ip, %rest,
+ $_field, '<', $start_ip, $type, %rest,
SUBKEY => $rest{'SUBKEY'}. '.LargeContent',
ENTRYAGGREGATOR => 'OR',
);
@@ -1672,7 +1676,7 @@ sub _CustomFieldLimit {
}
elsif ( !$negative_op || $single_value ) {
$cfkey .= '.'. $self->{'_sql_multiple_cfs_index'}++ if !$single_value && !$range_op;
- my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field );
+ my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field, $type );
$self->_OpenParen;
@@ -1841,7 +1845,7 @@ sub _CustomFieldLimit {
}
else {
$cfkey .= '.'. $self->{'_sql_multiple_cfs_index'}++;
- my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field );
+ my ($ObjectCFs, $CFs) = $self->_CustomFieldJoin( $cfkey, $cfid, $field, $type );
# reverse operation
$op =~ s/!|NOT\s+//i;
commit e55a3a03cdafc82fd25508262bd5548ebaadfdce
Author: Thomas Sibley <trs at bestpractical.com>
Date: Thu Jun 27 16:40:57 2013 -0700
Fix horrendous load order of shredder tests
They started failing because of an added
RT::Ticket->CustomFieldLookupType call.
The RT::Ticket load order is also awful and doesn't setup it's base
class until very late, including after importing other packages.
diff --git a/t/shredder/utils.pl b/t/shredder/utils.pl
index 7be9513..d5a0589 100644
--- a/t/shredder/utils.pl
+++ b/t/shredder/utils.pl
@@ -8,8 +8,14 @@ require RT::Test;
BEGIN {
### after: push @INC, qw(@RT_LIB_PATH@);
+
+ use RT;
+ RT->LoadConfig;
+ RT->InitPluginPaths;
+ RT->InitClasses;
}
-use RT::Shredder;
+
+require RT::Shredder;
=head1 DESCRIPTION
commit d5a2a7c6fc149675027e0af2abf46d44657530a3
Author: Thomas Sibley <trs at bestpractical.com>
Date: Fri Jun 28 10:10:49 2013 -0700
Add callbacks for before and after the query builder criteria picker
diff --git a/share/html/Search/Elements/PickCriteria b/share/html/Search/Elements/PickCriteria
index 7d8a4e9..a15a21a 100644
--- a/share/html/Search/Elements/PickCriteria
+++ b/share/html/Search/Elements/PickCriteria
@@ -50,9 +50,10 @@
<table width="100%" cellspacing="0" cellpadding="0" border="0">
-
+% $m->callback( %ARGS, CallbackName => "BeforeBasics" );
<& PickBasics, queues => \%queues &>
<& PickCFs, queues => \%queues &>
+% $m->callback( %ARGS, CallbackName => "AfterCFs" );
<tr class="separator"><td colspan="3"><hr /></td></tr>
<tr>
commit c18cf91ff6817e31e48b09bd649d04e13a518294
Author: Thomas Sibley <trs at bestpractical.com>
Date: Fri Jun 28 10:11:38 2013 -0700
PickTicketCFs refactored from the now-generic PickCFs
PickCFs may now be used for other types of CFs. Callback semantics
remain the same, so no extension using the callbacks in PickCFs will be
broken.
diff --git a/share/html/Search/Elements/PickCFs b/share/html/Search/Elements/PickCFs
index 5d16b9c..9765603 100644
--- a/share/html/Search/Elements/PickCFs
+++ b/share/html/Search/Elements/PickCFs
@@ -49,14 +49,6 @@
<& ConditionRow, Condition => $_ &>
% }
<%INIT>
-my $CustomFields = RT::CustomFields->new( $session{'CurrentUser'});
-foreach my $id (keys %queues) {
- # Gotta load up the $queue object, since queues get stored by name now.
- my $queue = RT::Queue->new($session{'CurrentUser'});
- $queue->Load($id);
- $CustomFields->LimitToQueue($queue->Id) if $queue->Id;
-}
-$CustomFields->LimitToGlobal;
$m->callback(
CallbackName => 'MassageCustomFields',
CustomFields => $CustomFields,
@@ -66,7 +58,7 @@ $m->callback(
my @lines;
while ( my $CustomField = $CustomFields->Next ) {
my %line;
- $line{'Name'} = "'CF.{" . $CustomField->Name . "}'";
+ $line{'Name'} = "'$TicketSQLField.{" . $CustomField->Name . "}'";
$line{'Field'} = $CustomField->Name;
# Op
@@ -120,4 +112,6 @@ $m->callback( Conditions => \@lines, Queues => \%queues );
<%ARGS>
%queues => ()
+$CustomFields
+$TicketSQLField => 'CF'
</%ARGS>
diff --git a/share/html/Search/Elements/PickCriteria b/share/html/Search/Elements/PickCriteria
index a15a21a..485fceb 100644
--- a/share/html/Search/Elements/PickCriteria
+++ b/share/html/Search/Elements/PickCriteria
@@ -52,7 +52,7 @@
% $m->callback( %ARGS, CallbackName => "BeforeBasics" );
<& PickBasics, queues => \%queues &>
-<& PickCFs, queues => \%queues &>
+<& PickTicketCFs, queues => \%queues &>
% $m->callback( %ARGS, CallbackName => "AfterCFs" );
<tr class="separator"><td colspan="3"><hr /></td></tr>
diff --git a/share/html/Search/Elements/PickTicketCFs b/share/html/Search/Elements/PickTicketCFs
new file mode 100644
index 0000000..17a62b4
--- /dev/null
+++ b/share/html/Search/Elements/PickTicketCFs
@@ -0,0 +1,14 @@
+<%ARGS>
+%queues => ()
+</%ARGS>
+<%init>
+my $CustomFields = RT::CustomFields->new( $session{'CurrentUser'});
+foreach my $id (keys %queues) {
+ # Gotta load up the $queue object, since queues get stored by name now.
+ my $queue = RT::Queue->new($session{'CurrentUser'});
+ $queue->Load($id);
+ $CustomFields->LimitToQueue($queue->Id) if $queue->Id;
+}
+$CustomFields->LimitToGlobal;
+</%init>
+<& PickCFs, %ARGS, TicketSQLField => 'CF', CustomFields => $CustomFields &>
commit 628aabaeba4741dbc0897be6e4d878d7eabf10b8
Author: Thomas Sibley <trs at bestpractical.com>
Date: Fri Jun 28 12:14:27 2013 -0700
Parse FooCF.{Bar} when adding a TicketSQL clause in the Query Builder
Extends the parsing from a strict CF.{â¦} to SomeOptionalWordCF.{â¦}
In an ideal world we programmatically build up what's recognized from a
data structure like %RT::Tickets::FIELD_METADATA, but that requires more
refactoring than we're up for in a stable series.
diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index e377622..40b45d4 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -190,7 +190,7 @@ my @new_values = ();
# Try to find if we're adding a clause
foreach my $arg ( keys %ARGS ) {
- next unless $arg =~ m/^ValueOf(\w+|'CF.{.*?}')$/
+ next unless $arg =~ m/^ValueOf(\w+|'\w*CF\.\{.*?\}')$/
&& ( ref $ARGS{$arg} eq "ARRAY"
? grep $_ ne '', @{ $ARGS{$arg} }
: $ARGS{$arg} ne '' );
@@ -234,10 +234,10 @@ foreach my $arg ( keys %ARGS ) {
$value = "'$value'";
}
- if ($keyword =~ /^'CF\.{(.*)}'/) {
- my $cf = $1;
+ if ($keyword =~ /^'(\w*CF)\.\{(.*)\}'/) {
+ my ($field, $cf) = ($1, $2);
$cf =~ s/(['\\])/\\$1/g;
- $keyword = "'CF.{$cf}'";
+ $keyword = "'$field.{$cf}'";
}
my $clause = {
-----------------------------------------------------------------------
More information about the Rt-commit
mailing list