mirror of https://github.com/FreshRSS/FreshRSS.git
155 lines
4.3 KiB
PHP
155 lines
4.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Logic to apply filter actions (for feeds, categories, user configuration...).
|
|
*/
|
|
trait FreshRSS_FilterActionsTrait {
|
|
|
|
/** @var array<FreshRSS_FilterAction>|null $filterActions */
|
|
private ?array $filterActions = null;
|
|
|
|
/**
|
|
* @return array<FreshRSS_FilterAction>
|
|
*/
|
|
private function filterActions(): array {
|
|
if (empty($this->filterActions)) {
|
|
$this->filterActions = [];
|
|
$filters = $this->attributeArray('filters') ?? [];
|
|
foreach ($filters as $filter) {
|
|
$filterAction = FreshRSS_FilterAction::fromJSON($filter);
|
|
if ($filterAction != null) {
|
|
$this->filterActions[] = $filterAction;
|
|
}
|
|
}
|
|
}
|
|
return $this->filterActions;
|
|
}
|
|
|
|
/**
|
|
* @param array<FreshRSS_FilterAction>|null $filterActions
|
|
*/
|
|
private function _filterActions(?array $filterActions): void {
|
|
$this->filterActions = $filterActions;
|
|
if ($this->filterActions !== null && !empty($this->filterActions)) {
|
|
$this->_attribute('filters', array_map(static function (?FreshRSS_FilterAction $af) {
|
|
return $af == null ? null : $af->toJSON();
|
|
}, $this->filterActions));
|
|
} else {
|
|
$this->_attribute('filters', null);
|
|
}
|
|
}
|
|
|
|
/** @return array<FreshRSS_BooleanSearch> */
|
|
public function filtersAction(string $action): array {
|
|
$action = trim($action);
|
|
if ($action == '') {
|
|
return [];
|
|
}
|
|
$filters = [];
|
|
$filterActions = $this->filterActions();
|
|
for ($i = count($filterActions) - 1; $i >= 0; $i--) {
|
|
$filterAction = $filterActions[$i];
|
|
if (in_array($action, $filterAction->actions(), true)) {
|
|
$filters[] = $filterAction->booleanSearch();
|
|
}
|
|
}
|
|
return $filters;
|
|
}
|
|
|
|
/**
|
|
* @param array<string> $filters
|
|
*/
|
|
public function _filtersAction(string $action, array $filters): void {
|
|
$action = trim($action);
|
|
if ($action === '') {
|
|
return;
|
|
}
|
|
$filters = array_unique(array_map('trim', $filters), SORT_STRING);
|
|
$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($filterActions, $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([
|
|
'search' => $filter,
|
|
'actions' => [$action],
|
|
]);
|
|
if ($filterAction != null) {
|
|
$filterActions[] = $filterAction;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (empty($filterActions)) {
|
|
$filterActions = null;
|
|
}
|
|
$this->_filterActions($filterActions);
|
|
}
|
|
|
|
/**
|
|
* @param bool $applyLabel Parameter by reference, which will be set to true if the callers needs to apply a label to the article entry.
|
|
*/
|
|
public function applyFilterActions(FreshRSS_Entry $entry, ?bool &$applyLabel = null): void {
|
|
$applyLabel = false;
|
|
foreach ($this->filterActions() as $filterAction) {
|
|
if ($entry->matches($filterAction->booleanSearch())) {
|
|
foreach ($filterAction->actions() as $action) {
|
|
switch ($action) {
|
|
case 'read':
|
|
if (!$entry->isRead()) {
|
|
$entry->_isRead(true);
|
|
Minz_ExtensionManager::callHook('entry_auto_read', $entry, 'filter');
|
|
}
|
|
break;
|
|
case 'star':
|
|
if (!$entry->isUpdated()) {
|
|
// Do not apply to updated articles, to avoid overruling a user manual action
|
|
$entry->_isFavorite(true);
|
|
}
|
|
break;
|
|
case 'label':
|
|
if (!$entry->isUpdated()) {
|
|
// Do not apply to updated articles, to avoid overruling a user manual action
|
|
$applyLabel = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|