diff options
-rw-r--r-- | Bugzilla/Search.pm | 321 |
1 files changed, 164 insertions, 157 deletions
diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm index 80e8dce43..2f7dfdcad 100644 --- a/Bugzilla/Search.pm +++ b/Bugzilla/Search.pm @@ -1629,79 +1629,11 @@ sub _pick_override_function { # Search Function Helpers # ########################### -sub SqlifyDate { - my ($str) = @_; - $str = "" if !defined $str; - if ($str eq "") { - my ($sec, $min, $hour, $mday, $month, $year, $wday) = localtime(time()); - return sprintf("%4d-%02d-%02d 00:00:00", $year+1900, $month+1, $mday); - } - - - if ($str =~ /^(-|\+)?(\d+)([hHdDwWmMyY])$/) { # relative date - my ($sign, $amount, $unit, $date) = ($1, $2, lc $3, time); - my ($sec, $min, $hour, $mday, $month, $year, $wday) = localtime($date); - if ($sign && $sign eq '+') { $amount = -$amount; } - if ($unit eq 'w') { # convert weeks to days - $amount = 7*$amount + $wday; - $unit = 'd'; - } - if ($unit eq 'd') { - $date -= $sec + 60*$min + 3600*$hour + 24*3600*$amount; - return time2str("%Y-%m-%d %H:%M:%S", $date); - } - elsif ($unit eq 'y') { - return sprintf("%4d-01-01 00:00:00", $year+1900-$amount); - } - elsif ($unit eq 'm') { - $month -= $amount; - while ($month<0) { $year--; $month += 12; } - return sprintf("%4d-%02d-01 00:00:00", $year+1900, $month+1); - } - elsif ($unit eq 'h') { - # Special case 0h for 'beginning of this hour' - if ($amount == 0) { - $date -= $sec + 60*$min; - } else { - $date -= 3600*$amount; - } - return time2str("%Y-%m-%d %H:%M:%S", $date); - } - return undef; # should not happen due to regexp at top - } - my $date = str2time($str); - if (!defined($date)) { - ThrowUserError("illegal_date", { date => $str }); - } - return time2str("%Y-%m-%d %H:%M:%S", $date); -} - sub build_subselect { my ($outer, $inner, $table, $cond) = @_; return "$outer IN (SELECT $inner FROM $table WHERE $cond)"; } -sub pronoun { - my ($noun, $user) = (@_); - if ($noun eq "%user%") { - if ($user->id) { - return $user->id; - } else { - ThrowUserError('login_required_for_pronoun'); - } - } - if ($noun eq "%reporter%") { - return "bugs.reporter"; - } - if ($noun eq "%assignee%") { - return "bugs.assigned_to"; - } - if ($noun eq "%qacontact%") { - return "bugs.qa_contact"; - } - return 0; -} - # Used by anyexact to get the list of input values. This allows us to # support values with commas inside of them in the standard charts, and # still accept string values for the boolean charts (and split them on @@ -1773,67 +1705,95 @@ sub _word_terms { return @terms; } -###################### -# Public Subroutines # -###################### +##################################### +# "Special Parsing" Functions: Date # +##################################### -# Validate that the query type is one we can deal with -sub IsValidQueryType -{ - my ($queryType) = @_; - if (grep { $_ eq $queryType } qw(specific advanced)) { - return 1; - } - return 0; -} +sub _timestamp_translate { + my ($self, $args) = @_; + my $value = $args->{value}; + my $dbh = Bugzilla->dbh; -# Splits out "asc|desc" from a sort order item. -sub split_order_term { - my $fragment = shift; - $fragment =~ /^(.+?)(?:\s+(ASC|DESC))?$/i; - my ($column_name, $direction) = (lc($1), uc($2 || '')); - return wantarray ? ($column_name, $direction) : $column_name; + return if $value !~ /^[\+\-]?\d+[hdwmy]$/i; + + $args->{value} = SqlifyDate($value); + $args->{quoted} = $dbh->quote($args->{value}); } -# Used to translate old SQL fragments from buglist.cgi's "order" argument -# into our modern field IDs. -sub translate_old_column { - my ($column) = @_; - # All old SQL fragments have a period in them somewhere. - return $column if $column !~ /\./; - - if ($column =~ /\bAS\s+(\w+)$/i) { - return $1; +sub SqlifyDate { + my ($str) = @_; + $str = "" if !defined $str; + if ($str eq "") { + my ($sec, $min, $hour, $mday, $month, $year, $wday) = localtime(time()); + return sprintf("%4d-%02d-%02d 00:00:00", $year+1900, $month+1, $mday); } - # product, component, classification, assigned_to, qa_contact, reporter - elsif ($column =~ /map_(\w+?)s?\.(login_)?name/i) { - return $1; + + if ($str =~ /^(-|\+)?(\d+)([hHdDwWmMyY])$/) { # relative date + my ($sign, $amount, $unit, $date) = ($1, $2, lc $3, time); + my ($sec, $min, $hour, $mday, $month, $year, $wday) = localtime($date); + if ($sign && $sign eq '+') { $amount = -$amount; } + if ($unit eq 'w') { # convert weeks to days + $amount = 7*$amount + $wday; + $unit = 'd'; + } + if ($unit eq 'd') { + $date -= $sec + 60*$min + 3600*$hour + 24*3600*$amount; + return time2str("%Y-%m-%d %H:%M:%S", $date); + } + elsif ($unit eq 'y') { + return sprintf("%4d-01-01 00:00:00", $year+1900-$amount); + } + elsif ($unit eq 'm') { + $month -= $amount; + while ($month<0) { $year--; $month += 12; } + return sprintf("%4d-%02d-01 00:00:00", $year+1900, $month+1); + } + elsif ($unit eq 'h') { + # Special case 0h for 'beginning of this hour' + if ($amount == 0) { + $date -= $sec + 60*$min; + } else { + $date -= 3600*$amount; + } + return time2str("%Y-%m-%d %H:%M:%S", $date); + } + return undef; # should not happen due to regexp at top } - - # If it doesn't match the regexps above, check to see if the old - # SQL fragment matches the SQL of an existing column - foreach my $key (%{ COLUMNS() }) { - next unless exists COLUMNS->{$key}->{name}; - return $key if COLUMNS->{$key}->{name} eq $column; + my $date = str2time($str); + if (!defined($date)) { + ThrowUserError("illegal_date", { date => $str }); } - - return $column; + return time2str("%Y-%m-%d %H:%M:%S", $date); } -##################################################################### -# Search Functions -##################################################################### +###################################### +# "Special Parsing" Functions: Users # +###################################### -sub _invalid_combination { - my ($self, $args) = @_; - my ($field, $operator) = @$args{qw(field operator)}; - ThrowUserError('search_field_operator_invalid', - { field => $field, operator => $operator }); +sub pronoun { + my ($noun, $user) = (@_); + if ($noun eq "%user%") { + if ($user->id) { + return $user->id; + } else { + ThrowUserError('login_required_for_pronoun'); + } + } + if ($noun eq "%reporter%") { + return "bugs.reporter"; + } + if ($noun eq "%assignee%") { + return "bugs.assigned_to"; + } + if ($noun eq "%qacontact%") { + return "bugs.qa_contact"; + } + return 0; } sub _contact_pronoun { my ($self, $args) = @_; - my ($value, $quoted) = @$args{qw(value quoted)}; + my $value = $args->{value}; my $user = $self->_user; if ($value =~ /^\%group/) { @@ -1873,24 +1833,6 @@ sub _contact_exact_group { } } -sub _contact_nonchanged { - my ($self, $args) = @_; - my $field = $args->{field}; - - $args->{full_field} = "profiles.login_name"; - $self->_do_operator_function($args); - my $term = $args->{term}; - $args->{term} = "bugs.$field IN (SELECT userid FROM profiles WHERE $term)"; -} - -sub _qa_contact_nonchanged { - my ($self, $args) = @_; - - # This will join in map_qa_contact for us. - $self->_add_extra_column('qa_contact'); - $args->{full_field} = "COALESCE(map_qa_contact.login_name,'')"; -} - sub _cc_pronoun { my ($self, $args) = @_; my ($full_field, $value) = @$args{qw(full_field value)}; @@ -1945,6 +1887,48 @@ sub _cc_exact_group { } } +# XXX This should probably be merged with cc_pronoun. +sub _commenter_pronoun { + my ($self, $args) = @_; + my $value = $args->{value}; + my $user = $self->_user; + + if ($value =~ /^(%\w+%)$/) { + $args->{value} = pronoun($1, $user); + $args->{quoted} = $args->{value}; + $args->{full_field} = "profiles.userid"; + } +} + +##################################################################### +# Search Functions +##################################################################### + +sub _invalid_combination { + my ($self, $args) = @_; + my ($field, $operator) = @$args{qw(field operator)}; + ThrowUserError('search_field_operator_invalid', + { field => $field, operator => $operator }); +} + +sub _contact_nonchanged { + my ($self, $args) = @_; + my $field = $args->{field}; + + $args->{full_field} = "profiles.login_name"; + $self->_do_operator_function($args); + my $term = $args->{term}; + $args->{term} = "bugs.$field IN (SELECT userid FROM profiles WHERE $term)"; +} + +sub _qa_contact_nonchanged { + my ($self, $args) = @_; + + # This will join in map_qa_contact for us. + $self->_add_extra_column('qa_contact'); + $args->{full_field} = "COALESCE(map_qa_contact.login_name,'')"; +} + sub _cc_nonchanged { my ($self, $args) = @_; my ($chart_id, $sequence, $field, $full_field, $operator, $joins) = @@ -2053,30 +2037,6 @@ sub _content_matches { COLUMNS->{'relevance'}->{name} = $select_term; } -sub _timestamp_translate { - my ($self, $args) = @_; - my $value = $args->{value}; - my $dbh = Bugzilla->dbh; - - return if $value !~ /^[\+\-]?\d+[hdwmy]$/i; - - $args->{value} = SqlifyDate($value); - $args->{quoted} = $dbh->quote($args->{value}); -} - -# XXX This should probably be merged with cc_pronoun. -sub _commenter_pronoun { - my ($self, $args) = @_; - my $value = $args->{value}; - my $user = $self->_user; - - if ($value =~ /^(%\w+%)$/) { - $args->{value} = pronoun($1, $user); - $args->{quoted} = $args->{value}; - $args->{full_field} = "profiles.userid"; - } -} - sub _commenter { my ($self, $args) = @_; my ($chart_id, $sequence, $joins, $field, $full_field, $operator) = @@ -2824,4 +2784,51 @@ sub _changedby { $args->{term} = "$table.bug_when IS NOT NULL"; } +###################### +# Public Subroutines # +###################### + +# Validate that the query type is one we can deal with +sub IsValidQueryType +{ + my ($queryType) = @_; + if (grep { $_ eq $queryType } qw(specific advanced)) { + return 1; + } + return 0; +} + +# Splits out "asc|desc" from a sort order item. +sub split_order_term { + my $fragment = shift; + $fragment =~ /^(.+?)(?:\s+(ASC|DESC))?$/i; + my ($column_name, $direction) = (lc($1), uc($2 || '')); + return wantarray ? ($column_name, $direction) : $column_name; +} + +# Used to translate old SQL fragments from buglist.cgi's "order" argument +# into our modern field IDs. +sub translate_old_column { + my ($column) = @_; + # All old SQL fragments have a period in them somewhere. + return $column if $column !~ /\./; + + if ($column =~ /\bAS\s+(\w+)$/i) { + return $1; + } + # product, component, classification, assigned_to, qa_contact, reporter + elsif ($column =~ /map_(\w+?)s?\.(login_)?name/i) { + return $1; + } + + # If it doesn't match the regexps above, check to see if the old + # SQL fragment matches the SQL of an existing column + foreach my $key (%{ COLUMNS() }) { + next unless exists COLUMNS->{$key}->{name}; + return $key if COLUMNS->{$key}->{name} eq $column; + } + + return $column; +} + 1; |