aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2020-04-17 10:57:35 +0200
committerGravatar GitHub <noreply@github.com> 2020-04-17 10:57:35 +0200
commitae70374b0323dc26f560b28414d2d270c06ddd50 (patch)
tree2716a1d96c0d45d5db7df7cbba7540a2b520aa5f
parenta49db010e4a5e48017d8583c374210242a680ddd (diff)
Filter by multiple feed IDs (#2892)
Add the possibility to filter by feed ID like `f:123 more-search` or multiple feed IDs, like `f:123,234,345 more-search` or an exclusion like `!f:456,789 more-search`
-rw-r--r--app/Models/EntryDAO.php20
-rw-r--r--app/Models/Search.php46
-rw-r--r--docs/en/users/03_Main_view.md10
-rw-r--r--docs/fr/users/03_Main_view.md14
4 files changed, 79 insertions, 11 deletions
diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php
index 1cca5cd75..9ee59fc5a 100644
--- a/app/Models/EntryDAO.php
+++ b/app/Models/EntryDAO.php
@@ -703,6 +703,26 @@ SQL;
continue;
}
$sub_search = '';
+
+ if ($filter->getFeedIds()) {
+ $sub_search .= 'AND ' . $alias . 'id_feed IN (';
+ foreach ($filter->getFeedIds() as $feed_id) {
+ $sub_search .= '?,';
+ $values[] = $feed_id;
+ }
+ $sub_search = rtrim($sub_search, ',');
+ $sub_search .= ') ';
+ }
+ if ($filter->getNotFeedIds()) {
+ $sub_search .= 'AND ' . $alias . 'id_feed NOT IN (';
+ foreach ($filter->getNotFeedIds() as $feed_id) {
+ $sub_search .= '?,';
+ $values[] = $feed_id;
+ }
+ $sub_search = rtrim($sub_search, ',');
+ $sub_search .= ') ';
+ }
+
if ($filter->getMinDate()) {
$sub_search .= 'AND ' . $alias . 'id >= ? ';
$values[] = "{$filter->getMinDate()}000000";
diff --git a/app/Models/Search.php b/app/Models/Search.php
index 74264b712..1e1b9c1ff 100644
--- a/app/Models/Search.php
+++ b/app/Models/Search.php
@@ -12,7 +12,9 @@ class FreshRSS_Search {
// This contains the user input string
private $raw_input = '';
+
// The following properties are extracted from the raw input
+ private $feed_ids;
private $intitle;
private $min_date;
private $max_date;
@@ -23,6 +25,7 @@ class FreshRSS_Search {
private $tags;
private $search;
+ private $not_feed_ids;
private $not_intitle;
private $not_min_date;
private $not_max_date;
@@ -41,6 +44,8 @@ class FreshRSS_Search {
$input = preg_replace('/:&quot;(.*?)&quot;/', ':"\1"', $input);
+ $input = $this->parseNotFeedIds($input);
+
$input = $this->parseNotPubdateSearch($input);
$input = $this->parseNotDateSearch($input);
@@ -49,6 +54,8 @@ class FreshRSS_Search {
$input = $this->parseNotInurlSearch($input);
$input = $this->parseNotTagsSearch($input);
+ $input = $this->parseFeedIds($input);
+
$input = $this->parsePubdateSearch($input);
$input = $this->parseDateSearch($input);
@@ -69,6 +76,13 @@ class FreshRSS_Search {
return $this->raw_input;
}
+ public function getFeedIds() {
+ return $this->feed_ids;
+ }
+ public function getNotFeedIds() {
+ return $this->not_feed_ids;
+ }
+
public function getIntitle() {
return $this->intitle;
}
@@ -154,6 +168,38 @@ class FreshRSS_Search {
}
/**
+ * Parse the search string to find feed IDs.
+ *
+ * @param string $input
+ * @return string
+ */
+ private function parseFeedIds($input) {
+ if (preg_match_all('/\bf:(?P<search>[0-9,]*)/', $input, $matches)) {
+ $ids_lists = $matches['search'];
+ $input = str_replace($matches[0], '', $input);
+ $ids_lists = self::removeEmptyValues($ids_lists);
+ if (!empty($ids_lists[0])) {
+ $this->feed_ids = explode(',', $ids_lists[0]);
+ array_filter($this->feed_ids, function($v) { $v != ''; });
+ }
+ }
+ return $input;
+ }
+
+ private function parseNotFeedIds($input) {
+ if (preg_match_all('/[!-]f:(?P<search>[0-9,]*)/', $input, $matches)) {
+ $ids_lists = $matches['search'];
+ $input = str_replace($matches[0], '', $input);
+ $ids_lists = self::removeEmptyValues($ids_lists);
+ if (!empty($ids_lists[0])) {
+ $this->not_feed_ids = explode(',', $ids_lists[0]);
+ array_filter($this->not_feed_ids, function($v) { $v != ''; });
+ }
+ }
+ return $input;
+ }
+
+ /**
* Parse the search string to find intitle keyword and the search related
* to it.
* The search is the first word following the keyword.
diff --git a/docs/en/users/03_Main_view.md b/docs/en/users/03_Main_view.md
index 2642e1d1e..d519e959f 100644
--- a/docs/en/users/03_Main_view.md
+++ b/docs/en/users/03_Main_view.md
@@ -158,6 +158,7 @@ It is possible to filter articles by their content by inputting a string in the
You can use the search field to further refine results:
+* by feed ID: `f:123` or multiple feed IDs: `f:123,234,345`
* by author: `author:name` or `author:'composed name'`
* by title: `intitle:keyword` or `intitle:'composed keyword'`
* by URL: `inurl:keyword` or `inurl:'composed keyword'`
@@ -200,9 +201,10 @@ You can use the search field to further refine results:
Be careful not to enter a space between the operator and the search value.
Some operators can be used negatively, to exclude articles, with the same syntax as above, but prefixed by a `!` or `-`:
-`-author:name`, `-intitle:keyword`, `-inurl:keyword`, `-#tag`, `!keyword`, `!date:2019`, `!date:P1W`, `!pubdate:P3d/`.
+`!f:234`, `-author:name`, `-intitle:keyword`, `-inurl:keyword`, `-#tag`, `!keyword`, `!date:2019`, `!date:P1W`, `!pubdate:P3d/`.
-It is also possible to combine keywords to create a more precise filter. For example, you can enter multiple instances of `author:`, `intitle:`, `inurl:`, `#`, and free-text.
+It is also possible to combine keywords to create a more precise filter.
+For example, you can enter multiple instances of `f:`, `author:`, `intitle:`, `inurl:`, `#`, and free-text.
-Combining several search criteria implies a logical *and*, but the keyword ` OR ` can be used to combine several search criteria with a logical *or* instead:
-`author:Dupont OR author:Dupond`
+Combining several search criteria implies a logical *and*, but the keyword ` OR `
+can be used to combine several search criteria with a logical *or* instead: `author:Dupont OR author:Dupond`
diff --git a/docs/fr/users/03_Main_view.md b/docs/fr/users/03_Main_view.md
index 6bb12714d..6c4034976 100644
--- a/docs/fr/users/03_Main_view.md
+++ b/docs/fr/users/03_Main_view.md
@@ -207,6 +207,7 @@ the search field.
Il est possible d’utiliser le champ de recherche pour raffiner les résultats
:
+* par ID de flux : `f:123` ou plusieurs flux : `f:123,234,345`
* par auteur : `author:nom` or `author:'nom composé'`
* par titre : `intitle:mot` or `intitle:'mot composé'`
* par URL: `inurl:mot` or `inurl:'mot composé'`
@@ -244,19 +245,18 @@ Il est possible d’utiliser le champ de recherche pour raffiner les résultats
* `date:PT30M/` (past thirty minutes)
* `date:PT90S/` (past ninety seconds)
* `date:P1DT1H/` (past one day and one hour)
-* by date of publication, using the same format: `pubdate:<date-interval>`
+* par date de publication, avec la même syntaxe: `pubdate:<date-interval>`
Attention à ne pas introduire d’espace entre l’opérateur et la valeur
recherchée.
Certains opérateurs peuvent être utilisé négativement, pour exclure des
-articles, avec la même syntaxe que ci-dessus, mais préfixé par `!` ou `-`
-:`-author:nom`, `-intitle:mot`, `-inurl:mot`, `-#tag`, `!mot`, `!date:2019`, `!date:P1W`, `!pubdate:P3d/`.
+articles, avec la même syntaxe que ci-dessus, mais préfixé par `!` ou `-` :
+`!f:123`, `-author:nom`, `-intitle:mot`, `-inurl:mot`, `-#tag`, `!mot`, `!date:2019`, `!date:P1W`, `!pubdate:P3d/`.
Il est également possible de combiner les mots-clefs pour faire un filtrage
encore plus précis, et il est autorisé d’avoir plusieurs instances de :
-`author:`, `intitle:`, `inurl:`, `#`, et texte libre.
+`f:`, `author:`, `intitle:`, `inurl:`, `#`, et texte libre.
-Combiner plusieurs critères implique un *et* logique, mais le mot clef ` OR
-` peut être utiliser pour combiner plusieurs critères avec un *ou* logique
-:`author:Dupont OR author:Dupond`
+Combiner plusieurs critères implique un *et* logique, mais le mot clef ` OR`
+peut être utiliser pour combiner plusieurs critères avec un *ou* logique : `author:Dupont OR author:Dupond`