[Rt-commit] rt branch, master, updated. rt-4.1.13-205-ge5943f6
Thomas Sibley
trs at bestpractical.com
Wed Jul 3 22:06:54 EDT 2013
The branch, master has been updated
via e5943f653df8c758b04cb3f010cd724283c3db81 (commit)
via 005f3a280119b7fe99082fd28fa7d72bea9bad53 (commit)
via dd88aead7846fcc5ca9fdd36870117e5ed1d7809 (commit)
via e1538530daebfae89bae81234943997c01c9c713 (commit)
via f4fefd1c2141c0b6d1edb947f0ef4c04662e7221 (commit)
via 390fb60c1d7c63c6dbf691bf4f7605b0563d6ab4 (commit)
via 71a5e134b987302bc5e63ad161dc7ede1b6bd25a (commit)
via 3ee4909ca08accd3ff6a3751f694acf258e6aea7 (commit)
via af1b6bf7a446f45e335a4f09633b7dd5584e386d (commit)
via f487fd06bb9326f8feaf4cfaeb687e0c8790a557 (commit)
via 15ffd62c9807f6454c2f068bc0d41358bce5cae7 (commit)
via 63da75bd9659ef0e8da9be26a4b79f965fcd4181 (commit)
via a5c768cc9a441e3e60d9b796f846087dbaf267db (commit)
via f642844c5adb271344ab018a8e465d13e236bd9d (commit)
via 84a913a13124970ec107851fd3585c8bb179192b (commit)
via ed8b7781912f6d7db47c06b1797e132a634b160b (commit)
via f3b33e9bfb221ba8bd25eaaccdc769c7928a5969 (commit)
via b9ba8c77ae18d036fca4e9c712d45796b91760b1 (commit)
via 655573291cc7f07de71045576b2b9804e1dd7ea8 (commit)
via 5d1a7e632c1e2c68ef3a2a3a860601ce977ffbde (commit)
via 9170af4debc2cfb89d1aa64d0062e47e4d4f5835 (commit)
via c4154e468dac5f402a9603a6d3a5effcd909e8ea (commit)
via 319e8ad2c9ff029a53e71a0ba4fe004afa1894c5 (commit)
via 885a64637c3e704b1961a562ebd1c44105ac767c (commit)
via bd23ffb9d47d20a3c7ce54bd815347b4d9b8e3cb (commit)
via f25f2d9c24f7d0426bfa5b1b078e955935975fe1 (commit)
via 9002a0cd4d8d408cba524f9208f8743a130598ef (commit)
via 26aff0330d61d037f01e7c4056155ea579183fbd (commit)
via 479935d3716ca9625d2bc242be737d771d81fc4b (commit)
via 1a30e4fe25543d0e331f74948d8b1cc58c40eeec (commit)
via 96da8956b3a01a5d431bf8b73dba7e5f5ce42771 (commit)
via b184ecbcd520715597225061a6c51c704e32f233 (commit)
via d68f64a76b20828ca63ce64186a34826b2f91f50 (commit)
via a4d38fb57d7e6350625b10cfe8131fb49ddd0fc7 (commit)
via 78a20e70a88429a5b6686a3d9c2bf26dc708b1c9 (commit)
via a251473e8d190580dd7d2f5b82ac28d140f1e598 (commit)
via a98515b4a9ede8645cbf399cc778166bd22d8df7 (commit)
via 865b37eaefffcfc656269291511ea42a54e8e6f4 (commit)
via a4436d0dc6d8d94caabb28aec05055e4c6768065 (commit)
via 5de477093121ab90f4720b040ce9e532095aa73c (commit)
via a1127c88653527f1f16f4705067b987e3598c62b (commit)
via ec101790ee2f0f1f9f302d23a708b749653c3875 (commit)
via 77cb586346cd63262e0d198dee740dd8504f1a02 (commit)
via fa5178a2a27365cdace20aed65ae66346cd7eea1 (commit)
via c6bfe58fd4ca447901b4f0542bdbdba0e9fabf5d (commit)
via e936ea928eb9cd89c7458389adeae5224b327ca7 (commit)
via 68b4ac2ddf90442117aacc264e595389cb577272 (commit)
via b2d0d67be60c09a1d29881892b9b3e3b6de85c53 (commit)
via c0b94a16264a0e996475eb63090a3adfeafb8ae3 (commit)
via eff03c293e603ee6366ff051f7ea4d78ec8e398a (commit)
via 738c076359536a180f55b9dda85a0d160184a53b (commit)
via 4fa2481ba84980b2715550951016f131257cdc0f (commit)
via 86d7b4d2fb4c2d9e989ecd4fd5149fd0e6528774 (commit)
via 153d7b8f4e232d4a44de51abf554735cb14dc8c2 (commit)
via 42059c2b0a4bc316bc88802d65ea6ab986290199 (commit)
via 7256b2b5064439c6935b3e6bc2959b8a3ae3b946 (commit)
via ea68c171ff90b3bd5ac362080ae96655a5c3affa (commit)
via 2ef014f419c2f7b52d056ed11e7f2b6f35eacb8b (commit)
via 717aa384c9ad66f51e944c0a06ebf60a5e978650 (commit)
via c8bdf1ffcfd81c7920370e04f2f7cfc0e1566f36 (commit)
via d81a4fa7a533128e7724e661b25f622c2a5854be (commit)
via 4cf816d416df911e9acb99337c7c473848d4d51d (commit)
via 6ec5437c01c0d062399038dd667e101896e30cc2 (commit)
via 2e1b70c47921e739ab871bb5c00859c16df7746d (commit)
via 8b1d371b41979d9ffaa290194b23691978bacd40 (commit)
via 5ffd77f2f6bf1eda093aaa1693ab1fcdc01491b3 (commit)
via 83d5bd6d0ef55ee814fe4dce3350bd8d714b651c (commit)
via 7cf22661971aeb598ec0062bc5c25f9f77c0be8f (commit)
via 1ef4c5e9616c6a1c5e22d05e91b65806a7764c2f (commit)
via d386ec08432483555196554defa70b12719feb3a (commit)
via 9f7736f6d105020f76e0e9972e9215c6f54481ea (commit)
via f3737d2c6f25e9c14a45b75653d509361a4aeec0 (commit)
via b9660bea6e145091612e77194cdf603d879f2776 (commit)
via a9e8bb8127620cb43acc2b238a521960b99f87fa (commit)
via a16828dd2b7cb5a076d28179b21cb00853d8c7cb (commit)
via 9f0521176943f23435b968ee18313359280dc74a (commit)
via 74eb701ab450625da462d8063ee59427c9d12f4f (commit)
via 59ec3a43fe99016fade26ca567b0738677700e83 (commit)
via 3b1b3f2ae247c5b8d5d2c7e370a8a745a5c8529e (commit)
via 87559a8f86d3f66f656930dbfc93cd6071718999 (commit)
via 696a5d935a59bb5ee95dcfced8f82f4698ec58af (commit)
via bdb225a77f2cbecc38ebd37ee95fd9cf32aa8f7b (commit)
via c59d4eeb001d3b2f30a2140e9ddeec4ffd2ce023 (commit)
via c556fba6d352352f28da4031592844742e2129b8 (commit)
via 0e0f6359e5ffd5f909d9df922998feeb1f222c80 (commit)
via 50ab54fddd8ffca1f85fc6053a105425818f6050 (commit)
via 115f373f5c874a7418fd8c98dab440166ec2055d (commit)
via c492ac54707c6e53c49a5884949f22f4c51b945e (commit)
via 7bd405b96c1bc3f57f476e6c5143179ee40e1e59 (commit)
via 0e830cdb5b10f00f27f85a8a1db34d8f7b4ff07b (commit)
via b8f6c68c282e0b6604533139cdeaa5a28715bfb6 (commit)
via 3370c9150ebac71e54e0b804ec0db548e7d16961 (commit)
via 2012462b0303ea050e9b8bb9999bab9b9ad40238 (commit)
via 1846886d40310d6e69108364500bc6007fbcdc16 (commit)
via 52ac9803e5966a7438b68788aba9d80abfbca41f (commit)
via 60069cea2c20a5f85977c3b726841a68521a1a20 (commit)
via 7e4b83ca7e0f2c03f49a43e1c0ed310d15bf5ea3 (commit)
via 3c6fede42a35638b8951a29255edea5888b8f3be (commit)
via 704fa93ff796ba72b7254a368a3bf2492234150c (commit)
via fc6a42d2fbd4916602816a443489d5fb83608eee (commit)
via 5fbdd35222dc241eb24ad0c191f17516dad0160f (commit)
via 50ee65f01526ba9840e4a3eae411426822f232a8 (commit)
via 5532b316ac29707a25429ce2e665531adcbffbe2 (commit)
via 15c07226f3d15e444ce4f69dc21458678ca162f0 (commit)
via 658a3b827913c0630ec67bb00f72c662d77e1066 (commit)
via 0fc3e2a1d6fd24e50e528223ee4895186d2427e6 (commit)
via 0a6fca96562b4ddcdeceee3f74fa99113f856343 (commit)
via 59370443dcf60489429e0994697067f4be9a4f3b (commit)
via 945624601c283e7f2f35941cef2e3f606cc0ee9d (commit)
via b0bb95b33021bf0361f595a0d843f58a4e2b9b1d (commit)
via f43442871fa53cac4301043ae6ba5620b7786d96 (commit)
via 88b80480163b19546eb8aae51bbf6d22bec46eaf (commit)
via eaf36218f6014a3d5d69d93f94a5e0543d914113 (commit)
via a3bae3d2d707713ee4604a0cae2da678c59cc65c (commit)
via cd5fda36475464fd9e49610e21ed37cbd5733067 (commit)
via a41f71068ace70ad62ed280eb0b03273140cec91 (commit)
via d3654e25c097d9015a9a689a997721000a2ea3d6 (commit)
via e8cce975142faa0e2eff325d10bd603a2c1678a0 (commit)
via 6157ebcf349f8c0e0f4b788ed308b6c129f2bce6 (commit)
via abcc3ca8d436e0e07158741d9d36456e1a447ce7 (commit)
via 54dfec479f3eb2930e2967ecd7c9c36b8e66c7b6 (commit)
via 25e35201ead1975db3f7e25a5287739520e40208 (commit)
via 02d7a7b01d6360d52a8cd4d2bd22f983a0ff1083 (commit)
via 1e85def7fbb617fc7545fe3f1586383f6c0ffdd8 (commit)
via aa1362992eb49465442ad52686ce66ab0d1376b0 (commit)
via a09f21ca64086bd5ed7359f3a8cbd0f4f6241413 (commit)
via 78e524d3fe7cbffcda328391dc830e51d1d62b09 (commit)
via 68c3906e4e322b87523dfa342180ebf810ebcea0 (commit)
via e60885aa24c5009e801b23c9bdac148fbe2a6276 (commit)
via eedce1294a5768a80a23ed8bb129040dab0d00b8 (commit)
via 1ff64458d8a18ebfda6020b024897cec5443c397 (commit)
via 3d143b76d8940419bd702b16152ea6e6ee08be86 (commit)
via 0670126702e64b1217a015bebf9ee098edbcc6eb (commit)
via 49a0d6217e08d6773e2d31cd311291a55ca5babe (commit)
from a4d522b6676eb4af12daacbb24f4977f39c4ebbe (commit)
Summary of changes:
etc/RT_Config.pm.in | 13 +
etc/upgrade/4.1.17/content | 26 +
lib/RT/Config.pm | 3 +
lib/RT/Date.pm | 126 ++-
lib/RT/I18N/cs.pm | 5 +-
lib/RT/I18N/ru.pm | 2 +-
lib/RT/Interface/Web.pm | 1 +
lib/RT/Record.pm | 1 +
lib/RT/Report/Tickets.pm | 1049 ++++++++++++++++----
lib/RT/Report/Tickets/Entry.pm | 73 +-
lib/RT/SearchBuilder.pm | 28 +-
lib/RT/Tickets.pm | 67 +-
lib/RT/User.pm | 4 +-
sbin/rt-test-dependencies.in | 4 +-
share/html/Elements/EditCustomFieldSelect | 8 +-
share/html/Elements/QueryString | 3 +-
share/html/Search/Chart | 460 +++++++--
share/html/Search/Chart.html | 88 +-
share/html/Search/Elements/Chart | 99 +-
share/html/Search/Elements/ChartTable | 117 +++
.../Elements/SelectChartFunction} | 37 +-
share/html/Search/Elements/SelectGroupBy | 26 +-
share/static/css/base/charts.css | 21 +
share/static/css/base/main.css | 1 +
share/static/js/cascaded.js | 11 +-
share/static/js/event-registration.js | 40 +
t/api/date.t | 22 +-
t/charts/basics.t | 90 ++
t/charts/compound-sql-function.t | 120 +++
t/web/charting.t | 38 +-
t/web/saved_search_chart.t | 8 +-
31 files changed, 2112 insertions(+), 479 deletions(-)
create mode 100644 etc/upgrade/4.1.17/content
create mode 100644 share/html/Search/Elements/ChartTable
copy share/html/{Articles/Article/Elements/SelectSearchPrivacy => Search/Elements/SelectChartFunction} (72%)
create mode 100644 share/static/css/base/charts.css
create mode 100644 t/charts/basics.t
create mode 100644 t/charts/compound-sql-function.t
- Log -----------------------------------------------------------------
commit e5943f653df8c758b04cb3f010cd724283c3db81
Merge: a4d522b 005f3a2
Author: Thomas Sibley <trs at bestpractical.com>
Date: Wed Jul 3 17:57:13 2013 -0700
Merge branch '4.2/charts'
Conflicts:
lib/RT/Report/Tickets.pm
lib/RT/SearchBuilder.pm
diff --cc lib/RT/Report/Tickets.pm
index 02217f3,16b48eb..3042ff7
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@@ -190,88 -582,170 +582,171 @@@ sub _FieldToFunction
my $self = shift;
my %args = (@_);
- my $field = $args{'FIELD'};
+ $args{'FIELD'} ||= $args{'KEY'};
- if ($field =~ /^(.*)(Hourly|Daily|Monthly|Annually)$/) {
- my ($field, $grouping) = ($1, $2);
- my $alias = $args{'ALIAS'} || 'main';
+ my $meta = $GROUPINGS_META{ $GROUPINGS{ $args{'KEY'} } };
+ return ('FUNCTION' => 'NULL') unless $meta;
- my $func = "$alias.$field";
+ return %args unless $meta->{'Function'};
- my $db_type = RT->Config->Get('DatabaseType');
- if ( RT->Config->Get('ChartsTimezonesInDB') ) {
- my $tz = $self->CurrentUser->UserObj->Timezone
- || RT->Config->Get('Timezone')
- || 'UTC';
- if ( lc $tz eq 'utc' ) {
- # do nothing
- }
- elsif ( $db_type eq 'Pg' ) {
- $func = "timezone('UTC', $func)";
- $func = "timezone(". $self->_Handle->dbh->quote($tz) .", $func)";
- }
- elsif ( $db_type eq 'mysql' ) {
- $func = "CONVERT_TZ($func, 'UTC', "
- . $self->_Handle->dbh->quote($tz)
- .")";
- }
- else {
- $RT::Logger->warning(
- "ChartsTimezonesInDB config option"
- ." is not supported on $db_type."
- );
- }
- }
+ my $code = $self->FindImplementationCode( $meta->{'Function'} );
+ return ('FUNCTION' => 'NULL') unless $code;
+
+ return $code->( $self, %args );
+ }
+
+
+ # Gotta skip over RT::Tickets->Next, since it does all sorts of crazy magic we
+ # don't want.
+ sub Next {
+ my $self = shift;
+ $self->RT::SearchBuilder::Next(@_);
+
+ }
+
+ sub NewItem {
+ my $self = shift;
+ my $res = RT::Report::Tickets::Entry->new($self->CurrentUser);
+ $res->{'report'} = $self;
+ weaken $res->{'report'};
+ return $res;
+ }
+
+ # This is necessary since normally NewItem (above) is used to intuit the
+ # correct class. However, since we're abusing a subclass, it's incorrect.
+ sub _RoleGroupClass { "RT::Ticket" }
++sub _SingularClass { "RT::Report::Tickets::Entry" }
+
+ sub SortEntries {
+ my $self = shift;
+
+ $self->_DoSearch if $self->{'must_redo_search'};
+ return unless $self->{'items'} && @{ $self->{'items'} };
- # Pg 8.3 requires explicit casting
- $func .= '::text' if $db_type eq 'Pg';
+ my @groups =
+ grep $_->{'TYPE'} eq 'grouping',
+ map $self->ColumnInfo($_),
+ $self->ColumnsList;
+ return unless @groups;
- if ( $grouping eq 'Hourly' ) {
- $func = "SUBSTR($func,1,13)";
+ my @SORT_OPS;
+ my $by_multiple = sub ($$) {
+ for my $f ( @SORT_OPS ) {
+ my $r = $f->($_[0], $_[1]);
+ return $r if $r;
}
- if ( $grouping eq 'Daily' ) {
- $func = "SUBSTR($func,1,10)";
+ };
+ my @data = map [$_], @{ $self->{'items'} };
+
+ for ( my $i = 0; $i < @groups; $i++ ) {
+ my $group_by = $groups[$i];
+ my $idx = $i+1;
+ my $method;
+
+ my $order = $group_by->{'META'}{Sort} || 'label';
+ if ( $order eq 'label' ) {
+ push @SORT_OPS, sub { $_[0][$idx] cmp $_[1][$idx] };
+ $method = 'LabelValue';
}
- elsif ( $grouping eq 'Monthly' ) {
- $func = "SUBSTR($func,1,7)";
+ elsif ( $order eq 'numeric label' ) {
+ push @SORT_OPS, sub { $_[0][$idx] <=> $_[1][$idx] };
+ $method = 'LabelValue';
}
- elsif ( $grouping eq 'Annually' ) {
- $func = "SUBSTR($func,1,4)";
+ elsif ( $order eq 'raw' ) {
+ push @SORT_OPS, sub { $_[0][$idx] cmp $_[1][$idx] };
+ $method = 'RawValue';
}
- $args{'FUNCTION'} = $func;
- } elsif ( $field =~ /^(?:CF|CustomField)\.{(.*)}$/ ) { #XXX: use CFDecipher method
- my $cf_name = $1;
- my $cf = RT::CustomField->new( $self->CurrentUser );
- $cf->Load($cf_name);
- unless ( $cf->id ) {
- $RT::Logger->error("Couldn't load CustomField #$cf_name");
+ elsif ( $order eq 'numeric raw' ) {
+ push @SORT_OPS, sub { $_[0][$idx] <=> $_[1][$idx] };
+ $method = 'RawValue';
} else {
- my ($ticket_cf_alias, $cf_alias) = $self->_CustomFieldJoin($cf->id, $cf);
- @args{qw(ALIAS FIELD)} = ($ticket_cf_alias, 'Content');
+ $RT::Logger->error("Unknown sorting function '$order'");
+ next;
}
- } elsif ( $field =~ /^(?:(Owner|Creator|LastUpdatedBy))(?:\.(.*))?$/ ) {
- my $type = $1 || '';
- my $column = $2 || 'Name';
- my $u_alias = $self->{"_sql_report_${type}_users_${column}"}
- ||= $self->Join(
- TYPE => 'LEFT',
- ALIAS1 => 'main',
- FIELD1 => $type,
- TABLE2 => 'Users',
- FIELD2 => 'id',
- );
- @args{qw(ALIAS FIELD)} = ($u_alias, $column);
- } elsif ( $field =~ /^(?:Watcher|(Requestor|Cc|AdminCc))(?:\.(.*))?$/ ) {
- my $type = $1 || '';
- my $column = $2 || 'Name';
- my $u_alias = $self->{"_sql_report_watcher_users_alias_$type"};
- unless ( $u_alias ) {
- my ($g_alias, $gm_alias);
- ($g_alias, $gm_alias, $u_alias) = $self->_WatcherJoin( Name => $type );
- $self->{"_sql_report_watcher_users_alias_$type"} = $u_alias;
+ $_->[$idx] = $_->[0]->$method( $group_by->{'NAME'} ) for @data;
+ }
+ $self->{'items'} = [
+ map $_->[0],
+ sort $by_multiple @data
+ ];
+ }
+
+ sub PostProcessRecords {
+ my $self = shift;
+
+ my $info = $self->{'column_info'};
+ foreach my $column ( values %$info ) {
+ next unless $column->{'TYPE'} eq 'statistic';
+ if ( $column->{'META'}{'Calculate'} ) {
+ $self->CalculatePostFunction( $column );
+ }
+ elsif ( $column->{'META'}{'SubValues'} ) {
+ $self->MapSubValues( $column );
+ }
+ }
+ }
+
+ sub CalculatePostFunction {
+ my $self = shift;
+ my $info = shift;
+
+ my $code = $self->FindImplementationCode( $info->{'META'}{'Calculate'} );
+ unless ( $code ) {
+ # TODO: fill in undefs
+ return;
+ }
+
+ my $column = $info->{'NAME'};
+
+ my $base_query = $self->Query;
+ foreach my $item ( @{ $self->{'items'} } ) {
+ $item->{'values'}{ lc $column } = $code->(
+ $self,
+ Query => join(
+ ' AND ', map "($_)", grep defined && length, $base_query, $item->Query,
+ ),
+ );
+ $item->{'fetched'}{ lc $column } = 1;
+ }
+ }
+
+ sub MapSubValues {
+ my $self = shift;
+ my $info = shift;
+
+ my $to = $info->{'NAME'};
+ my $map = $info->{'MAP'};
+
+ foreach my $item ( @{ $self->{'items'} } ) {
+ my $dst = $item->{'values'}{ lc $to } = { };
+ while (my ($k, $v) = each %{ $map } ) {
+ $dst->{ $k } = delete $item->{'values'}{ lc $v->{'NAME'} };
+ utf8::decode( $dst->{ $k } )
+ if defined $dst->{ $k }
+ and not utf8::is_utf8( $dst->{ $k } );
+ delete $item->{'fetched'}{ lc $v->{'NAME'} };
}
- @args{qw(ALIAS FIELD)} = ($u_alias, $column);
+ $item->{'fetched'}{ lc $to } = 1;
+ }
+ }
+
+ sub GenerateDateFunction {
+ my $self = shift;
+ my %args = @_;
+
+ my $tz;
+ if ( RT->Config->Get('ChartsTimezonesInDB') ) {
+ my $to = $self->CurrentUser->UserObj->Timezone
+ || RT->Config->Get('Timezone');
+ $tz = { From => 'UTC', To => $to }
+ if $to && lc $to ne 'utc';
}
+
+ $args{'FUNCTION'} = $RT::Handle->DateTimeFunction(
+ Type => $args{'SUBKEY'},
+ Field => $self->NotSetDateToNullFunction,
+ Timezone => $tz,
+ );
return %args;
}
diff --cc lib/RT/SearchBuilder.pm
index 75e3ed7,e1993c9..7ac964b
--- a/lib/RT/SearchBuilder.pm
+++ b/lib/RT/SearchBuilder.pm
@@@ -922,17 -908,30 +920,41 @@@ sub ColumnMapClassName
return $Class;
}
+=head2 NewItem
+
+Returns a new item based on L</RecordClass> using the current user.
+
+=cut
+
+sub NewItem {
+ my $self = shift;
+ return $self->RecordClass->new($self->CurrentUser);
+}
+
+ =head2 NotSetDateToNullFunction
+
+ Takes a paramhash with an optional FIELD key whose value is the name of a date
+ column. If no FIELD is provided, a literal C<?> placeholder is used so the
+ caller can fill in the field later.
+
+ Returns a SQL function which evaluates to C<NULL> if the FIELD is set to the
+ Unix epoch; otherwise it evaluates to FIELD. This is useful because RT
+ currently stores unset dates as a Unix epoch timestamp instead of NULL, but
+ NULLs are often more desireable.
+
+ =cut
+
+ sub NotSetDateToNullFunction {
+ my $self = shift;
+ my %args = ( FIELD => undef, @_ );
+
+ my $res = "CASE WHEN ? BETWEEN '1969-12-31 11:59:59' AND '1970-01-01 12:00:01' THEN NULL ELSE ? END";
+ if ( $args{FIELD} ) {
+ $res = $self->CombineFunctionWithField( %args, FUNCTION => $res );
+ }
+ return $res;
+ }
+
RT::Base->_ImportOverlays();
1;
-----------------------------------------------------------------------
More information about the Rt-commit
mailing list