aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2020-04-01 17:26:19 +0200
committerGravatar GitHub <noreply@github.com> 2020-04-01 17:26:19 +0200
commit61c8026ac98a5ed7d4c715102d66d56d967553ab (patch)
treed10292dc8446d29fbe2f7b71856c7c2a4bd98e09
parent656b61ff2956351538cc70fe79cc534b1eb58e0c (diff)
Implement negation for searching by date intervals (#2869)
* Implement negation for searching by date intervals #fix https://github.com/FreshRSS/FreshRSS/issues/2866 Allow searching for e.g. `!date:P1W` to exlude all articles newer than one week. More generally, allows exclusion on some date intervals. * Fix OR
-rw-r--r--app/Models/EntryDAO.php32
-rw-r--r--app/Models/Search.php44
-rw-r--r--docs/en/users/03_Main_view.md2
-rw-r--r--docs/fr/users/03_Main_view.md2
4 files changed, 76 insertions, 4 deletions
diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php
index ebe530ec1..1cca5cd75 100644
--- a/app/Models/EntryDAO.php
+++ b/app/Models/EntryDAO.php
@@ -720,6 +720,38 @@ SQL;
$values[] = $filter->getMaxPubdate();
}
+ //Negation of date intervals must be combined by OR
+ if ($filter->getNotMinDate() || $filter->getNotMaxDate()) {
+ $sub_search .= 'AND (';
+ if ($filter->getNotMinDate()) {
+ $sub_search .= $alias . 'id < ?';
+ $values[] = "{$filter->getNotMinDate()}000000";
+ if ($filter->getNotMaxDate()) {
+ $sub_search .= ' OR ';
+ }
+ }
+ if ($filter->getNotMaxDate()) {
+ $sub_search .= $alias . 'id > ?';
+ $values[] = "{$filter->getNotMaxDate()}000000";
+ }
+ $sub_search .= ') ';
+ }
+ if ($filter->getNotMinPubdate() || $filter->getNotMaxPubdate()) {
+ $sub_search .= 'AND (';
+ if ($filter->getNotMinPubdate()) {
+ $sub_search .= $alias . 'date < ?';
+ $values[] = $filter->getNotMinPubdate();
+ if ($filter->getNotMaxPubdate()) {
+ $sub_search .= ' OR ';
+ }
+ }
+ if ($filter->getNotMaxPubdate()) {
+ $sub_search .= $alias . 'date > ?';
+ $values[] = $filter->getNotMaxPubdate();
+ }
+ $sub_search .= ') ';
+ }
+
if ($filter->getAuthor()) {
foreach ($filter->getAuthor() as $author) {
$sub_search .= 'AND ' . $alias . 'author LIKE ? ';
diff --git a/app/Models/Search.php b/app/Models/Search.php
index f9cda7354..74264b712 100644
--- a/app/Models/Search.php
+++ b/app/Models/Search.php
@@ -24,6 +24,10 @@ class FreshRSS_Search {
private $search;
private $not_intitle;
+ private $not_min_date;
+ private $not_max_date;
+ private $not_min_pubdate;
+ private $not_max_pubdate;
private $not_inurl;
private $not_author;
private $not_tags;
@@ -37,6 +41,9 @@ class FreshRSS_Search {
$input = preg_replace('/:&quot;(.*?)&quot;/', ':"\1"', $input);
+ $input = $this->parseNotPubdateSearch($input);
+ $input = $this->parseNotDateSearch($input);
+
$input = $this->parseNotIntitleSearch($input);
$input = $this->parseNotAuthorSearch($input);
$input = $this->parseNotInurlSearch($input);
@@ -72,7 +79,9 @@ class FreshRSS_Search {
public function getMinDate() {
return $this->min_date;
}
-
+ public function getNotMinDate() {
+ return $this->not_min_date;
+ }
public function setMinDate($value) {
return $this->min_date = $value;
}
@@ -80,7 +89,9 @@ class FreshRSS_Search {
public function getMaxDate() {
return $this->max_date;
}
-
+ public function getNotMaxDate() {
+ return $this->not_max_date;
+ }
public function setMaxDate($value) {
return $this->max_date = $value;
}
@@ -88,10 +99,16 @@ class FreshRSS_Search {
public function getMinPubdate() {
return $this->min_pubdate;
}
+ public function getNotMinPubdate() {
+ return $this->not_min_pubdate;
+ }
public function getMaxPubdate() {
return $this->max_pubdate;
}
+ public function getNotMaxPubdate() {
+ return $this->not_max_pubdate;
+ }
public function getInurl() {
return $this->inurl;
@@ -257,6 +274,18 @@ class FreshRSS_Search {
return $input;
}
+ private function parseNotDateSearch($input) {
+ if (preg_match_all('/[!-]date:(?P<search>[^\s]*)/', $input, $matches)) {
+ $input = str_replace($matches[0], '', $input);
+ $dates = self::removeEmptyValues($matches['search']);
+ if (!empty($dates[0])) {
+ list($this->not_min_date, $this->not_max_date) = parseDateInterval($dates[0]);
+ }
+ }
+ return $input;
+ }
+
+
/**
* Parse the search string to find pubdate keyword and the search related
* to it.
@@ -276,6 +305,17 @@ class FreshRSS_Search {
return $input;
}
+ private function parseNotPubdateSearch($input) {
+ if (preg_match_all('/[!-]pubdate:(?P<search>[^\s]*)/', $input, $matches)) {
+ $input = str_replace($matches[0], '', $input);
+ $dates = self::removeEmptyValues($matches['search']);
+ if (!empty($dates[0])) {
+ list($this->not_min_pubdate, $this->not_max_pubdate) = parseDateInterval($dates[0]);
+ }
+ }
+ return $input;
+ }
+
/**
* Parse the search string to find tags keyword (# followed by a word)
* and the search related to it.
diff --git a/docs/en/users/03_Main_view.md b/docs/en/users/03_Main_view.md
index 7259d756e..2642e1d1e 100644
--- a/docs/en/users/03_Main_view.md
+++ b/docs/en/users/03_Main_view.md
@@ -200,7 +200,7 @@ 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`.
+`-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.
diff --git a/docs/fr/users/03_Main_view.md b/docs/fr/users/03_Main_view.md
index e827d6c6d..6bb12714d 100644
--- a/docs/fr/users/03_Main_view.md
+++ b/docs/fr/users/03_Main_view.md
@@ -251,7 +251,7 @@ 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`.
+:`-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 :