mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
Support conjunctive keyword search in RPC interface
Newly supported API Version 6 modifies `type=search` for _by_ type `name-desc`: it now behaves the same as `name-desc` search through the https://aur.archlinux.org/packages/ search page. Search for packages containing the literal keyword `blah blah` AND `haha`: https://aur.archlinux.org/rpc/?v=6&type=search&arg="blah blah"%20haha Search for packages containing the literal keyword `abc 123`: https://aur.archlinux.org/rpc/?v=6&type=search&arg="abc 123" The following example searches for packages that contain `blah` AND `abc`: https://aur.archlinux.org/rpc/?v=6&type=search&arg=blah%20abc The legacy method still searches for packages that contain `blah abc`: https://aur.archlinux.org/rpc/?v=5&type=search&arg=blah%20abc https://aur.archlinux.org/rpc/?v=5&type=search&arg=blah%20abc API Version 6 is currently only considered during a `search` of `name-desc`. Note: This change was written as a solution to https://bugs.archlinux.org/task/49133. PS: + Some spacing issues fixed in comments. Signed-off-by: Kevin Morris <kevr.gtalk@gmail.com> Signed-off-by: Lukas Fleischer <lfleischer@archlinux.org>
This commit is contained in:
parent
239988def7
commit
efe99dc16f
3 changed files with 43 additions and 24 deletions
|
@ -39,6 +39,10 @@ Examples
|
||||||
`/rpc/?v=5&type=search&by=makedepends&arg=boost`
|
`/rpc/?v=5&type=search&by=makedepends&arg=boost`
|
||||||
`search` with callback::
|
`search` with callback::
|
||||||
`/rpc/?v=5&type=search&arg=foobar&callback=jsonp1192244621103`
|
`/rpc/?v=5&type=search&arg=foobar&callback=jsonp1192244621103`
|
||||||
|
`search` with API Version 6 for packages containing `cookie` AND `milk`::
|
||||||
|
`/rpc/?v=6&type=search&arg=cookie%20milk`
|
||||||
|
`search` with API Version 6 for packages containing `cookie milk`::
|
||||||
|
`/rpc/?v=6&type=search&arg="cookie milk"`
|
||||||
`info`::
|
`info`::
|
||||||
`/rpc/?v=5&type=info&arg[]=foobar`
|
`/rpc/?v=5&type=info&arg[]=foobar`
|
||||||
`info` with multiple packages::
|
`info` with multiple packages::
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
include_once("aur.inc.php");
|
include_once("aur.inc.php");
|
||||||
|
include_once("pkgfuncs.inc.php");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This class defines a remote interface for fetching data from the AUR using
|
* This class defines a remote interface for fetching data from the AUR using
|
||||||
|
@ -80,7 +81,7 @@ class AurJSON {
|
||||||
if (isset($http_data['v'])) {
|
if (isset($http_data['v'])) {
|
||||||
$this->version = intval($http_data['v']);
|
$this->version = intval($http_data['v']);
|
||||||
}
|
}
|
||||||
if ($this->version < 1 || $this->version > 5) {
|
if ($this->version < 1 || $this->version > 6) {
|
||||||
return $this->json_error('Invalid version specified.');
|
return $this->json_error('Invalid version specified.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +141,7 @@ class AurJSON {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if an IP needs to be rate limited.
|
* Check if an IP needs to be rate limited.
|
||||||
*
|
*
|
||||||
* @param $ip IP of the current request
|
* @param $ip IP of the current request
|
||||||
*
|
*
|
||||||
|
@ -192,7 +193,7 @@ class AurJSON {
|
||||||
$value = get_cache_value('ratelimit-ws:' . $ip, $status);
|
$value = get_cache_value('ratelimit-ws:' . $ip, $status);
|
||||||
if (!$status || ($status && $value < $deletion_time)) {
|
if (!$status || ($status && $value < $deletion_time)) {
|
||||||
if (set_cache_value('ratelimit-ws:' . $ip, $time, $window_length) &&
|
if (set_cache_value('ratelimit-ws:' . $ip, $time, $window_length) &&
|
||||||
set_cache_value('ratelimit:' . $ip, 1, $window_length)) {
|
set_cache_value('ratelimit:' . $ip, 1, $window_length)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -370,7 +371,7 @@ class AurJSON {
|
||||||
} elseif ($this->version >= 2) {
|
} elseif ($this->version >= 2) {
|
||||||
if ($this->version == 2 || $this->version == 3) {
|
if ($this->version == 2 || $this->version == 3) {
|
||||||
$fields = implode(',', self::$fields_v2);
|
$fields = implode(',', self::$fields_v2);
|
||||||
} else if ($this->version == 4 || $this->version == 5) {
|
} else if ($this->version >= 4 && $this->version <= 6) {
|
||||||
$fields = implode(',', self::$fields_v4);
|
$fields = implode(',', self::$fields_v4);
|
||||||
}
|
}
|
||||||
$query = "SELECT {$fields} " .
|
$query = "SELECT {$fields} " .
|
||||||
|
@ -492,13 +493,21 @@ class AurJSON {
|
||||||
if (strlen($keyword_string) < 2) {
|
if (strlen($keyword_string) < 2) {
|
||||||
return $this->json_error('Query arg too small.');
|
return $this->json_error('Query arg too small.');
|
||||||
}
|
}
|
||||||
$keyword_string = $this->dbh->quote("%" . addcslashes($keyword_string, '%_') . "%");
|
|
||||||
|
|
||||||
if ($search_by === 'name') {
|
if ($this->version >= 6 && $search_by === 'name-desc') {
|
||||||
$where_condition = "(Packages.Name LIKE $keyword_string)";
|
$where_condition = construct_keyword_search($this->dbh,
|
||||||
} else if ($search_by === 'name-desc') {
|
$keyword_string, true, false);
|
||||||
$where_condition = "(Packages.Name LIKE $keyword_string OR ";
|
} else {
|
||||||
$where_condition .= "Description LIKE $keyword_string)";
|
$keyword_string = $this->dbh->quote(
|
||||||
|
"%" . addcslashes($keyword_string, '%_') . "%");
|
||||||
|
|
||||||
|
if ($search_by === 'name') {
|
||||||
|
$where_condition = "(Packages.Name LIKE $keyword_string)";
|
||||||
|
} else if ($search_by === 'name-desc') {
|
||||||
|
$where_condition = "(Packages.Name LIKE $keyword_string ";
|
||||||
|
$where_condition .= "OR Description LIKE $keyword_string)";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else if ($search_by === 'maintainer') {
|
} else if ($search_by === 'maintainer') {
|
||||||
if (empty($keyword_string)) {
|
if (empty($keyword_string)) {
|
||||||
|
|
|
@ -696,8 +696,10 @@ function pkg_search_page($params, $show_headers=true, $SID="") {
|
||||||
$q_where .= "AND (PackageBases.Name LIKE " . $dbh->quote($K) . ") ";
|
$q_where .= "AND (PackageBases.Name LIKE " . $dbh->quote($K) . ") ";
|
||||||
}
|
}
|
||||||
elseif (isset($params["SeB"]) && $params["SeB"] == "k") {
|
elseif (isset($params["SeB"]) && $params["SeB"] == "k") {
|
||||||
/* Search by keywords. */
|
/* Search by name. */
|
||||||
$q_where .= construct_keyword_search($dbh, $params['K'], false);
|
$q_where .= "AND (";
|
||||||
|
$q_where .= construct_keyword_search($dbh, $params['K'], false, true);
|
||||||
|
$q_where .= ") ";
|
||||||
}
|
}
|
||||||
elseif (isset($params["SeB"]) && $params["SeB"] == "N") {
|
elseif (isset($params["SeB"]) && $params["SeB"] == "N") {
|
||||||
/* Search by name (exact match). */
|
/* Search by name (exact match). */
|
||||||
|
@ -709,7 +711,9 @@ function pkg_search_page($params, $show_headers=true, $SID="") {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Keyword search (default). */
|
/* Keyword search (default). */
|
||||||
$q_where .= construct_keyword_search($dbh, $params['K'], true);
|
$q_where .= "AND (";
|
||||||
|
$q_where .= construct_keyword_search($dbh, $params['K'], true, true);
|
||||||
|
$q_where .= ") ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,10 +836,11 @@ function pkg_search_page($params, $show_headers=true, $SID="") {
|
||||||
* @param handle $dbh Database handle
|
* @param handle $dbh Database handle
|
||||||
* @param string $keywords The search term
|
* @param string $keywords The search term
|
||||||
* @param bool $namedesc Search name and description fields
|
* @param bool $namedesc Search name and description fields
|
||||||
|
* @param bool $keyword Search packages with a matching PackageBases.Keyword
|
||||||
*
|
*
|
||||||
* @return string WHERE part of the SQL clause
|
* @return string WHERE part of the SQL clause
|
||||||
*/
|
*/
|
||||||
function construct_keyword_search($dbh, $keywords, $namedesc) {
|
function construct_keyword_search($dbh, $keywords, $namedesc, $keyword=false) {
|
||||||
$count = 0;
|
$count = 0;
|
||||||
$where_part = "";
|
$where_part = "";
|
||||||
$q_keywords = "";
|
$q_keywords = "";
|
||||||
|
@ -860,13 +865,18 @@ function construct_keyword_search($dbh, $keywords, $namedesc) {
|
||||||
|
|
||||||
$term = "%" . addcslashes($term, '%_') . "%";
|
$term = "%" . addcslashes($term, '%_') . "%";
|
||||||
$q_keywords .= $op . " (";
|
$q_keywords .= $op . " (";
|
||||||
|
$q_keywords .= "Packages.Name LIKE " . $dbh->quote($term) . " ";
|
||||||
if ($namedesc) {
|
if ($namedesc) {
|
||||||
$q_keywords .= "Packages.Name LIKE " . $dbh->quote($term) . " OR ";
|
$q_keywords .= "OR Description LIKE " . $dbh->quote($term) . " ";
|
||||||
$q_keywords .= "Description LIKE " . $dbh->quote($term) . " OR ";
|
}
|
||||||
|
|
||||||
|
if ($keyword) {
|
||||||
|
$q_keywords .= "OR EXISTS (SELECT * FROM PackageKeywords WHERE ";
|
||||||
|
$q_keywords .= "PackageKeywords.PackageBaseID = Packages.PackageBaseID AND ";
|
||||||
|
$q_keywords .= "PackageKeywords.Keyword LIKE " . $dbh->quote($term) . ")) ";
|
||||||
|
} else {
|
||||||
|
$q_keywords .= ") ";
|
||||||
}
|
}
|
||||||
$q_keywords .= "EXISTS (SELECT * FROM PackageKeywords WHERE ";
|
|
||||||
$q_keywords .= "PackageKeywords.PackageBaseID = Packages.PackageBaseID AND ";
|
|
||||||
$q_keywords .= "PackageKeywords.Keyword LIKE " . $dbh->quote($term) . ")) ";
|
|
||||||
|
|
||||||
$count++;
|
$count++;
|
||||||
if ($count >= 20) {
|
if ($count >= 20) {
|
||||||
|
@ -875,11 +885,7 @@ function construct_keyword_search($dbh, $keywords, $namedesc) {
|
||||||
$op = "AND ";
|
$op = "AND ";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($q_keywords)) {
|
return $q_keywords;
|
||||||
$where_part = "AND (" . $q_keywords . ") ";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $where_part;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Reference in a new issue