Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 296930 Details for
Bug 427882
XMLRPC function runQuery()
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Patch to add Bug.search capability to WebServices API (v2)
bug_search.patch (text/plain), 34.50 KB, created by
David Lawrence
on 2008-03-05 20:42:44 UTC
(
hide
)
Description:
Patch to add Bug.search capability to WebServices API (v2)
Filename:
MIME Type:
Creator:
David Lawrence
Created:
2008-03-05 20:42:44 UTC
Size:
34.50 KB
patch
obsolete
>Index: buglist.cgi >=================================================================== >RCS file: /cvs/qa/rh_bugzilla_3/buglist.cgi,v >retrieving revision 1.8 >diff -u -p -r1.8 buglist.cgi >--- buglist.cgi 27 Feb 2008 21:50:21 -0000 1.8 >+++ buglist.cgi 5 Mar 2008 20:38:33 -0000 >@@ -598,96 +598,9 @@ if (!$params->param('query_format')) { > $buffer = $params->query_string; > } > >-################################################################################ >-# Column Definition >-################################################################################ >- >-# Define the columns that can be selected in a query and/or displayed in a bug >-# list. Column records include the following fields: >-# >-# 1. ID: a unique identifier by which the column is referred in code; >-# >-# 2. Name: The name of the column in the database (may also be an expression >-# that returns the value of the column); >-# >-# 3. Title: The title of the column as displayed to users. >-# >-# Note: There are a few hacks in the code that deviate from these definitions. >-# In particular, when the list is sorted by the "votes" field the word >-# "DESC" is added to the end of the field to sort in descending order, >-# and the redundant short_desc column is removed when the client >-# requests "all" columns. >-# Note: For column names using aliasing (SQL "<field> AS <alias>"), the column >-# ID needs to be identical to the field ID for list ordering to work. >- >-local our $columns = {}; >-sub DefineColumn { >- my ($id, $name, $title) = @_; >- $columns->{$id} = { 'name' => $name , 'title' => $title }; >-} >- >-# Column: ID Name Title >-DefineColumn("bug_id" , "bugs.bug_id" , "ID" ); >-DefineColumn("alias" , "bugs.alias" , "Alias" ); >-DefineColumn("opendate" , "bugs.creation_ts" , "Opened" ); >-DefineColumn("changeddate" , "bugs.delta_ts" , "Changed" ); >-DefineColumn("bug_severity" , "bugs.bug_severity" , "Severity" ); >-DefineColumn("priority" , "bugs.priority" , "Priority" ); >-DefineColumn("rep_platform" , "bugs.rep_platform" , "Hardware" ); >-DefineColumn("assigned_to" , "map_assigned_to.login_name" , "Assignee" ); >-DefineColumn("reporter" , "map_reporter.login_name" , "Reporter" ); >-DefineColumn("qa_contact" , "map_qa_contact.login_name" , "QA Contact" ); >-if ($format->{'extension'} eq 'html') { >- DefineColumn("assigned_to_realname", "CASE WHEN map_assigned_to.realname = '' THEN map_assigned_to.login_name ELSE map_assigned_to.realname END AS assigned_to_realname", "Assignee" ); >- DefineColumn("reporter_realname" , "CASE WHEN map_reporter.realname = '' THEN map_reporter.login_name ELSE map_reporter.realname END AS reporter_realname" , "Reporter" ); >- DefineColumn("qa_contact_realname" , "CASE WHEN map_qa_contact.realname = '' THEN map_qa_contact.login_name ELSE map_qa_contact.realname END AS qa_contact_realname" , "QA Contact"); >-} else { >- DefineColumn("assigned_to_realname", "map_assigned_to.realname AS assigned_to_realname", "Assignee" ); >- DefineColumn("reporter_realname" , "map_reporter.realname AS reporter_realname" , "Reporter" ); >- DefineColumn("qa_contact_realname" , "map_qa_contact.realname AS qa_contact_realname" , "QA Contact"); >-} >-DefineColumn("bug_status" , "bugs.bug_status" , "Status" ); >-DefineColumn("resolution" , "bugs.resolution" , "Resolution" ); >-DefineColumn("short_short_desc" , "bugs.short_desc" , "Summary" ); >-DefineColumn("short_desc" , "bugs.short_desc" , "Summary" ); >-DefineColumn("status_whiteboard" , "bugs.status_whiteboard" , "Whiteboard" ); >-# REDHAT EXTENSION START 406151 >-DefineColumn("devel_whiteboard" , "bugs.devel_whiteboard" , "Devel Whiteboard" ); >-DefineColumn("qa_whiteboard" , "bugs.qa_whiteboard" , "QA Whiteboard" ); >-DefineColumn("internal_whiteboard" , "bugs.internal_whiteboard" , "Internal Whiteboard"); >-DefineColumn("fixed_in" , "bugs.fixed_in" , "Fixed In" ); >-# REDHAT EXTENSION END 406151 >-DefineColumn("component" , "map_components.name" , "Component" ); >-DefineColumn("product" , "map_products.name" , "Product" ); >-DefineColumn("classification" , "map_classifications.name" , "Classification" ); >-DefineColumn("version" , "bugs.version" , "Version" ); >-DefineColumn("op_sys" , "bugs.op_sys" , "OS" ); >-DefineColumn("target_milestone" , "bugs.target_milestone" , "Target Milestone" ); >-DefineColumn("votes" , "bugs.votes" , "Votes" ); >-DefineColumn("keywords" , "bugs.keywords" , "Keywords" ); >-DefineColumn("estimated_time" , "bugs.estimated_time" , "Estimated Hours" ); >-DefineColumn("remaining_time" , "bugs.remaining_time" , "Remaining Hours" ); >-DefineColumn("actual_time" , "(SUM(ldtime.work_time)*COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id)) AS actual_time", "Actual Hours"); >-DefineColumn("percentage_complete", >- "(CASE WHEN (SUM(ldtime.work_time)*COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id)) " . >- " + bugs.remaining_time = 0.0 " . >- "THEN 0.0 " . >- "ELSE 100*((SUM(ldtime.work_time)*COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id)) " . >- " /((SUM(ldtime.work_time)*COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id)) + bugs.remaining_time)) " . >- "END) AS percentage_complete" , "% Complete"); >-DefineColumn("relevance" , "relevance" , "Relevance" ); >-DefineColumn("deadline" , $dbh->sql_date_format('bugs.deadline', '%Y-%m-%d') . " AS deadline", "Deadline"); >-# REDHAT EXTENSION START 406371 >-DefineColumn("issuetrackers" , $dbh->sql_issue_tracker_list() . " AS issuetrackers", "Issue Trackers"); >-DefineColumn("dependson" , $dbh->sql_dependson_list() . " AS dependson", "Depends On"); >-DefineColumn("blockedby" , $dbh->sql_blockedby_list() . " AS blockedby", "Blocked By"); >-DefineColumn("itmaxscore" , $dbh->sql_it_max_score() . " AS itmaxscore", "IT Max Score"); >-DefineColumn("flags" , $dbh->sql_flag_list(values(%{Bugzilla->user->groups})) . " AS flags", "Flags" ); >-# REDHAT EXTENSION END 406371 >- >-foreach my $field (Bugzilla->active_custom_fields) { >- DefineColumn($field->name, 'bugs.' . $field->name, $field->description); >-} >+# Define the columns that can be selected in a query >+# and/or displayed in a bug list. >+my $columns = Bugzilla::Search->columns($format); > > ################################################################################ > # Display Column Determination >Index: Bugzilla/Search.pm >=================================================================== >RCS file: /cvs/qa/rh_bugzilla_3/Bugzilla/Search.pm,v >retrieving revision 1.14 >diff -u -p -r1.14 Search.pm >--- Bugzilla/Search.pm 29 Feb 2008 22:17:54 -0000 1.14 >+++ Bugzilla/Search.pm 5 Mar 2008 20:38:33 -0000 >@@ -1056,6 +1056,127 @@ sub _split_words_into_like { > return @words; > } > >+################################################################################ >+# Column Definition >+################################################################################ >+ >+# Define the columns that can be selected in a query and/or displayed in a bug >+# list. Column records include the following fields: >+# >+# 1. ID: a unique identifier by which the column is referred in code; >+# >+# 2. Name: The name of the column in the database (may also be an expression >+# that returns the value of the column); >+# >+# 3. Title: The title of the column as displayed to users. >+# >+# Note: There are a few hacks in the code that deviate from these definitions. >+# In particular, when the list is sorted by the "votes" field the word >+# "DESC" is added to the end of the field to sort in descending order, >+# and the redundant short_desc column is removed when the client >+# requests "all" columns. >+# Note: For column names using aliasing (SQL "<field> AS <alias>"), the column >+# ID needs to be identical to the field ID for list ordering to work. >+ >+sub columns { >+ my ($self, $format) = @_; >+ my $dbh = Bugzilla->dbh; >+ >+ ### ID Name Title >+ my $columns = { >+ bug_id => { name => "bugs.bug_id", title => "ID" }, >+ alias => { name => "bugs.alias", title => "Alias" }, >+ opendate => { name => "bugs.creation_ts", title => "Opened" }, >+ changeddate => { name => "bugs.delta_ts", title => "Changed" }, >+ bug_severity => { name => "bugs.bug_severity", title => "Severity" }, >+ priority => { name => "bugs.priority", title => "Priority" }, >+ rep_platform => { name => "bugs.rep_platform", title => "Hardware" }, >+ assigned_to => { name => "map_assigned_to.login_name", title => "Assignee" }, >+ reporter => { name => "map_reporter.login_name", title => "Reporter" }, >+ qa_contact => { name => "map_qa_contact.login_name", title => "QA Contact" }, >+ bug_status => { name => "bugs.bug_status", title => "Status" }, >+ resolution => { name => "bugs.resolution", title => "Resolution" }, >+ short_short_desc => { name => "bugs.short_desc", title => "Summary" }, >+ short_desc => { name => "bugs.short_desc", title => "Summary" }, >+ status_whiteboard => { name => "bugs.status_whiteboard", title => "Whiteboard" }, >+ component => { name => "map_components.name", title => "Component" }, >+ product => { name => "map_products.name", title => "Product" }, >+ classification => { name => "map_classifications.name", title => "Classification" }, >+ version => { name => "bugs.version", title => "Version" }, >+ op_sys => { name => "bugs.op_sys", title => "OS" }, >+ target_milestone => { name => "bugs.target_milestone", title => "Target Milestone" }, >+ votes => { name => "bugs.votes", title => "Votes" }, >+ keywords => { name => "bugs.keywords", title => "Keywords" }, >+ estimated_time => { name => "bugs.estimated_time", title => "Estimated Hours" }, >+ remaining_time => { name => "bugs.remaining_time", title => "Remaining Hours" }, >+ actual_time => { >+ name => "(SUM(ldtime.work_time)*COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id)) AS actual_time", >+ title => "Actual Hours" }, >+ percentage_complete => { >+ name => "(CASE WHEN (SUM(ldtime.work_time)*COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id)) " . >+ " + bugs.remaining_time = 0.0 " . >+ "THEN 0.0 " . >+ "ELSE 100*((SUM(ldtime.work_time)*COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id)) " . >+ "/((SUM(ldtime.work_time)*COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id)) + bugs.remaining_time)) " . >+ "END) AS percentage_complete", >+ title => "% Complete" }, >+ relevance => { name => "relevance", title => "Relevance" }, >+ deadline => { name => $dbh->sql_date_format('bugs.deadline'=> '%Y-%m-%d') . " AS deadline", >+ title => "Deadline" }, >+ >+ # REDHAT EXTENSION START 406151 >+ devel_whiteboard => { name => "bugs.devel_whiteboard", title => "Devel Whiteboard" }, >+ qa_whiteboard => { name => "bugs.qa_whiteboard", title => "QA Whiteboard" }, >+ internal_whiteboard => { name => "bugs.internal_whiteboard", title => "Internal Whiteboard" }, >+ fixed_in => { name => "bugs.fixed_in", title => "Fixed In" }, >+ # REDHAT EXTENSION END 406151 >+ >+ # REDHAT EXTENSION START 406371 >+ issuetrackers => { name => $dbh->sql_issue_tracker_list() . " AS issuetrackers", >+ title => "Issue Trackers" }, >+ dependson => { name => $dbh->sql_dependson_list() . " AS dependson", >+ title => "Depends On" }, >+ blockedby => { name => $dbh->sql_blockedby_list() . " AS blockedby", >+ title => "Blocked By" }, >+ itmaxscore => { name => $dbh->sql_it_max_score() . " AS itmaxscore", >+ title => "IT Max Score" }, >+ flags => { name => $dbh->sql_flag_list(values(%{Bugzilla->user->groups})) . " AS flags", >+ title => "Flags" }, >+ # REDHAT EXTENSION END 406371 >+ }; >+ >+ if ($format->{'extension'} eq 'html') { >+ $columns->{"assigned_to_realname"} = >+ { name => "CASE WHEN map_assigned_to.realname = '' THEN map_assigned_to.login_name " . >+ "ELSE map_assigned_to.realname END AS assigned_to_realname", >+ title => "Assignee" }; >+ $columns->{"reporter_realname"} = >+ { name => "CASE WHEN map_reporter.realname = '' THEN map_reporter.login_name " . >+ "ELSE map_reporter.realname END AS reporter_realname", >+ title => "Reporter" }; >+ $columns->{"qa_contact_realname"} = >+ { name => "CASE WHEN map_qa_contact.realname = '' THEN map_qa_contact.login_name " . >+ "ELSE map_qa_contact.realname END AS qa_contact_realname", >+ title => "QA Contact" }; >+ } else { >+ $columns->{"assigned_to_realname"} = >+ { name => "map_assigned_to.realname AS assigned_to_realname", >+ title => "Assignee" }; >+ $columns->{"reporter_realname"} = >+ { name => "map_reporter.realname AS reporter_realname", >+ title => "Reporter" }; >+ $columns->{"qa_contact_realname"} = >+ { name => "map_qa_contact.realname AS qa_contact_realname", >+ title => "QA Contact" }; >+ } >+ >+ foreach my $field (Bugzilla->get_fields({ custom => 1, obsolete => 0})) { >+ $columns->{$field->name} = { name => 'bugs.' . $field->name, title => $field->description }; >+ } >+ >+ return $columns; >+} >+ > ##################################################################### > # Search Functions > ##################################################################### >Index: Bugzilla/Search/Quicksearch.pm >=================================================================== >RCS file: /cvs/qa/rh_bugzilla_3/Bugzilla/Search/Quicksearch.pm,v >retrieving revision 1.3 >diff -u -p -r1.3 Quicksearch.pm >--- Bugzilla/Search/Quicksearch.pm 8 Jan 2008 02:06:58 -0000 1.3 >+++ Bugzilla/Search/Quicksearch.pm 5 Mar 2008 20:38:33 -0000 >@@ -112,7 +112,7 @@ use constant COMPONENT_EXCEPTIONS => ( > our ($chart, $and, $or); > > sub quicksearch { >- my ($searchstring) = (@_); >+ my ($searchstring, $noredirect) = (@_); > my $cgi = Bugzilla->cgi; > my $urlbase = correct_urlbase(); > >@@ -130,7 +130,7 @@ sub quicksearch { > # Allow separation by comma or whitespace. > $searchstring =~ s/[,\s]+/,/g; > >- if (index($searchstring, ',') < $[) { >+ if (index($searchstring, ',') < $[ && !$noredirect) { > # Single bug number; shortcut to show_bug.cgi. > print $cgi->redirect(-uri => "${urlbase}show_bug.cgi?id=$searchstring"); > exit; >Index: Bugzilla/WebService/Bug.pm >=================================================================== >RCS file: /cvs/qa/rh_bugzilla_3/Bugzilla/WebService/Bug.pm,v >retrieving revision 1.6 >diff -u -p -r1.6 Bug.pm >--- Bugzilla/WebService/Bug.pm 29 Feb 2008 04:01:24 -0000 1.6 >+++ Bugzilla/WebService/Bug.pm 5 Mar 2008 20:38:33 -0000 >@@ -16,6 +16,7 @@ > # Max Kanat-Alexander <mkanat@bugzilla.org> > # Mads Bondo Dydensborg <mbd@dbc.dk> > # Tsahi Asher <tsahi_75@yahoo.com> >+# Dave Lawrence <dkl@redhat.com> > > package Bugzilla::WebService::Bug; > >@@ -30,6 +31,11 @@ use Bugzilla::WebService::Constants; > use Bugzilla::Bug; > use Bugzilla::BugMail; > use Bugzilla::Constants; >+use Bugzilla::CGI; >+use Bugzilla::Search; >+use Bugzilla::Search::Quicksearch; >+use Bugzilla::Search::Saved; >+use Bugzilla::Util; > > ############# > # Constants # >@@ -241,6 +247,302 @@ sub add_comment { > return undef; > } > >+sub search { >+ my ($self, $params) = @_; >+ my $dbh = Bugzilla->dbh; >+ my $search_params; >+ >+ # HACK: We need to do this otherwise CGI always treats as POST >+ delete $ENV{CONTENT_TYPE}; >+ >+ # Determine whether this is a quicksearch query. Also set noredirect to true in case it is a single bug id. >+ if (defined($params->{quicksearch})) { >+ my $quick_search_data = quicksearch($params->{quicksearch}, 1); >+ $search_params = Bugzilla::CGI->new($quick_search_data); >+ } >+ >+ # Load previously saved query and use it >+ if (defined($params->{savedsearch})) { >+ Bugzilla->user->id || ThrowUserError("saved_search_login_required"); >+ >+ my $saved_search = Bugzilla::Search::Saved->new( >+ { name => $params->{savedsearch}, >+ userid => Bugzilla->user->id } >+ ); >+ >+ $saved_search || ThrowUserError("missing_query"); >+ >+ # Clean out any empty variables in the stored query. >+ # Should only affect pre-3.x queries as new queries are cleaned >+ # before they go into the database >+ my $saved_search_data = Bugzilla->cgi->clean_search_url($saved_search->url); >+ if ($saved_search_data ne "") { >+ $search_params = Bugzilla::CGI->new($saved_search_data); >+ } >+ } >+ >+ # We should have already looked at these so delete them >+ delete $params->{savedsearch}; >+ delete $params->{quicksearch}; >+ >+ # ThrowUserError if we do not have any search criteria >+ if (!%$params && (! defined $search_params || !$search_params->param())) { >+ ThrowUserError("buglist_parameters_required"); >+ } >+ >+ # If configured to not allow empty words, reject empty searches from the >+ # Find a Specific Bug search form, including words being a single or >+ # several consecutive whitespaces only. >+ if (!Bugzilla->params->{'specific_search_allow_empty_words'} >+ && defined $params->{content} && $params->{content} =~ /^\s*$/) { >+ ThrowUserError("buglist_parameters_required"); >+ } >+ >+ # Figure out whether or not the user is doing a fulltext search. If not, >+ # we'll remove the relevance column from the lists of columns to display >+ # and order by, since relevance only exists when doing a fulltext search. >+ my $fulltext = 0; >+ if ($params->{content}) { >+ $fulltext = 1 >+ } >+ my @charts = map(/^field(\d-\d-\d)$/ ? $1 : (), keys %{$params}); >+ foreach my $chart (@charts) { >+ if ($params->{"field$chart"} eq 'content' && $params->{"value$chart"}) { >+ $fulltext = 1; >+ last; >+ } >+ } >+ >+ # Define the columns that can be selected in a query >+ # and/or displayed in a bug list. >+ my $columns = Bugzilla::Search->columns(); >+ >+ # Determine the columns that will be displayed in the bug list via the >+ # # columnlist parameter, the user's preferences, or the default. >+ my @displaycolumns = (); >+ if (defined $params->{columnlist} and ref($params->{columnlist})) { >+ if ($params->{columnlist} eq "all") { >+ # If the value of the CGI parameter is "all", display all columns, >+ # but remove the redundant "short_desc" column. >+ @displaycolumns = grep($_ ne 'short_desc', keys(%$columns)); >+ } >+ else { >+ @displaycolumns = @{$params->{columnlist}}; >+ } >+ } >+ elsif (defined $params->{columnlist}) { >+ @displaycolumns = split(/[ ,]+/, $params->{columnlist}); >+ } >+ else { >+ # Use the default list of columns. >+ @displaycolumns = DEFAULT_COLUMN_LIST; >+ } >+ >+ # Weed out columns that don't actually exist to prevent the user >+ # from hacking their column list cookie to grab data to which they >+ # should not have access. Detaint the data along the way. >+ @displaycolumns = grep($columns->{$_} && trick_taint($_), @displaycolumns); >+ >+ # Remove the "ID" column from the list because bug IDs are always displayed >+ # and are hard-coded into the display templates. >+ @displaycolumns = grep($_ ne 'bug_id', @displaycolumns); >+ >+ # Add the votes column to the list of columns to be displayed >+ # in the bug list if the user is searching for bugs with a certain >+ # number of votes and the votes column is not already on the list. >+ >+ # Some versions of perl will taint 'votes' if this is done as a single >+ # statement, because the votes param is tainted at this point >+ my $votes = $params->{votes}; >+ $votes ||= ""; >+ if (trim($votes) && !grep($_ eq 'votes', @displaycolumns)) { >+ push(@displaycolumns, 'votes'); >+ } >+ >+ # Remove the timetracking columns if they are not a part of the group >+ # (happens if a user had access to time tracking and it was revoked/disabled) >+ if (!Bugzilla->user->in_group(Bugzilla->params->{"timetrackinggroup"})) { >+ @displaycolumns = grep($_ ne 'estimated_time', @displaycolumns); >+ @displaycolumns = grep($_ ne 'remaining_time', @displaycolumns); >+ @displaycolumns = grep($_ ne 'actual_time', @displaycolumns); >+ @displaycolumns = grep($_ ne 'percentage_complete', @displaycolumns); >+ @displaycolumns = grep($_ ne 'deadline', @displaycolumns); >+ } >+ >+ # Remove the relevance column if the user is not doing a fulltext search. >+ if (grep('relevance', @displaycolumns) && !$fulltext) { >+ @displaycolumns = grep($_ ne 'relevance', @displaycolumns); >+ } >+ >+ # REDHAT EXTENSION START 406151 >+ # Remove specific protected columns based on group permissions >+ @displaycolumns = grep($_ ne 'devel_whiteboard', @displaycolumns) if !Bugzilla->user->in_group('devel'); >+ @displaycolumns = grep($_ ne 'qa_whiteboard', @displaycolumns) if !Bugzilla->user->in_group('qa'); >+ @displaycolumns = grep($_ ne 'internal_whiteboard', @displaycolumns) if !Bugzilla->user->in_group('internalwhiteboard'); >+ # REDHAT EXTENSION END 406151 >+ >+ # The bug ID is always selected because bug IDs are always displayed. >+ my @selectcolumns = ('bug_id'); >+ >+ # if using classification, we also need to look in product.classification_id >+ if (Bugzilla->params->{"useclassification"}) { >+ push (@selectcolumns,"product"); >+ } >+ >+ # remaining and actual_time are required for percentage_complete calculation: >+ if (lsearch(\@displaycolumns, "percentage_complete") >= 0) { >+ push (@selectcolumns, "remaining_time"); >+ push (@selectcolumns, "actual_time"); >+ } >+ >+ push(@selectcolumns, @displaycolumns); >+ >+ # Convert the list of columns being selected into a list of column names. >+ my @selectnames = map($columns->{$_}->{'name'}, @selectcolumns); >+ >+ # Remove columns with no names, such as percentage_complete >+ # (or a removed *_time column due to permissions) >+ @selectnames = grep($_ ne '', @selectnames); >+ >+ my $order = $params->{order} >+ || "bugs.bug_status, bugs.priority, map_assigned_to.login_name, bugs.bug_id"; >+ >+ # Make sure ORDER BY columns are included in the field list. >+ foreach my $fragment (split(/,/, $order)) { >+ $fragment = trim($fragment); >+ if (!grep($fragment =~ /^\Q$_\E(\s+(asc|desc))?$/, @selectnames)) { >+ # Add order columns to selectnames >+ # The fragment has already been validated >+ $fragment =~ s/\s+(asc|desc)$//; >+ >+ # While newer fragments contain IDs for aliased columns, older >+ # LASTORDER cookies (or bookmarks) may contain full names. >+ # Convert them to an ID here. >+ if ($fragment =~ / AS (\w+)/) { >+ $fragment = $1; >+ } >+ >+ $fragment =~ tr/a-zA-Z\.0-9\-_//cd; >+ >+ # If the order fragment is an ID, we need its corresponding name >+ # to be in the field list. >+ if (exists($columns->{$fragment})) { >+ $fragment = $columns->{$fragment}->{'name'}; >+ } >+ >+ push @selectnames, $fragment; >+ } >+ } >+ >+ my $db_order = $order; # Copy $order into $db_order for use with SQL query >+ >+ # If we are sorting by votes, sort in descending order if no explicit >+ # sort order was given >+ $db_order =~ s/bugs.votes\s*(,|$)/bugs.votes desc$1/i; >+ >+ # the 'actual_time' field is defined as an aggregate function, but >+ # for order we just need the column name 'actual_time' >+ my $aggregate_search = quotemeta($columns->{'actual_time'}->{'name'}); >+ $db_order =~ s/$aggregate_search/actual_time/g; >+ >+ # the 'percentage_complete' field is defined as an aggregate too >+ $aggregate_search = quotemeta($columns->{'percentage_complete'}->{'name'}); >+ $db_order =~ s/$aggregate_search/percentage_complete/g; >+ >+ # Now put $db_order into a format that Bugzilla::Search can use. >+ # (We create $db_order as a string first because that's the way >+ # we did it before Bugzilla::Search took an "order" argument.) >+ my @orderstrings = split(/,\s*/, $db_order); >+ >+ # Load the CGI object with our param data since Bugzilla::Search >+ # is expecting it. >+ $search_params ||= Bugzilla::CGI->new(); >+ foreach my $key (keys %{$params}) { >+ $search_params->param(-name => $key, -value => $params->{$key}); >+ } >+ >+ # Generate the basic SQL query that will be used to generate the bug list. >+ my $search = new Bugzilla::Search('fields' => \@selectnames, >+ 'params' => $search_params, >+ 'order' => \@orderstrings); >+ my $query = $search->getSQL(); >+ >+ if (defined $params->{limit}) { >+ my $limit = $params->{limit}; >+ if (detaint_natural($limit)) { >+ $query .= " " . $dbh->sql_limit($limit); >+ } >+ } >+ elsif ($fulltext) { >+ $query .= " " . $dbh->sql_limit(FULLTEXT_BUGLIST_LIMIT); >+ } >+ >+ # Connect to the shadow database if this installation is using one to improve >+ # query performance. >+ $dbh = Bugzilla->switch_to_shadow_db(); >+ >+ # Normally, we ignore SIGTERM and SIGPIPE, but we need to >+ # respond to them here to prevent someone DOSing us by reloading a query >+ # a large number of times. >+ $::SIG{TERM} = 'DEFAULT'; >+ $::SIG{PIPE} = 'DEFAULT'; >+ >+ # Execute the query. >+ my $buglist_sth = $dbh->prepare($query); >+ $buglist_sth->execute(); >+ >+ my @bugs; >+ my @bugidlist; >+ >+ while (my @row = $buglist_sth->fetchrow_array()) { >+ my $bug = {}; # a record >+ >+ # Slurp the row of data into the record. >+ # The second from last column in the record is the number of groups >+ # to which the bug is restricted. >+ foreach my $column (@selectcolumns) { >+ $bug->{$column} = shift @row; >+ } >+ >+ $bug->{'secure_mode'} = undef; >+ >+ # Add the record to the list. >+ push(@bugs, $bug); >+ >+ # Add id to list for checking for bug privacy later >+ push(@bugidlist, $bug->{'bug_id'}); >+ } >+ >+ my %min_membercontrol; >+ if (@bugidlist) { >+ my $sth = $dbh->prepare( >+ "SELECT DISTINCT bugs.bug_id, MIN(group_control_map.membercontrol) " . >+ "FROM bugs " . >+ "INNER JOIN bug_group_map " . >+ "ON bugs.bug_id = bug_group_map.bug_id " . >+ "LEFT JOIN group_control_map " . >+ "ON group_control_map.product_id = bugs.product_id " . >+ "AND group_control_map.group_id = bug_group_map.group_id " . >+ "WHERE " . $dbh->sql_in('bugs.bug_id', \@bugidlist) . >+ $dbh->sql_group_by('bugs.bug_id')); >+ $sth->execute(); >+ while (my ($bug_id, $min_membercontrol) = $sth->fetchrow_array()) { >+ $min_membercontrol{$bug_id} = $min_membercontrol || CONTROLMAPNA; >+ } >+ foreach my $bug (@bugs) { >+ next unless defined($min_membercontrol{$bug->{'bug_id'}}); >+ if ($min_membercontrol{$bug->{'bug_id'}} == CONTROLMAPMANDATORY) { >+ $bug->{'secure_mode'} = 'implied'; >+ } >+ else { >+ $bug->{'secure_mode'} = 'manual'; >+ } >+ } >+ } >+ >+ return { sql => $query, bugs => \@bugs }; >+} >+ > 1; > > __END__ >@@ -306,7 +608,6 @@ You specified a field that doesn't exist > > =back > >- > =back > > =head2 Bug Creation and Modification >@@ -667,5 +968,72 @@ You did not have the necessary rights to > > =back > >+=item C<search> B<EXPERIMENTAL> >+ >+=over >+ >+=item B<Description> >+ >+This allows you to search the database for bugs in Bugzilla. The first argument is a >+hash containing key names similar to the form variable names generated by query.cgi. >+You may also pass in a quicksearch string similar to the Bugzilla homepage or >+pass in a savedsearch string to run one of your previously saved searches. >+ >+=item B<Params> >+ >+The first argument is a hash containing the key = value pairs that you want to >+search for in the database. You can also pass in keys called quicksearch and >+savedsearch which will populate the search criteria hash for you. >+ >+=over >+ >+=item quicksearch >+ >+C<string> Perform a quick search using keywords similar to the ones >+used on the Bugzilla home page. For more information see https://bugzilla.mozilla.org/page.cgi?id=quicksearch.html >+ >+=item savedsearch >+ >+C<string> The name of a previously saved search to execute. Must have already >+stored the query using the web UI and also requires being logged in to a Bugzilla account. >+ >+=back >+ >+=item B<Returns> >+ >+A hash containing two elements, C<sql> and C<bugs>. >+ >+=over >+ >+=item sql >+ >+C<string> The SQL generated by executing the search. >+ >+=item bugs >+ >+C<array> A list of hashes, each one containing bug data based on the columnlist >+you provided or the default columnlist. >+ >+=back >+ >+=item B<Errors> >+ >+=over >+ >+=item 507 (Search Parameters Required) >+ >+You tried to search without any search terms. >+ >+=item 508 (Login Required for Saved Searches) >+ >+You need to be logged into a valid account to execute a previously saved search. >+ >+=item 509 (Missing Query) >+ >+The saved search name was not found in the system. >+ >+=back >+ >+=back > > =back >Index: Bugzilla/WebService/Constants.pm >=================================================================== >RCS file: /cvs/qa/rh_bugzilla_3/Bugzilla/WebService/Constants.pm,v >retrieving revision 1.8 >diff -u -p -r1.8 Constants.pm >--- Bugzilla/WebService/Constants.pm 5 Mar 2008 08:43:06 -0000 1.8 >+++ Bugzilla/WebService/Constants.pm 5 Mar 2008 20:38:33 -0000 >@@ -101,7 +101,10 @@ use constant WS_ERROR_CODE => { > invalid_user_group => 504, > user_access_by_id_denied => 505, > multiple_users_update_not_allowed => 506, >- >+ buglist_parameters_required => 507, >+ saved_search_login_required => 508, >+ missing_query => 509, >+ > }; > > # These are the fallback defaults for errors not in ERROR_CODE. >Index: contrib/bz_webservice_demo.pl >=================================================================== >RCS file: /cvs/qa/rh_bugzilla_3/contrib/bz_webservice_demo.pl,v >retrieving revision 1.3 >diff -u -p -r1.3 bz_webservice_demo.pl >--- contrib/bz_webservice_demo.pl 20 Jan 2008 16:37:20 -0000 1.3 >+++ contrib/bz_webservice_demo.pl 5 Mar 2008 20:38:33 -0000 >@@ -54,6 +54,7 @@ my $legal_field_values; > my $add_comment; > my $private; > my $work_time; >+my $quicksearch; > > GetOptions('help|h|?' => \$help, > 'uri=s' => \$Bugzilla_uri, >@@ -66,7 +67,8 @@ GetOptions('help|h|?' => \$help, > 'field:s' => \$legal_field_values, > 'comment:s' => \$add_comment, > 'private:i' => \$private, >- 'worktime:f' => \$work_time >+ 'worktime:f' => \$work_time, >+ 'quicksearch:s' => \$quicksearch > ) or pod2usage({'-verbose' => 0, '-exitval' => 1}); > > =head1 OPTIONS >@@ -133,6 +135,9 @@ An optional non-zero value to specify B< > > An optional double precision number specifying the work time for B<--comment>. > >+=item --quicksearch >+ >+An optional search string to return a list of matching bugs. > > =back > >@@ -344,6 +349,36 @@ if ($add_comment) { > } > } > >+=head2 Searching for bugs >+ >+Call C<Bug.search> with a string containing search keywords to retrieve a list of >+matching bugs. >+ >+=cut >+ >+if ($quicksearch) { >+ $soapresult = $proxy->call('Bug.search', { quicksearch => $quicksearch }); >+ _die_on_fault($soapresult); >+ $result = $soapresult->result; >+ >+ if (ref($result) eq 'HASH') { >+ my $count = 1; >+ print "ID, Status, Summary\n"; >+ foreach my $bug (@{$result->{bugs}}) { >+ print "$bug->{bug_id}, $bug->{bug_status}, $bug->{short_desc}}\n"; >+ $count++; >+ } >+ print "Count: $count\n"; >+ } >+ else { >+ print "$soapresult\n"; >+ } >+} >+else { >+ print "A --quicksearch string must be supplied to search for bugs.\n"; >+} >+ >+ > =head1 NOTES > > =head2 Character Set Encoding >Index: template/en/default/global/user-error.html.tmpl >=================================================================== >RCS file: /cvs/qa/rh_bugzilla_3/template/en/default/global/user-error.html.tmpl,v >retrieving revision 1.17 >diff -u -p -r1.17 user-error.html.tmpl >--- template/en/default/global/user-error.html.tmpl 5 Mar 2008 09:03:36 -0000 1.17 >+++ template/en/default/global/user-error.html.tmpl 5 Mar 2008 20:38:33 -0000 >@@ -1616,6 +1616,11 @@ > You can not change users password or login info when changing > several users at once, as these values need to be unique for > each user. >+ >+ [% ELSIF error == "saved_search_login_required" %] >+ [% title = "Login Required for Saved Searches" %] >+ You must be logged in with a valid username to execute >+ a previous saved search. > > [% ELSE %] >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
nelhawar
: review-
dkl
: review? (
kbaker
)
Actions:
View
|
Diff
Attachments on
bug 427882
:
296412
|
296930
|
297485