Commit e8662ecd authored by Max Kanat-Alexander's avatar Max Kanat-Alexander

Bug 580174: Search.pm: Move special parsing functions around, to be more

orderly r=mkanat, a=mkanat (module owner)
parent ba3b4c64
...@@ -1629,79 +1629,11 @@ sub _pick_override_function { ...@@ -1629,79 +1629,11 @@ sub _pick_override_function {
# Search Function Helpers # # 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 { sub build_subselect {
my ($outer, $inner, $table, $cond) = @_; my ($outer, $inner, $table, $cond) = @_;
return "$outer IN (SELECT $inner FROM $table WHERE $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 # 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 # support values with commas inside of them in the standard charts, and
# still accept string values for the boolean charts (and split them on # still accept string values for the boolean charts (and split them on
...@@ -1773,67 +1705,95 @@ sub _word_terms { ...@@ -1773,67 +1705,95 @@ sub _word_terms {
return @terms; return @terms;
} }
###################### #####################################
# Public Subroutines # # "Special Parsing" Functions: Date #
###################### #####################################
# Validate that the query type is one we can deal with sub _timestamp_translate {
sub IsValidQueryType my ($self, $args) = @_;
{ my $value = $args->{value};
my ($queryType) = @_; my $dbh = Bugzilla->dbh;
if (grep { $_ eq $queryType } qw(specific advanced)) {
return 1;
}
return 0;
}
# Splits out "asc|desc" from a sort order item. return if $value !~ /^[\+\-]?\d+[hdwmy]$/i;
sub split_order_term {
my $fragment = shift; $args->{value} = SqlifyDate($value);
$fragment =~ /^(.+?)(?:\s+(ASC|DESC))?$/i; $args->{quoted} = $dbh->quote($args->{value});
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 sub SqlifyDate {
# into our modern field IDs. my ($str) = @_;
sub translate_old_column { $str = "" if !defined $str;
my ($column) = @_; if ($str eq "") {
# All old SQL fragments have a period in them somewhere. my ($sec, $min, $hour, $mday, $month, $year, $wday) = localtime(time());
return $column if $column !~ /\./; return sprintf("%4d-%02d-%02d 00:00:00", $year+1900, $month+1, $mday);
if ($column =~ /\bAS\s+(\w+)$/i) {
return $1;
} }
# product, component, classification, assigned_to, qa_contact, reporter
elsif ($column =~ /map_(\w+?)s?\.(login_)?name/i) { if ($str =~ /^(-|\+)?(\d+)([hHdDwWmMyY])$/) { # relative date
return $1; 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 it doesn't match the regexps above, check to see if the old if (!defined($date)) {
# SQL fragment matches the SQL of an existing column ThrowUserError("illegal_date", { date => $str });
foreach my $key (%{ COLUMNS() }) {
next unless exists COLUMNS->{$key}->{name};
return $key if COLUMNS->{$key}->{name} eq $column;
} }
return time2str("%Y-%m-%d %H:%M:%S", $date);
return $column;
} }
##################################################################### ######################################
# Search Functions # "Special Parsing" Functions: Users #
##################################################################### ######################################
sub _invalid_combination { sub pronoun {
my ($self, $args) = @_; my ($noun, $user) = (@_);
my ($field, $operator) = @$args{qw(field operator)}; if ($noun eq "%user%") {
ThrowUserError('search_field_operator_invalid', if ($user->id) {
{ field => $field, operator => $operator }); 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 { sub _contact_pronoun {
my ($self, $args) = @_; my ($self, $args) = @_;
my ($value, $quoted) = @$args{qw(value quoted)}; my $value = $args->{value};
my $user = $self->_user; my $user = $self->_user;
if ($value =~ /^\%group/) { if ($value =~ /^\%group/) {
...@@ -1873,24 +1833,6 @@ sub _contact_exact_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 { sub _cc_pronoun {
my ($self, $args) = @_; my ($self, $args) = @_;
my ($full_field, $value) = @$args{qw(full_field value)}; my ($full_field, $value) = @$args{qw(full_field value)};
...@@ -1945,6 +1887,48 @@ sub _cc_exact_group { ...@@ -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 { sub _cc_nonchanged {
my ($self, $args) = @_; my ($self, $args) = @_;
my ($chart_id, $sequence, $field, $full_field, $operator, $joins) = my ($chart_id, $sequence, $field, $full_field, $operator, $joins) =
...@@ -2053,30 +2037,6 @@ sub _content_matches { ...@@ -2053,30 +2037,6 @@ sub _content_matches {
COLUMNS->{'relevance'}->{name} = $select_term; 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 { sub _commenter {
my ($self, $args) = @_; my ($self, $args) = @_;
my ($chart_id, $sequence, $joins, $field, $full_field, $operator) = my ($chart_id, $sequence, $joins, $field, $full_field, $operator) =
...@@ -2824,4 +2784,51 @@ sub _changedby { ...@@ -2824,4 +2784,51 @@ sub _changedby {
$args->{term} = "$table.bug_when IS NOT NULL"; $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; 1;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment