summaryrefslogtreecommitdiffstats
path: root/extensions/ProdCompSearch/lib/WebService.pm
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/ProdCompSearch/lib/WebService.pm')
-rw-r--r--extensions/ProdCompSearch/lib/WebService.pm120
1 files changed, 120 insertions, 0 deletions
diff --git a/extensions/ProdCompSearch/lib/WebService.pm b/extensions/ProdCompSearch/lib/WebService.pm
new file mode 100644
index 000000000..3f8f0b75e
--- /dev/null
+++ b/extensions/ProdCompSearch/lib/WebService.pm
@@ -0,0 +1,120 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Extension::ProdCompSearch::WebService;
+
+use strict;
+use warnings;
+
+use base qw(Bugzilla::WebService);
+
+use Bugzilla::Error;
+use Bugzilla::Util qw(detaint_natural trick_taint trim);
+
+sub prod_comp_search {
+ my ($self, $params) = @_;
+ my $user = Bugzilla->user;
+ my $dbh = Bugzilla->switch_to_shadow_db();
+
+ my $search = trim($params->{'search'} || '');
+ $search || ThrowCodeError('param_required',
+ { function => 'PCS.prod_comp_search', param => 'search' });
+
+ my $limit = detaint_natural($params->{'limit'})
+ ? $dbh->sql_limit($params->{'limit'})
+ : '';
+
+ # We do this in the DB directly as we want it to be fast and
+ # not have the overhead of loading full product objects
+
+ # All products which the user has "Entry" access to.
+ my $enterable_ids = $dbh->selectcol_arrayref(
+ 'SELECT products.id FROM products
+ LEFT JOIN group_control_map
+ ON group_control_map.product_id = products.id
+ AND group_control_map.entry != 0
+ AND group_id NOT IN (' . $user->groups_as_string . ')
+ WHERE group_id IS NULL
+ AND products.isactive = 1');
+
+ if (scalar @$enterable_ids) {
+ # And all of these products must have at least one component
+ # and one version.
+ $enterable_ids = $dbh->selectcol_arrayref(
+ 'SELECT DISTINCT products.id FROM products
+ WHERE ' . $dbh->sql_in('products.id', $enterable_ids) .
+ ' AND products.id IN (SELECT DISTINCT components.product_id
+ FROM components
+ WHERE components.isactive = 1)
+ AND products.id IN (SELECT DISTINCT versions.product_id
+ FROM versions
+ WHERE versions.isactive = 1)');
+ }
+
+ return { products => [] } if !scalar @$enterable_ids;
+
+ trick_taint($search);
+ my @terms;
+ my @order;
+
+ if ($search =~ /^(.*?)::(.*)$/) {
+ my ($product, $component) = (trim($1), trim($2));
+ push @terms, _build_terms($product, 1, 0);
+ push @terms, _build_terms($component, 0, 1);
+ push @order, "products.name != " . $dbh->quote($product) if $product ne '';
+ push @order, "components.name != " . $dbh->quote($component) if $component ne '';
+ push @order, "products.name";
+ push @order, "components.name";
+ } else {
+ push @terms, _build_terms($search, 1, 1);
+ push @order, "products.name != " . $dbh->quote($search);
+ push @order, "components.name != " . $dbh->quote($search);
+ push @order, "products.name";
+ push @order, "components.name";
+ }
+ return { products => [] } if !scalar @terms;
+
+ # To help mozilla staff file bmo administration bugs into the right
+ # component, sort bmo first when searching for 'bugzilla'
+ if ($search =~ /bugzilla/i && $search !~ /^bugzilla\s*::/i
+ && ($user->in_group('mozilla-corporation') || $user->in_group('mozilla-foundation')))
+ {
+ unshift @order, "products.name != 'bugzilla.mozilla.org'";
+ }
+
+ my $products = $dbh->selectall_arrayref("
+ SELECT products.name AS product,
+ components.name AS component
+ FROM products
+ INNER JOIN components ON products.id = components.product_id
+ WHERE (" . join(" AND ", @terms) . ")
+ AND products.id IN (" . join(",", @$enterable_ids) . ")
+ ORDER BY " . join(", ", @order) . " $limit",
+ { Slice => {} });
+
+ return { products => $products };
+}
+
+sub _build_terms {
+ my ($query, $product, $component) = @_;
+ my $dbh = Bugzilla->dbh();
+
+ my @fields;
+ push @fields, 'products.name', 'products.description' if $product;
+ push @fields, 'components.name', 'components.description' if $component;
+ # note: CONCAT_WS is MySQL specific
+ my $field = "CONCAT_WS(' ', ". join(',', @fields) . ")";
+
+ my @terms;
+ foreach my $word (split(/[\s,]+/, $query)) {
+ push(@terms, $dbh->sql_iposition($dbh->quote($word), $field) . " > 0")
+ if $word ne '';
+ }
+ return @terms;
+}
+
+1;