diff --git a/app/Http/Controllers/Rule/IndexController.php b/app/Http/Controllers/Rule/IndexController.php index a0fef5dc2b..6f2e020184 100644 --- a/app/Http/Controllers/Rule/IndexController.php +++ b/app/Http/Controllers/Rule/IndexController.php @@ -92,14 +92,7 @@ class IndexController extends Controller public function search(Rule $rule): RedirectResponse { $route = route('search.index'); - $params = []; - /** @var RuleTrigger $trigger */ - foreach ($rule->ruleTriggers as $trigger) { - if ('user_action' !== $trigger->trigger_type) { - $params[] = sprintf('%s:"%s"', OperatorQuerySearch::getRootOperator($trigger->trigger_type), $trigger->trigger_value); - } - } - $query = implode(' ', $params); + $query = $this->ruleRepos->getSearchQuery($rule); $route = sprintf('%s?%s', $route, http_build_query(['search' => $query, 'rule' => $rule->id])); return redirect($route); diff --git a/app/Http/Controllers/Rule/SelectController.php b/app/Http/Controllers/Rule/SelectController.php index c985ecf507..0490704432 100644 --- a/app/Http/Controllers/Rule/SelectController.php +++ b/app/Http/Controllers/Rule/SelectController.php @@ -189,4 +189,51 @@ class SelectController extends Controller return response()->json(['html' => $view, 'warning' => $warning]); } + /** + * This method allows the user to test a certain set of rule triggers. The rule triggers are grabbed from + * the rule itself. + * + * @param Rule $rule + * + * @return JsonResponse + * + */ + public function testTriggersByRule(Rule $rule): JsonResponse + { + $triggers = $rule->ruleTriggers; + + if (0 === count($triggers)) { + return response()->json(['html' => '', 'warning' => (string) trans('firefly.warning_no_valid_triggers')]); // @codeCoverageIgnore + } + + + // create new rule engine: + $newRuleEngine = app(RuleEngineInterface::class); + + // set rules: + $newRuleEngine->setRules(new Collection([$rule])); + $collection = $newRuleEngine->find(); + $collection = $collection->slice(0, 20); + + $warning = ''; + if (0 === count($collection)) { + $warning = (string) trans('firefly.warning_no_matching_transactions'); // @codeCoverageIgnore + } + + // Return json response + $view = 'ERROR, see logs.'; + try { + $view = view('list.journals-array-tiny', ['groups' => $collection])->render(); + // @codeCoverageIgnoreStart + } catch (Throwable $exception) { + Log::error(sprintf('Could not render view in testTriggersByRule(): %s', $exception->getMessage())); + Log::error($exception->getTraceAsString()); + } + + // @codeCoverageIgnoreEnd + + return response()->json(['html' => $view, 'warning' => $warning]); + } + + } diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index d7983a5c71..167ec697ad 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers; +use FireflyIII\Repositories\Rule\RuleRepositoryInterface; use FireflyIII\Support\Search\SearchInterface; use Illuminate\Contracts\View\Factory; use Illuminate\Http\JsonResponse; @@ -62,15 +63,33 @@ class SearchController extends Controller */ public function index(Request $request, SearchInterface $searcher) { - $fullQuery = (string) $request->get('search'); - $page = 0 === (int) $request->get('page') ? 1 : (int) $request->get('page'); + // search params: + $fullQuery = (string) $request->get('search'); + $page = 0 === (int) $request->get('page') ? 1 : (int) $request->get('page'); + $ruleId = (int) $request->get('rule'); + $rule = null; + $ruleChanged = false; + + // find rule, check if query is different, offer to update. + $ruleRepository = app(RuleRepositoryInterface::class); + $rule = $ruleRepository->find($ruleId); + if (null !== $rule) { + $originalQuery = $ruleRepository->getSearchQuery($rule); + if ($originalQuery !== $fullQuery) { + $ruleChanged = true; + } + } + // parse search terms: $searcher->parseQuery($fullQuery); - $query = $searcher->getWordsAsString(); - $modifiers = $searcher->getModifiers(); - $subTitle = (string) trans('breadcrumbs.search_result', ['query' => $query]); - return view('search.index', compact('query', 'modifiers', 'page', 'fullQuery', 'subTitle')); + // words from query and operators: + $query = $searcher->getWordsAsString(); + $operators = $searcher->getOperators(); + + $subTitle = (string) trans('breadcrumbs.search_result', ['query' => $fullQuery]); + + return view('search.index', compact('query', 'operators', 'page', 'rule', 'fullQuery', 'subTitle', 'ruleId', 'ruleChanged')); } /** diff --git a/app/Repositories/Rule/RuleRepository.php b/app/Repositories/Rule/RuleRepository.php index b2e743bb4f..2506b2519b 100644 --- a/app/Repositories/Rule/RuleRepository.php +++ b/app/Repositories/Rule/RuleRepository.php @@ -27,6 +27,7 @@ use FireflyIII\Models\Rule; use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleGroup; use FireflyIII\Models\RuleTrigger; +use FireflyIII\Support\Search\OperatorQuerySearch; use FireflyIII\User; use Illuminate\Support\Collection; use Log; @@ -119,7 +120,7 @@ class RuleRepository implements RuleRepositoryInterface */ public function getHighestOrderInRuleGroup(RuleGroup $ruleGroup): int { - return (int)$ruleGroup->rules()->max('order'); + return (int) $ruleGroup->rules()->max('order'); } /** @@ -461,8 +462,8 @@ class RuleRepository implements RuleRepositoryInterface */ public function duplicate(Rule $rule): Rule { - $newRule = $rule->replicate(); - $newRule->title = (string)trans('firefly.rule_copy_of', ['title' => $rule->title]); + $newRule = $rule->replicate(); + $newRule->title = (string) trans('firefly.rule_copy_of', ['title' => $rule->title]); $newRule->save(); // replicate all triggers @@ -503,13 +504,13 @@ class RuleRepository implements RuleRepositoryInterface */ public function getStoreRules(): Collection { - $collection = $this->user->rules()->with(['ruleGroup','ruleTriggers'])->get(); - $filtered = new Collection; + $collection = $this->user->rules()->with(['ruleGroup', 'ruleTriggers'])->get(); + $filtered = new Collection; /** @var Rule $rule */ - foreach($collection as $rule) { + foreach ($collection as $rule) { /** @var RuleTrigger $ruleTrigger */ - foreach($rule->ruleTriggers as $ruleTrigger) { - if('user_action' === $ruleTrigger->trigger_type && 'store-journal' === $ruleTrigger->trigger_value) { + foreach ($rule->ruleTriggers as $ruleTrigger) { + if ('user_action' === $ruleTrigger->trigger_type && 'store-journal' === $ruleTrigger->trigger_value) { $filtered->push($rule); } } @@ -522,17 +523,33 @@ class RuleRepository implements RuleRepositoryInterface */ public function getUpdateRules(): Collection { - $collection = $this->user->rules()->with(['ruleGroup','ruleTriggers'])->get(); - $filtered = new Collection; + $collection = $this->user->rules()->with(['ruleGroup', 'ruleTriggers'])->get(); + $filtered = new Collection; /** @var Rule $rule */ - foreach($collection as $rule) { + foreach ($collection as $rule) { /** @var RuleTrigger $ruleTrigger */ - foreach($rule->ruleTriggers as $ruleTrigger) { - if('user_action' === $ruleTrigger->trigger_type && 'update-journal' === $ruleTrigger->trigger_value) { + foreach ($rule->ruleTriggers as $ruleTrigger) { + if ('user_action' === $ruleTrigger->trigger_type && 'update-journal' === $ruleTrigger->trigger_value) { $filtered->push($rule); } } } return $filtered; } + + /** + * @inheritDoc + */ + public function getSearchQuery(Rule $rule): string + { + $params = []; + /** @var RuleTrigger $trigger */ + foreach ($rule->ruleTriggers as $trigger) { + if ('user_action' !== $trigger->trigger_type) { + $params[] = sprintf('%s:"%s"', OperatorQuerySearch::getRootOperator($trigger->trigger_type), $trigger->trigger_value); + } + } + return implode(' ', $params); + + } } diff --git a/app/Repositories/Rule/RuleRepositoryInterface.php b/app/Repositories/Rule/RuleRepositoryInterface.php index 178eb3953e..d49199c4fc 100644 --- a/app/Repositories/Rule/RuleRepositoryInterface.php +++ b/app/Repositories/Rule/RuleRepositoryInterface.php @@ -39,6 +39,14 @@ interface RuleRepositoryInterface */ public function count(): int; + /** + * Return search query for rule. + * + * @param Rule $rule + * @return string + */ + public function getSearchQuery(Rule $rule): string; + /** * @param Rule $rule * @param RuleGroup $ruleGroup diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index c2255e557c..03a0247207 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -318,6 +318,8 @@ return [ 'search_modifier_bill_is' => 'Bill is ":value"', 'search_modifier_transaction_type' => 'Transaction type is ":value"', 'search_modifier_tag_is' => 'Tag is ":value"', + 'update_rule_from_query' => 'Update rule ":rule" from search query', + 'create_rule_from_query' => 'Create new rule from search query', // END 'modifiers_applies_are' => 'The following modifiers are applied to the search as well:', diff --git a/resources/views/v1/rules/index.twig b/resources/views/v1/rules/index.twig index 8318969d08..4b1901c8e5 100644 --- a/resources/views/v1/rules/index.twig +++ b/resources/views/v1/rules/index.twig @@ -72,27 +72,6 @@
- {# - {% if rule.order > 1 %} - - {% else %} - - {% endif %} - {% if rule.order < ruleGroup.rules.count %} - - - {% else %} - - {% endif %} - #}
@@ -109,21 +88,16 @@
- {# show which transactions would match #} {% if rule.active %} - + {# show which transactions would match #} + - {# actually execute rule #} - - + {# actually execute rule #} + {% endif %} + {# duplicate rule #} - - +
diff --git a/resources/views/v1/search/index.twig b/resources/views/v1/search/index.twig index 41089ab394..0f7408a2fe 100644 --- a/resources/views/v1/search/index.twig +++ b/resources/views/v1/search/index.twig @@ -1,7 +1,7 @@ {% extends "./layout/default" %} {% block breadcrumbs %} - {{ Breadcrumbs.render(Route.getCurrentRoute.getName, query) }} + {{ Breadcrumbs.render(Route.getCurrentRoute.getName, fullQuery) }} {% endblock %} {% block content %} @@ -26,20 +26,27 @@
- + + {% if ruleId > 0 and ruleChanged %} + {{ trans('firefly.update_rule_from_query', {rule: rule.title}) }} + {% endif %} + {{ 'create_rule_from_query'|_ }}
+ {% if 0 != ruleId %} + + {% endif %} {% if '' != query %}

{{ trans('firefly.search_for_query', {query: query|escape})|raw}}

{% endif %} - {% if modifiers|length > 0 %} + {% if operators|length > 0 %}

{{ trans('firefly.modifiers_applies_are') }}

{% endif %} diff --git a/routes/web.php b/routes/web.php index ac660c2f99..210adf1f1c 100644 --- a/routes/web.php +++ b/routes/web.php @@ -920,6 +920,7 @@ Route::group( // select controller Route::get('test', ['uses' => 'Rule\SelectController@testTriggers', 'as' => 'test-triggers']); Route::get('test-rule/{rule}', ['uses' => 'Rule\SelectController@testTriggersByRule', 'as' => 'test-triggers-rule']); + Route::get('search/{rule}', ['uses' => 'Rule\IndexController@search', 'as' => 'search']); Route::get('select/{rule}', ['uses' => 'Rule\SelectController@selectTransactions', 'as' => 'select-transactions']); Route::post('execute/{rule}', ['uses' => 'Rule\SelectController@execute', 'as' => 'execute']);