[Bps-public-commit] RTx-TicketSQL-TransactionCFs branch, master, updated. v20130628-2-g7f7cf85
Thomas Sibley
trs at bestpractical.com
Mon Jul 15 14:08:36 EDT 2013
The branch, master has been updated
via 7f7cf853a74dab92c4ef29e4c23b033006de3f4d (commit)
from df722e2b4dac85df86246536263ab8c1729d6e04 (commit)
Summary of changes:
patches/rt-4.0.13.patch | 1130 -----------------------------------------------
1 file changed, 1130 deletions(-)
delete mode 100644 patches/rt-4.0.13.patch
- Log -----------------------------------------------------------------
commit 7f7cf853a74dab92c4ef29e4c23b033006de3f4d
Author: Thomas Sibley <trs at bestpractical.com>
Date: Mon Jul 15 11:07:53 2013 -0700
4.0.14 will include these changes, so just require 4.0.14
diff --git a/patches/rt-4.0.13.patch b/patches/rt-4.0.13.patch
deleted file mode 100644
index c7495c2..0000000
--- a/patches/rt-4.0.13.patch
+++ /dev/null
@@ -1,1130 +0,0 @@
-From e37801b72138e97fd23ad9e2a6e95d8ef96032d5 Mon Sep 17 00:00:00 2001
-From: Thomas Sibley <trs at bestpractical.com>
-Date: Wed, 6 Feb 2013 17:25:22 -0800
-Subject: [PATCH 01/12] Allow CustomFieldLookupType to be called as a class
- method
-
-(cherry picked from commit 1ff3f2b0a97d1e336ced7542ce2b0201ff5309fc)
----
- lib/RT/Record.pm | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/lib/RT/Record.pm b/lib/RT/Record.pm
-index a58979e..9e44639 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;
- }
-
-
---
-1.8.3.1
-
-
-From 7e5b1ccb0955d8c730d99a6a14b6cc05ec4b6960 Mon Sep 17 00:00:00 2001
-From: Kevin Falcone <falcone at bestpractical.com>
-Date: Mon, 30 Jan 2012 17:27:49 -0500
-Subject: [PATCH 02/12] 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.
----
- lib/RT/CustomField.pm | 27 ++++++++++++++++++++++++++-
- 1 file changed, 26 insertions(+), 1 deletion(-)
-
-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;
---
-1.8.3.1
-
-
-From 5088509209ccc5ecdfe9e905959c3f4b096cb5ae Mon Sep 17 00:00:00 2001
-From: Thomas Sibley <trs at bestpractical.com>
-Date: Wed, 26 Jun 2013 16:06:31 -0700
-Subject: [PATCH 03/12] ObjectType/RecordTypeFromLookupType as class methods
-
-Where LookupType must be passed as an argument.
----
- lib/RT/CustomField.pm | 40 +++++++++++++++++++++++++++++-----------
- 1 file changed, 29 insertions(+), 11 deletions(-)
-
-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;
---
-1.8.3.1
-
-
-From f0ea5922e8c14114e3d1698f526634acff567dff Mon Sep 17 00:00:00 2001
-From: Thomas Sibley <trs at bestpractical.com>
-Date: Wed, 26 Jun 2013 22:56:11 -0700
-Subject: [PATCH 04/12] Refactor part of LimitToGlobalOrObjectId into
- LimitToObjectId
-
-Useful when you only want to find CFs applied to a certain object and
-not global ones too.
----
- lib/RT/CustomFields.pm | 33 ++++++++++++++++++++++-----------
- 1 file changed, 22 insertions(+), 11 deletions(-)
-
-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 {
---
-1.8.3.1
-
-
-From a9ae79a1ee31dff81b9712493da1cf9bbd39f488 Mon Sep 17 00:00:00 2001
-From: Kevin Falcone <falcone at bestpractical.com>
-Date: Mon, 30 Jan 2012 17:31:47 -0500
-Subject: [PATCH 05/12] 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
----
- lib/RT/Tickets.pm | 66 +++++++++++++++++++++++++++----------------------------
- 1 file changed, 33 insertions(+), 33 deletions(-)
-
-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";
---
-1.8.3.1
-
-
-From eb7dff164d3a37da0da73ca414c37fb91f42c4ba Mon Sep 17 00:00:00 2001
-From: Thomas Sibley <trs at bestpractical.com>
-Date: Thu, 27 Jun 2013 15:25:46 -0700
-Subject: [PATCH 06/12] Decipher TicketSQL CF identifiers using a passed in
- LookupType
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-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:
-
- ⢠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. Disabled CFs, even if found, are eliminated from
-results by later code. The two behaviour changes are effectively bug
-fixes.
-
-A case-sensitivity difference between CF.{Name} and CF.Queue.{Name} is
-preserved by checking which syntax was used. This is bending over
-backwards solely for the sake of compatibility within the 4.0 series.
-It is conceivable that someone is relying on it, knowingly or not, and
-it is easy enough to replicate. In 4.2, we should remove this
-distinction.
----
- lib/RT/Tickets.pm | 55 ++++++++++++++++++++++++++++++++++---------------------
- 1 file changed, 34 insertions(+), 21 deletions(-)
-
-diff --git a/lib/RT/Tickets.pm b/lib/RT/Tickets.pm
-index 679186b..3ef735c 100644
---- a/lib/RT/Tickets.pm
-+++ b/lib/RT/Tickets.pm
-@@ -1314,33 +1314,44 @@ 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->Limit( FIELD => 'Name', VALUE => $field, ($applied_to ? (CASESENSITIVE => 0) : ()) );
-+ $cfs->LimitToLookupType($lookuptype);
-+
-+ 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 +1364,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 +1490,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 +1587,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 +1965,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
---
-1.8.3.1
-
-
-From d39521de41ec430ddcaab92f7efbad0d93de77ac Mon Sep 17 00:00:00 2001
-From: Thomas Sibley <trs at bestpractical.com>
-Date: Wed, 26 Jun 2013 16:47:43 -0700
-Subject: [PATCH 07/12] Refactor _CustomFieldJoin to take a LookupType
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-⦠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.
----
- lib/RT/Tickets.pm | 21 ++++++++++++++++-----
- 1 file changed, 16 insertions(+), 5 deletions(-)
-
-diff --git a/lib/RT/Tickets.pm b/lib/RT/Tickets.pm
-index 3ef735c..0afe20b 100644
---- a/lib/RT/Tickets.pm
-+++ b/lib/RT/Tickets.pm
-@@ -1377,8 +1377,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} )
-@@ -1387,11 +1393,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',
-@@ -1429,7 +1439,7 @@ sub _CustomFieldJoin {
- LEFTJOIN => $CFs,
- ENTRYAGGREGATOR => 'AND',
- FIELD => 'LookupType',
-- VALUE => 'RT::Queue-RT::Ticket',
-+ VALUE => $type,
- );
- $self->SUPER::Limit(
- LEFTJOIN => $CFs,
-@@ -1448,15 +1458,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(
---
-1.8.3.1
-
-
-From daf0a6c18f1ef822349e1d89d12be827b356d02e Mon Sep 17 00:00:00 2001
-From: Thomas Sibley <trs at bestpractical.com>
-Date: Thu, 27 Jun 2013 15:50:34 -0700
-Subject: [PATCH 08/12] 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).
----
- lib/RT/Tickets.pm | 32 ++++++++++++++++++--------------
- 1 file changed, 18 insertions(+), 14 deletions(-)
-
-diff --git a/lib/RT/Tickets.pm b/lib/RT/Tickets.pm
-index 0afe20b..b2480b0 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
-@@ -1497,12 +1497,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
-@@ -1598,13 +1602,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,
-@@ -1630,11 +1634,11 @@ sub _CustomFieldLimit {
- $self->_OpenParen;
- if ( $op !~ /NOT|!=|<>/i ) { # positive equation
- $self->_CustomFieldLimit(
-- 'CF', '<=', $end_ip, %rest,
-+ $_field, '<=', $end_ip, %rest,
- SUBKEY => $rest{'SUBKEY'}. '.Content',
- );
- $self->_CustomFieldLimit(
-- 'CF', '>=', $start_ip, %rest,
-+ $_field, '>=', $start_ip, %rest,
- SUBKEY => $rest{'SUBKEY'}. '.LargeContent',
- ENTRYAGGREGATOR => 'AND',
- );
-@@ -1642,20 +1646,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', %rest,
- # SUBKEY => $rest{'SUBKEY'}. '.Content',
- # ENTRYAGGREGATOR => 'AND',
- # );
- # $self->_CustomFieldLimit(
--# $field, '<=', '255.255.255.255', %rest,
-+# $_field, '<=', '255.255.255.255', %rest,
- # SUBKEY => $rest{'SUBKEY'}. '.LargeContent',
- # ENTRYAGGREGATOR => 'AND',
- # );
- }
- else { # negative equation
-- $self->_CustomFieldLimit($field, '>', $end_ip, %rest);
-+ $self->_CustomFieldLimit($_field, '>', $end_ip, %rest);
- $self->_CustomFieldLimit(
-- $field, '<', $start_ip, %rest,
-+ $_field, '<', $start_ip, %rest,
- SUBKEY => $rest{'SUBKEY'}. '.LargeContent',
- ENTRYAGGREGATOR => 'OR',
- );
-@@ -1667,7 +1671,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;
-
-@@ -1836,7 +1840,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;
---
-1.8.3.1
-
-
-From be665348b78679d0a31900afb788517f9a10fda6 Mon Sep 17 00:00:00 2001
-From: Thomas Sibley <trs at bestpractical.com>
-Date: Thu, 27 Jun 2013 16:40:57 -0700
-Subject: [PATCH 09/12] 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.
----
- t/shredder/utils.pl | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
-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
-
---
-1.8.3.1
-
-
-From 94aeca9f47f7923b8fe82c02e02d7f9e892716a7 Mon Sep 17 00:00:00 2001
-From: Thomas Sibley <trs at bestpractical.com>
-Date: Fri, 28 Jun 2013 10:10:49 -0700
-Subject: [PATCH 10/12] Add callbacks for before and after the query builder
- criteria picker
-
----
- share/html/Search/Elements/PickCriteria | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-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>
---
-1.8.3.1
-
-
-From 565b40eaf184d846c20da315b5247fd7c86c2e17 Mon Sep 17 00:00:00 2001
-From: Thomas Sibley <trs at bestpractical.com>
-Date: Fri, 28 Jun 2013 10:11:38 -0700
-Subject: [PATCH 11/12] 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.
----
- share/html/Search/Elements/PickCFs | 12 ++------
- share/html/Search/Elements/PickCriteria | 2 +-
- .../Elements/{PickCriteria => PickTicketCFs} | 34 +++++++---------------
- 3 files changed, 15 insertions(+), 33 deletions(-)
- copy share/html/Search/Elements/{PickCriteria => PickTicketCFs} (79%)
-
-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/PickCriteria b/share/html/Search/Elements/PickTicketCFs
-similarity index 79%
-copy from share/html/Search/Elements/PickCriteria
-copy to share/html/Search/Elements/PickTicketCFs
-index a15a21a..6b01aa2 100644
---- a/share/html/Search/Elements/PickCriteria
-+++ b/share/html/Search/Elements/PickTicketCFs
-@@ -45,29 +45,17 @@
- %# those contributions and any derivatives thereof.
- %#
- %# END BPS TAGGED BLOCK }}}
--<&| /Widgets/TitleBox, title => loc('Add Criteria')&>
--
--<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>
--<td class="label"><&|/l&>Aggregator</&></td>
--<td class="operator" colspan="2"><& SelectAndOr, Name => "AndOr" &></td>
--
--</tr>
--
--</table>
--
--</&>
--
- <%ARGS>
--$addquery => 0
--$query => undef
- %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 &>
---
-1.8.3.1
-
-
-From 228451ce0c60bac20bf329d0896c7312db3af318 Mon Sep 17 00:00:00 2001
-From: Thomas Sibley <trs at bestpractical.com>
-Date: Fri, 28 Jun 2013 12:14:27 -0700
-Subject: [PATCH 12/12] Parse FooCF.{Bar} when adding a TicketSQL clause in the
- Query Builder
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-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.
----
- share/html/Search/Build.html | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-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 = {
---
-1.8.3.1
-
-----------------------------------------------------------------------
More information about the Bps-public-commit
mailing list