[Rt-commit] rt branch, 4.2/date-time-improvements-in-charts, created. rt-3.8.10-28-ge5056ee

Ruslan Zakirov ruz at bestpractical.com
Wed Jun 1 11:40:14 EDT 2011


The branch, 4.2/date-time-improvements-in-charts has been created
        at  e5056eecc62d15eff639a0d8b8bb0f04c5451b6f (commit)

- Log -----------------------------------------------------------------
commit 24862c28f0e82dc53db537f1ddfa2e4cd094e75a
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri May 20 12:56:28 2011 +0400

    list possible groupings by date in a variable

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index c601485..2a8fa4b 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -54,6 +54,18 @@ use RT::Report::Tickets::Entry;
 use strict;
 use warnings;
 
+our %GROUPINGS = (
+    Date => [qw(
+        Time
+        Hourly Hour
+        Date Daily
+        DayOfWeek Day DayOfMonth DayOfYear
+        Month Monthly
+        Year Annually
+        WeekOfYear
+    )],
+);
+
 sub Groupings {
     my $self = shift;
     my %args = (@_);

commit 21589e14b97da22f89e8772c5f9b14d680850b8c
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri May 20 12:57:14 2011 +0400

    switch over . joined grouping for date fields
    
    we use regexp to parse it later with copied list of possible
    functions, list grows, harder to maintain regexp.
    
    Also, dot joined is consistent with TicketSQL and we'll need
    Created.DayOfWeek = 'Monday'

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index 2a8fa4b..0859bd9 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -82,9 +82,9 @@ sub Groupings {
 
 
     for my $field (qw(Due Resolved Created LastUpdated Started Starts)) {
-        for my $frequency (qw(Hourly Daily Monthly Annually)) {
+        for my $frequency (@{ $GROUPINGS{'Date'} }) {
             my $item = $field.$frequency;
-            push @fields,  $item,  $item;
+            push @fields, "$field $frequency", "$field.$frequency";
         }
     }
 

commit fb576cf99f79c5aae0a650b983d90e22d3a71f79
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri May 20 13:02:37 2011 +0400

    use DateTimeFunction, new method in SB::Handle
    
    we port our custom implementations of the following features
    into DBIx::SearchBuilder
    
    * timezones in DB
    * extracting parts of DateTime columns using DB's functions

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index 0859bd9..62d6ced 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -201,53 +201,23 @@ sub _FieldToFunction {
 
     my $field = $args{'FIELD'};
 
-    if ($field =~ /^(.*)(Hourly|Daily|Monthly|Annually)$/) {
-        my ($field, $grouping) = ($1, $2);
-        my $alias = $args{'ALIAS'} || 'main';
+    my ($key, $subkey) = split /\./, $field, 2;
 
-        my $func = "$alias.$field";
-
-        my $db_type = RT->Config->Get('DatabaseType');
+    if ( $subkey && grep $_ eq $subkey, @{ $GROUPINGS{'Date'} } ) {
+        my $tz;
         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 $to = $self->CurrentUser->UserObj->Timezone
+                || RT->Config->Get('Timezone');
+            $tz = { From => 'UTC', To => $to }
+                if $to && lc $to ne 'utc';
         }
 
-        # Pg 8.3 requires explicit casting
-        $func .= '::text' if $db_type eq 'Pg';
-
-        if ( $grouping eq 'Hourly' ) {
-            $func = "SUBSTR($func,1,13)";
-        }
-        if ( $grouping eq 'Daily' ) {
-            $func = "SUBSTR($func,1,10)";
-        }
-        elsif ( $grouping eq 'Monthly' ) {
-            $func = "SUBSTR($func,1,7)";
-        }
-        elsif ( $grouping eq 'Annually' ) {
-            $func = "SUBSTR($func,1,4)";
-        }
-        $args{'FUNCTION'} = $func;
+        $args{'FUNCTION'} = $RT::Handle->DateTimeFunction(
+            Type => $subkey,
+            Field => "?",
+            Timezone => $tz,
+        );
+        $args{'FIELD'} = $key;
     } elsif ( $field =~ /^(?:CF|CustomField)\.{(.*)}$/ ) { #XXX: use CFDecipher method
         my $cf_name = $1;
         my $cf = RT::CustomField->new( $self->CurrentUser );

commit 6807accee013d8d2b74546e8a75350da5e71dc70
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu May 26 02:21:42 2011 +0400

    @rest is an hash actually, we'll need access by key

diff --git a/lib/RT/Tickets_Overlay.pm b/lib/RT/Tickets_Overlay.pm
index d3a3599..8b8e017 100755
--- a/lib/RT/Tickets_Overlay.pm
+++ b/lib/RT/Tickets_Overlay.pm
@@ -517,7 +517,7 @@ Meta Data:
 =cut
 
 sub _DateLimit {
-    my ( $sb, $field, $op, $value, @rest ) = @_;
+    my ( $sb, $field, $op, $value, %rest ) = @_;
 
     die "Invalid Date Op: $op"
         unless $op =~ /^(=|>|<|>=|<=)$/;
@@ -546,14 +546,14 @@ sub _DateLimit {
             FIELD    => $meta->[1],
             OPERATOR => ">=",
             VALUE    => $daystart,
-            @rest,
+            %rest,
         );
 
         $sb->_SQLLimit(
             FIELD    => $meta->[1],
             OPERATOR => "<",
             VALUE    => $dayend,
-            @rest,
+            %rest,
             ENTRYAGGREGATOR => 'AND',
         );
 
@@ -565,7 +565,7 @@ sub _DateLimit {
             FIELD    => $meta->[1],
             OPERATOR => $op,
             VALUE    => $date->ISO,
-            @rest,
+            %rest,
         );
     }
 }

commit 2f6b145dc96e65e88dc85e2b1bc3f7273fbc8969
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu May 26 03:22:28 2011 +0400

    add searches by DateField.Xxx, ex. Created.Day

diff --git a/lib/RT/Tickets_Overlay.pm b/lib/RT/Tickets_Overlay.pm
index 8b8e017..1fcf6db 100755
--- a/lib/RT/Tickets_Overlay.pm
+++ b/lib/RT/Tickets_Overlay.pm
@@ -526,6 +526,28 @@ sub _DateLimit {
     die "Incorrect Meta Data for $field"
         unless ( defined $meta->[1] );
 
+    if ( my $subkey = $rest{SUBKEY} ) {
+        my $tz;
+        if ( RT->Config->Get('ChartsTimezonesInDB') ) {
+            my $to = $sb->CurrentUser->UserObj->Timezone
+                || RT->Config->Get('Timezone');
+            $tz = { From => 'UTC', To => $to }
+                if $to && lc $to ne 'utc';
+        }
+        my $function = $RT::Handle->DateTimeFunction(
+            Type     => $subkey,
+            Field    => '?',
+            Timezone => $tz,
+        );
+        return $sb->_SQLLimit(
+            FUNCTION => $function,
+            FIELD    => $meta->[1],
+            OPERATOR => $op,
+            VALUE    => $value,
+            %rest,
+        );
+    }
+
     my $date = RT::Date->new( $sb->CurrentUser );
     $date->Set( Format => 'unknown', Value => $value );
 

commit fc2a2e885360abf5d1ad1445b70f8636fb8b807b
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri May 27 22:58:42 2011 +0400

    delete split of FUNCTION into ALIAS/FIELD arguments
    
    it was only way to write a function on left hand side,
    now Limit in SearchBuilder has FUNCTION argumnt and we
    can avoid this mispractice

diff --git a/lib/RT/SearchBuilder.pm b/lib/RT/SearchBuilder.pm
index e4a17f4..e45ac07 100755
--- a/lib/RT/SearchBuilder.pm
+++ b/lib/RT/SearchBuilder.pm
@@ -306,10 +306,7 @@ sub Limit {
         $ARGS{'VALUE'} = 'NULL';
     }
 
-    if ($ARGS{FUNCTION}) {
-        ($ARGS{ALIAS}, $ARGS{FIELD}) = split /\./, delete $ARGS{FUNCTION}, 2;
-        $self->SUPER::Limit(%ARGS);
-    } elsif ($ARGS{FIELD} =~ /\W/
+    if ($ARGS{FIELD} =~ /\W/
           or $ARGS{OPERATOR} !~ /^(=|<|>|!=|<>|<=|>=
                                   |(NOT\s*)?LIKE
                                   |(NOT\s*)?(STARTS|ENDS)WITH

commit c434b297dcd21d89d393d7f7bac72eeeb215e16e
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sun May 29 02:45:01 2011 +0400

    handle not set dates with CASE before applying functions

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index 62d6ced..0294d5a 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -214,7 +214,7 @@ sub _FieldToFunction {
 
         $args{'FUNCTION'} = $RT::Handle->DateTimeFunction(
             Type => $subkey,
-            Field => "?",
+            Field => "CASE WHEN ? < '1970-01-02 00:00:00' THEN NULL ELSE ? END",
             Timezone => $tz,
         );
         $args{'FIELD'} = $key;
diff --git a/lib/RT/Report/Tickets/Entry.pm b/lib/RT/Report/Tickets/Entry.pm
index 158e553..27e592f 100644
--- a/lib/RT/Report/Tickets/Entry.pm
+++ b/lib/RT/Report/Tickets/Entry.pm
@@ -62,21 +62,7 @@ and ensuring that dates are in local not DB timezones.
 
 sub LabelValue {
     my $self  = shift;
-    my $field = shift;
-    my $value = $self->__Value( $field );
-
-    if ( $field =~ /(Daily|Monthly|Annually|Hourly)$/ ) {
-        my $re;
-        # it's not just 1970-01-01 00:00:00 because of timezone shifts
-        # and conversion from UTC to user's TZ
-        $re = qr{19(?:70-01-01|69-12-31) [0-9]{2}} if $field =~ /Hourly$/;
-        $re = qr{19(?:70-01-01|69-12-31)} if $field =~ /Daily$/;
-        $re = qr{19(?:70-01|69-12)} if $field =~ /Monthly$/;
-        $re = qr{19(?:70|69)} if $field =~ /Annually$/;
-        $value =~ s/^$re/Not Set/;
-    }
-
-    return $value;
+    return $self->__Value( @_ );
 }
 
 RT::Base->_ImportOverlays();
diff --git a/lib/RT/Tickets_Overlay.pm b/lib/RT/Tickets_Overlay.pm
index 1fcf6db..7de46ba 100755
--- a/lib/RT/Tickets_Overlay.pm
+++ b/lib/RT/Tickets_Overlay.pm
@@ -536,7 +536,7 @@ sub _DateLimit {
         }
         my $function = $RT::Handle->DateTimeFunction(
             Type     => $subkey,
-            Field    => '?',
+            Field    => "CASE WHEN ? < '1970-01-02 00:00:00' THEN NULL ELSE ? END",
             Timezone => $tz,
         );
         return $sb->_SQLLimit(
@@ -584,6 +584,7 @@ sub _DateLimit {
     }
     else {
         $sb->_SQLLimit(
+            FUNCTION => "CASE WHEN ? < '1970-01-02 00:00:00' THEN NULL ELSE ? END",
             FIELD    => $meta->[1],
             OPERATOR => $op,
             VALUE    => $date->ISO,

commit 7abc33048da208409f0511a2259d61ad671fd0d0
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue May 31 03:13:20 2011 +0400

    add users' fields to our %GROUPINGS hash

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index 0294d5a..2121bb3 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -55,6 +55,12 @@ use strict;
 use warnings;
 
 our %GROUPINGS = (
+    User => [qw(
+        Name RealName NickName
+        EmailAddress
+        Organization
+        Lang City Country Timezone
+    )],
     Date => [qw(
         Time
         Hourly Hour
@@ -75,9 +81,7 @@ sub Groupings {
     );
 
     foreach my $type ( qw(Owner Creator LastUpdatedBy Requestor Cc AdminCc Watcher) ) {
-        push @fields, $type.' '.$_, $type.'.'.$_ foreach qw(
-            Name EmailAddress RealName NickName Organization Lang City Country Timezone
-        );
+        push @fields, map { ("$type $_", "$type.$_") } @{ $GROUPINGS{'User'} };
     }
 
 

commit 48a7cd7141577be5ad38acaae67c86237f41aba3
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue May 31 03:14:08 2011 +0400

    drop unused code

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index 2121bb3..f138d27 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -84,10 +84,8 @@ sub Groupings {
         push @fields, map { ("$type $_", "$type.$_") } @{ $GROUPINGS{'User'} };
     }
 
-
     for my $field (qw(Due Resolved Created LastUpdated Started Starts)) {
         for my $frequency (@{ $GROUPINGS{'Date'} }) {
-            my $item = $field.$frequency;
             push @fields, "$field $frequency", "$field.$frequency";
         }
     }

commit d6d7d9e4734fd673d90739603cdaf68672a50de7
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue May 31 05:13:39 2011 +0400

    make it possible to search by day and month names
    
    for example:
        Created.DayOfWeek = 'Thu'
        Started.Month = 'Jun'

diff --git a/lib/RT/Tickets_Overlay.pm b/lib/RT/Tickets_Overlay.pm
index 7de46ba..fddaa39 100755
--- a/lib/RT/Tickets_Overlay.pm
+++ b/lib/RT/Tickets_Overlay.pm
@@ -527,6 +527,25 @@ sub _DateLimit {
         unless ( defined $meta->[1] );
 
     if ( my $subkey = $rest{SUBKEY} ) {
+        if ( $subkey eq 'DayOfWeek' && $op !~ /IS/i && $value =~ /[^0-9]/ ) {
+            for ( my $i = 0; $i < @RT::Date::DAYS_OF_WEEK; $i++ ) {
+                next unless lc $RT::Date::DAYS_OF_WEEK[ $i ] eq lc $value;
+
+                $value = $i; last;
+            }
+            return $sb->_SQLLimit( FIELD => 'id', VALUE => 0, %rest )
+                if $value =~ /[^0-9]/;
+        }
+        elsif ( $subkey eq 'Month' && $op !~ /IS/i && $value =~ /[^0-9]/ ) {
+            for ( my $i = 0; $i < @RT::Date::MONTHS; $i++ ) {
+                next unless lc $RT::Date::MONTHS[ $i ] eq lc $value;
+
+                $value = $i; last;
+            }
+            return $sb->_SQLLimit( FIELD => 'id', VALUE => 0, %rest )
+                if $value =~ /[^0-9]/;
+        }
+
         my $tz;
         if ( RT->Config->Get('ChartsTimezonesInDB') ) {
             my $to = $sb->CurrentUser->UserObj->Timezone
@@ -534,11 +553,13 @@ sub _DateLimit {
             $tz = { From => 'UTC', To => $to }
                 if $to && lc $to ne 'utc';
         }
+
         my $function = $RT::Handle->DateTimeFunction(
             Type     => $subkey,
             Field    => "CASE WHEN ? < '1970-01-02 00:00:00' THEN NULL ELSE ? END",
             Timezone => $tz,
         );
+
         return $sb->_SQLLimit(
             FUNCTION => $function,
             FIELD    => $meta->[1],

commit f99d3845b06a817a838dcf36ee92774accef179b
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue May 31 18:28:52 2011 +0400

    store grouping properties by column alias

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index f138d27..c7f8bd3 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -137,15 +137,28 @@ sub SetupGroupings {
     my %args = (Query => undef, GroupBy => undef, @_);
 
     $self->FromSQL( $args{'Query'} );
+
     my @group_by = ref( $args{'GroupBy'} )? @{ $args{'GroupBy'} } : ($args{'GroupBy'});
     $self->GroupBy( map { {FIELD => $_} } @group_by );
 
     # UseSQLForACLChecks may add late joins
     my $joined = ($self->_isJoined || RT->Config->Get('UseSQLForACLChecks')) ? 1 : 0;
 
+    my %column_type;
+
     my @res;
+
     push @res, $self->Column( FUNCTION => ($joined? 'DISTINCT COUNT' : 'COUNT'), FIELD => 'id' );
-    push @res, map $self->Column( FIELD => $_ ), @group_by;
+    $column_type{ $res[-1] } = { FUNCTION => ($joined? 'DISTINCT COUNT' : 'COUNT'), FIELD => 'id' };
+
+    foreach my $group_by ( @group_by ) {
+        my $alias = $self->Column( FIELD => $group_by );
+        $column_type{ $alias } = { FIELD => $group_by };
+        push @res, $alias;
+    }
+
+    $self->{'column_types'} = \%column_type;
+
     return @res;
 }
 

commit 28e4f68a313181b8a88881cc5762da9c61c0d06b
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue May 31 18:31:38 2011 +0400

    pass properties of our report to individual entries

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index c7f8bd3..7a6a5d8 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -293,7 +293,9 @@ sub Next {
 
 sub NewItem {
     my $self = shift;
-    return RT::Report::Tickets::Entry->new($RT::SystemUser); # $self->CurrentUser);
+    my $res = RT::Report::Tickets::Entry->new($RT::SystemUser); # $self->CurrentUser);
+    $res->{'column_types'} = $self->{'column_types'};
+    return $res;
 }
 
 

commit 3e349e968b1c11fa391da112f08693d53306369d
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue May 31 18:34:18 2011 +0400

    upgrade DayOfWeek and Month to words in LabelValue

diff --git a/lib/RT/Report/Tickets/Entry.pm b/lib/RT/Report/Tickets/Entry.pm
index 27e592f..a7d0d00 100644
--- a/lib/RT/Report/Tickets/Entry.pm
+++ b/lib/RT/Report/Tickets/Entry.pm
@@ -52,6 +52,14 @@ use base qw/RT::Record/;
 # XXX TODO: how the heck do we acl a report?
 sub CurrentUserHasRight {1}
 
+sub ColumnType {
+    my $self = shift;
+    my $column = shift;
+
+    return $self->{'column_types'}{$column};
+}
+
+
 =head2 LabelValue
 
 If you're pulling a value out of this collection and using it as a label,
@@ -62,7 +70,32 @@ and ensuring that dates are in local not DB timezones.
 
 sub LabelValue {
     my $self  = shift;
-    return $self->__Value( @_ );
+    my $name = shift;
+
+    my $raw = $self->RawValue( $name, @_ );
+
+    my $type = $self->ColumnType( $name );
+    return $raw unless $type;
+
+    my $field = $type->{'FIELD'};
+    return $raw unless $field;
+
+    my ($key, $subkey) = split /\./, $field, 2;
+    if ( $subkey && grep $_ eq $subkey, @{ $RT::Report::Tickets::GROUPINGS{'Date'} } ) {
+        return $raw unless defined $raw;
+        if ( $subkey eq 'DayOfWeek' ) {
+            return $RT::Date::DAYS_OF_WEEK[ int $raw ];
+        }
+        elsif ( $subkey eq 'Month' ) {
+            return $RT::Date::MONTHS[ int $raw ];
+        }
+    }
+
+    return $raw;
+}
+
+sub RawValue {
+    return (shift)->__Value( @_ );
 }
 
 RT::Base->_ImportOverlays();

commit b55de0849b75f8f12ce6cfa2f74eda980d3922e7
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Jun 1 02:53:17 2011 +0400

    GroupBy in SB doesn't combine function with field
    
    GroupBy supports functions for a while, but it's
    not yet compatible with Column and new Limit API,
    so we combine ourself

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index 7a6a5d8..1320ec1 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -167,7 +167,12 @@ sub GroupBy {
     my @args = ref $_[0]? @_ : { @_ };
 
     @{ $self->{'_group_by_field'} ||= [] } = map $_->{'FIELD'}, @args;
-    $_ = { $self->_FieldToFunction( %$_ ) } foreach @args;
+
+    foreach my $e ( @args ) {
+        $e = { $self->_FieldToFunction( %$e ) };
+        $e->{'FUNCTION'} = $self->CombineFunctionWithField( %$e )
+            if $e->{'FUNCTION'};
+    }
 
     $self->SUPER::GroupBy( @args );
 }

commit 8078c28c05088e660e9d20785e8e8b2235ddbf25
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Jun 1 02:55:38 2011 +0400

    component to pick a function calculated in charts

diff --git a/share/html/Search/Elements/SelectChartFunction b/share/html/Search/Elements/SelectChartFunction
new file mode 100644
index 0000000..cff9bd9
--- /dev/null
+++ b/share/html/Search/Elements/SelectChartFunction
@@ -0,0 +1,68 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC
+%#                                          <sales at bestpractical.com>
+%#
+%# (Except where explicitly superseded by other copyright notices)
+%#
+%#
+%# LICENSE:
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+%# General Public License for more details.
+%#
+%# You should have received a copy of the GNU General Public License
+%# along with this program; if not, write to the Free Software
+%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# CONTRIBUTION SUBMISSION POLICY:
+%#
+%# (The following paragraph is not intended to limit the rights granted
+%# to you to modify and distribute this software under the terms of
+%# the GNU General Public License and is only of importance to you if
+%# you choose to contribute your changes and enhancements to the
+%# community by submitting them to Best Practical Solutions, LLC.)
+%#
+%# By intentionally submitting any modifications, corrections or
+%# derivatives to this work, or any other work intended for use with
+%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+%# you are the copyright holder for those contributions and you grant
+%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
+%# royalty-free, perpetual, license to use, copy, create derivative
+%# works based on those contributions, and sublicense and distribute
+%# those contributions and any derivatives thereof.
+%#
+%# END BPS TAGGED BLOCK }}}
+<select name="<% $Name %>">
+% my @tmp = @functions;
+% while ( my ($display, $value) = splice @tmp, 0, 2 ) {
+<option value="<% $value %>"<% $value eq $Default ? qq[ selected="selected"] : '' |n %>><% loc( $display ) %></option>
+% }
+</select>
+<%ARGS>
+$Name => 'ChartFunction'
+$Default => 'COUNT'
+</%ARGS>
+<%ONCE>
+my @functions = (
+    'Count of tickets'  => 'COUNT id',
+);
+foreach my $field (qw(Worked Estimated Left)) {
+    push @functions, "Total time \L$field" => "SUM Time$field",
+        "Average time \L$field" => "AVG Time$field",
+        "Minimum time \L$field" => "MIN Time$field",
+        "Maximum time \L$field" => "MAX Time$field";
+}
+</%ONCE>

commit 2c18ad5913b5881c6ffda59fe129a431ddec703f
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Jun 1 02:57:06 2011 +0400

    Allow to pick chart's function and pass it around
    
    At the end pass it into SetupGrouping, but there is
    no implementation

diff --git a/share/html/Search/Chart b/share/html/Search/Chart
index 7bcb8d0..83768fc 100644
--- a/share/html/Search/Chart
+++ b/share/html/Search/Chart
@@ -50,6 +50,7 @@ $Query => "id > 0"
 $PrimaryGroupBy => 'Queue'
 $SecondaryGroupBy => undef
 $ChartStyle => 'bars'
+$ChartFunction => 'COUNT id'
 </%args>
 <%init>
 my $chart_class;
@@ -69,7 +70,9 @@ my $tix = RT::Report::Tickets->new( $session{'CurrentUser'} );
 my %AllowedGroupings = reverse $tix->Groupings( Query => $Query );
 $PrimaryGroupBy = 'Queue' unless exists $AllowedGroupings{$PrimaryGroupBy};
 my ($count_name, $value_name) = $tix->SetupGroupings(
-    Query => $Query, GroupBy => $PrimaryGroupBy,
+    Query => $Query,
+    GroupBy => $PrimaryGroupBy,
+    Function => $ChartFunction,
 );
 
 my %class = (
diff --git a/share/html/Search/Chart.html b/share/html/Search/Chart.html
index 1a80ee3..1d7b25c 100644
--- a/share/html/Search/Chart.html
+++ b/share/html/Search/Chart.html
@@ -49,6 +49,7 @@
 $PrimaryGroupBy => 'Queue'
 $SecondaryGroupBy => ''
 $ChartStyle => 'bars'
+$ChartFunction => 'COUNT id'
 $Description => undef
 </%args>
 <%init>
@@ -90,8 +91,11 @@ my @actions = $m->comp( '/Widgets/SavedSearch:process', args => \%ARGS, self =>
 <form method="get" action="<%RT->Config->Get('WebPath')%>/Search/Chart.html">
 <input type="hidden" class="hidden" name="Query" value="<% $ARGS{Query} %>" />
 <input type="hidden" class="hidden" name="SavedChartSearchId" value="<% $saved_search->{SearchId} || 'new' %>" />
-<&|/l, $m->scomp('Elements/SelectChartType', Name => 'ChartStyle', Default => $ChartStyle), $m->scomp('Elements/SelectGroupBy', Name => 'PrimaryGroupBy', Query => $ARGS{Query}, Default => $PrimaryGroupBy) 
-&>[_1] chart by [_2]</&><input type="submit" class="button" value="<%loc('Update Graph')%>" />
+<&|/l,
+  $m->scomp('Elements/SelectChartFunction', Default => $ChartFunction),
+  $m->scomp('Elements/SelectChartType', Default => $ChartStyle),
+  $m->scomp('Elements/SelectGroupBy', Name => 'PrimaryGroupBy', Query => $ARGS{Query}, Default => $PrimaryGroupBy) 
+&>[_1] [_2] chart by [_3]</&><input type="submit" class="button" value="<%loc('Update Graph')%>" />
 </form>
 </&>
 
diff --git a/share/html/Search/Elements/Chart b/share/html/Search/Elements/Chart
index e25a9ef..9733352 100644
--- a/share/html/Search/Elements/Chart
+++ b/share/html/Search/Elements/Chart
@@ -50,16 +50,21 @@ $Query => "id > 0"
 $PrimaryGroupBy => 'Queue'
 $SecondaryGroupBy => undef
 $ChartStyle => 'bars'
+$ChartFunction => 'COUNT id'
 </%args>
 <%init>
 use RT::Report::Tickets;
 $PrimaryGroupBy ||= 'Queue'; # make sure PrimaryGroupBy is not undef
 
 my $tix = RT::Report::Tickets->new( $session{'CurrentUser'} );
+
 my %AllowedGroupings = reverse $tix->Groupings( Query => $Query );
 $PrimaryGroupBy = 'Queue' unless exists $AllowedGroupings{$PrimaryGroupBy};
+
 my ($count_name, $value_name) = $tix->SetupGroupings(
-    Query => $Query, GroupBy => $PrimaryGroupBy,
+    Query => $Query,
+    GroupBy => $PrimaryGroupBy,
+    Function => $ChartFunction,
 );
 
 my %class = (

commit 2ac069b3114d9bd3a0dbf37cb7f804a1fdaa92cd
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Jun 1 02:58:16 2011 +0400

    implement Function argument in ChartGrouping

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index 1320ec1..d10690d 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -134,7 +134,12 @@ sub Label {
 
 sub SetupGroupings {
     my $self = shift;
-    my %args = (Query => undef, GroupBy => undef, @_);
+    my %args = (
+        Query => undef,
+        GroupBy => undef,
+        Function => undef,
+        @_
+    );
 
     $self->FromSQL( $args{'Query'} );
 
@@ -144,12 +149,15 @@ sub SetupGroupings {
     # UseSQLForACLChecks may add late joins
     my $joined = ($self->_isJoined || RT->Config->Get('UseSQLForACLChecks')) ? 1 : 0;
 
-    my %column_type;
-
-    my @res;
+    my (@res, %column_type);
 
-    push @res, $self->Column( FUNCTION => ($joined? 'DISTINCT COUNT' : 'COUNT'), FIELD => 'id' );
-    $column_type{ $res[-1] } = { FUNCTION => ($joined? 'DISTINCT COUNT' : 'COUNT'), FIELD => 'id' };
+    my @function = ref( $args{'Function'} )? @{ $args{'Function'} } : ($args{'Function'});
+    foreach my $e ( @function ) {
+        my ($function, $field) = split /\s+/, $e, 2;
+        $function = 'DISTINCT COUNT' if $joined && lc($function) eq 'count';
+        push @res, $self->Column( FUNCTION => $function, FIELD => $field );
+        $column_type{ $res[-1] } = { FUNCTION => $function, FIELD => $field };
+    }
 
     foreach my $group_by ( @group_by ) {
         my $alias = $self->Column( FIELD => $group_by );

commit e5056eecc62d15eff639a0d8b8bb0f04c5451b6f
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Jun 1 19:38:46 2011 +0400

    branch specific todo

diff --git a/TODO.charts b/TODO.charts
new file mode 100644
index 0000000..f3a36d2
--- /dev/null
+++ b/TODO.charts
@@ -0,0 +1,7 @@
+expand GROUPINGS to list fields and a few callbacks
+
+move abuse protection code from callers to SetupGrouping
+
+protect Function in SetupGrouping from abuse
+
+extend GroupBy in DBIx::SB with CombineFunctionWithField

-----------------------------------------------------------------------


More information about the Rt-commit mailing list