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:
Kevin Morris 2020-07-05 18:19:06 -07:00 committed by Lukas Fleischer
parent 239988def7
commit efe99dc16f
3 changed files with 43 additions and 24 deletions

View file

@ -1,6 +1,7 @@
<?php
include_once("aur.inc.php");
include_once("pkgfuncs.inc.php");
/*
* This class defines a remote interface for fetching data from the AUR using
@ -80,7 +81,7 @@ class AurJSON {
if (isset($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.');
}
@ -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
*
@ -192,7 +193,7 @@ class AurJSON {
$value = get_cache_value('ratelimit-ws:' . $ip, $status);
if (!$status || ($status && $value < $deletion_time)) {
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;
}
} else {
@ -370,7 +371,7 @@ class AurJSON {
} elseif ($this->version >= 2) {
if ($this->version == 2 || $this->version == 3) {
$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);
}
$query = "SELECT {$fields} " .
@ -492,13 +493,21 @@ class AurJSON {
if (strlen($keyword_string) < 2) {
return $this->json_error('Query arg too small.');
}
$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 OR ";
$where_condition .= "Description LIKE $keyword_string)";
if ($this->version >= 6 && $search_by === 'name-desc') {
$where_condition = construct_keyword_search($this->dbh,
$keyword_string, true, false);
} else {
$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') {
if (empty($keyword_string)) {