summaryrefslogtreecommitdiff
path: root/app/Models
diff options
context:
space:
mode:
authorGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2019-03-23 22:52:47 +0100
committerGravatar GitHub <noreply@github.com> 2019-03-23 22:52:47 +0100
commit1804c0e0bc095487b9a1ad13cbc9f55f6cef2a2a (patch)
tree4a250b570a3d0adbfe5f520533c7719646d97c2c /app/Models
parente7a57915f9c90c144d95918048d2523418866921 (diff)
Filter actions (#2275)
* Draft of filter actions * Travis * Implement UI + finish logic * Travis
Diffstat (limited to 'app/Models')
-rw-r--r--app/Models/Entry.php113
-rw-r--r--app/Models/Feed.php104
-rw-r--r--app/Models/FilterAction.php45
3 files changed, 262 insertions, 0 deletions
diff --git a/app/Models/Entry.php b/app/Models/Entry.php
index f2f3d08fe..3bb977283 100644
--- a/app/Models/Entry.php
+++ b/app/Models/Entry.php
@@ -185,6 +185,119 @@ class FreshRSS_Entry extends Minz_Model {
$this->tags = $value;
}
+ public function matches($booleanSearch) {
+ if (!$booleanSearch || count($booleanSearch->searches()) <= 0) {
+ return true;
+ }
+ foreach ($booleanSearch->searches() as $filter) {
+ $ok = true;
+ if ($ok && $filter->getMinPubdate()) {
+ $ok &= $this->date >= $filter->getMinPubdate();
+ }
+ if ($ok && $filter->getMaxPubdate()) {
+ $ok &= $this->date <= $filter->getMaxPubdate();
+ }
+ if ($ok && $filter->getMinDate()) {
+ $ok &= strnatcmp($this->id, $filter->getMinDate() . '000000') >= 0;
+ }
+ if ($ok && $filter->getMaxDate()) {
+ $ok &= strnatcmp($this->id, $filter->getMaxDate() . '000000') <= 0;
+ }
+ if ($ok && $filter->getInurl()) {
+ foreach ($filter->getInurl() as $url) {
+ $ok &= stripos($this->link, $url) !== false;
+ }
+ }
+ if ($ok && $filter->getNotInurl()) {
+ foreach ($filter->getNotInurl() as $url) {
+ $ok &= stripos($this->link, $url) === false;
+ }
+ }
+ if ($ok && $filter->getAuthor()) {
+ foreach ($filter->getAuthor() as $author) {
+ $ok &= stripos($this->authors, $author) !== false;
+ }
+ }
+ if ($ok && $filter->getNotAuthor()) {
+ foreach ($filter->getNotAuthor() as $author) {
+ $ok &= stripos($this->authors, $author) === false;
+ }
+ }
+ if ($ok && $filter->getIntitle()) {
+ foreach ($filter->getIntitle() as $title) {
+ $ok &= stripos($this->title, $title) !== false;
+ }
+ }
+ if ($ok && $filter->getNotIntitle()) {
+ foreach ($filter->getNotIntitle() as $title) {
+ $ok &= stripos($this->title, $title) === false;
+ }
+ }
+ if ($ok && $filter->getTags()) {
+ foreach ($filter->getTags() as $tag2) {
+ $found = false;
+ foreach ($this->tags as $tag1) {
+ if (strcasecmp($tag1, $tag2) === 0) {
+ $found = true;
+ }
+ }
+ $ok &= $found;
+ }
+ }
+ if ($ok && $filter->getNotTags()) {
+ foreach ($filter->getNotTags() as $tag2) {
+ $found = false;
+ foreach ($this->tags as $tag1) {
+ if (strcasecmp($tag1, $tag2) === 0) {
+ $found = true;
+ }
+ }
+ $ok &= !$found;
+ }
+ }
+ if ($ok && $filter->getSearch()) {
+ foreach ($filter->getSearch() as $needle) {
+ $ok &= (stripos($this->title, $needle) !== false || stripos($this->content, $needle) !== false);
+ }
+ }
+ if ($ok && $filter->getNotSearch()) {
+ foreach ($filter->getNotSearch() as $needle) {
+ $ok &= (stripos($this->title, $needle) === false && stripos($this->content, $needle) === false);
+ }
+ }
+ if ($ok) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public function applyFilterActions() {
+ if ($this->feed != null) {
+ if ($this->feed->attributes('read_upon_reception') ||
+ ($this->feed->attributes('read_upon_reception') === null && FreshRSS_Context::$user_conf->mark_when['reception'])) {
+ $this->_isRead(true);
+ }
+ foreach ($this->feed->filterActions() as $filterAction) {
+ if ($this->matches($filterAction->booleanSearch())) {
+ foreach ($filterAction->actions() as $action => $params) {
+ switch ($action) {
+ case 'read':
+ $this->_isRead(true);
+ break;
+ case 'star':
+ $this->_is_favorite(true);
+ break;
+ case 'label':
+ //TODO: Implement more actions
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
public function isDay($day, $today) {
$date = $this->dateAdded(true);
switch ($day) {
diff --git a/app/Models/Feed.php b/app/Models/Feed.php
index b21a8bbbe..89989236c 100644
--- a/app/Models/Feed.php
+++ b/app/Models/Feed.php
@@ -32,6 +32,7 @@ class FreshRSS_Feed extends Minz_Model {
private $lockPath = '';
private $hubUrl = '';
private $selfUrl = '';
+ private $filterActions = null;
public function __construct($url, $validate = true) {
if ($validate) {
@@ -498,6 +499,109 @@ class FreshRSS_Feed extends Minz_Model {
@unlink($this->lockPath);
}
+ public function filterActions() {
+ if ($this->filterActions == null) {
+ $this->filterActions = array();
+ $filters = $this->attributes('filters');
+ if (is_array($filters)) {
+ foreach ($filters as $filter) {
+ $filterAction = FreshRSS_FilterAction::fromJSON($filter);
+ if ($filterAction != null) {
+ $this->filterActions[] = $filterAction;
+ }
+ }
+ }
+ }
+ return $this->filterActions;
+ }
+
+ private function _filterActions($filterActions) {
+ $this->filterActions = $filterActions;
+ if (is_array($this->filterActions) && !empty($this->filterActions)) {
+ $this->_attributes('filters', array_map(function ($af) {
+ return $af == null ? null : $af->toJSON();
+ }, $this->filterActions));
+ } else {
+ $this->_attributes('filters', null);
+ }
+ }
+
+ public function filtersAction($action) {
+ $action = trim($action);
+ if ($action == '') {
+ return array();
+ }
+ $filters = array();
+ $filterActions = $this->filterActions();
+ for ($i = count($filterActions) - 1; $i >= 0; $i--) {
+ $filterAction = $filterActions[$i];
+ if ($filterAction != null && $filterAction->booleanSearch() != null &&
+ $filterAction->actions() != null && in_array($action, $filterAction->actions(), true)) {
+ $filters[] = $filterAction->booleanSearch();
+ }
+ }
+ return $filters;
+ }
+
+ public function _filtersAction($action, $filters) {
+ $action = trim($action);
+ if ($action == '' || !is_array($filters)) {
+ return false;
+ }
+ $filters = array_unique(array_map('trim', $filters));
+ $filterActions = $this->filterActions();
+
+ //Check existing filters
+ for ($i = count($filterActions) - 1; $i >= 0; $i--) {
+ $filterAction = $filterActions[$i];
+ if ($filterAction == null || !is_array($filterAction->actions()) ||
+ $filterAction->booleanSearch() == null || trim($filterAction->booleanSearch()->getRawInput()) == '') {
+ array_splice($filterAction, $i, 1);
+ continue;
+ }
+ $actions = $filterAction->actions();
+ //Remove existing rules with same action
+ for ($j = count($actions) - 1; $j >= 0; $j--) {
+ if ($actions[$j] === $action) {
+ array_splice($actions, $j, 1);
+ }
+ }
+ //Update existing filter with new action
+ for ($k = count($filters) - 1; $k >= 0; $k --) {
+ $filter = $filters[$k];
+ if ($filter === $filterAction->booleanSearch()->getRawInput()) {
+ $actions[] = $action;
+ array_splice($filters, $k, 1);
+ }
+ }
+ //Save result
+ if (empty($actions)) {
+ array_splice($filterActions, $i, 1);
+ } else {
+ $filterAction->_actions($actions);
+ }
+ }
+
+ //Add new filters
+ for ($k = count($filters) - 1; $k >= 0; $k --) {
+ $filter = $filters[$k];
+ if ($filter != '') {
+ $filterAction = FreshRSS_FilterAction::fromJSON(array(
+ 'search' => $filter,
+ 'actions' => array($action),
+ ));
+ if ($filterAction != null) {
+ $filterActions[] = $filterAction;
+ }
+ }
+ }
+
+ if (empty($filterActions)) {
+ $filterActions = null;
+ }
+ $this->_filterActions($filterActions);
+ }
+
//<WebSub>
public function pubSubHubbubEnabled() {
diff --git a/app/Models/FilterAction.php b/app/Models/FilterAction.php
new file mode 100644
index 000000000..23a45d14e
--- /dev/null
+++ b/app/Models/FilterAction.php
@@ -0,0 +1,45 @@
+<?php
+
+class FreshRSS_FilterAction {
+
+ private $booleanSearch = null;
+ private $actions = null;
+
+ private function __construct($booleanSearch, $actions) {
+ $this->booleanSearch = $booleanSearch;
+ $this->_actions($actions);
+ }
+
+ public function booleanSearch() {
+ return $this->booleanSearch;
+ }
+
+ public function actions() {
+ return $this->actions;
+ }
+
+ public function _actions($actions) {
+ if (is_array($actions)) {
+ $this->actions = array_unique($actions);
+ } else {
+ $this->actions = null;
+ }
+ }
+
+ public function toJSON() {
+ if (is_array($this->actions) && $this->booleanSearch != null) {
+ return array(
+ 'search' => $this->booleanSearch->getRawInput(),
+ 'actions' => $this->actions,
+ );
+ }
+ return '';
+ }
+
+ public static function fromJSON($json) {
+ if (!empty($json['search']) && !empty($json['actions']) && is_array($json['actions'])) {
+ return new FreshRSS_FilterAction(new FreshRSS_BooleanSearch($json['search']), $json['actions']);
+ }
+ return null;
+ }
+}