diff --git a/app/Http/Controllers/Rule/CreateController.php b/app/Http/Controllers/Rule/CreateController.php index 65926fd693..2cc612fe08 100644 --- a/app/Http/Controllers/Rule/CreateController.php +++ b/app/Http/Controllers/Rule/CreateController.php @@ -32,11 +32,15 @@ use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Rule\RuleRepositoryInterface; use FireflyIII\Support\Http\Controllers\ModelInformation; use FireflyIII\Support\Http\Controllers\RuleManagement; +use FireflyIII\Support\Search\OperatorQuerySearch; +use FireflyIII\Support\Search\SearchInterface; use Illuminate\Contracts\View\Factory; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Routing\Redirector; use Illuminate\View\View; +use Log; +use Throwable; /** * Class CreateController @@ -44,6 +48,7 @@ use Illuminate\View\View; class CreateController extends Controller { use RuleManagement, ModelInformation; + /** @var RuleRepositoryInterface Rule repository */ private $ruleRepos; @@ -86,6 +91,20 @@ class CreateController extends Controller $oldTriggers = []; $oldActions = []; + // build triggers from query, if present. + $query = (string) $request->get('from_query'); + if ('' !== $query) { + $search = app(SearchInterface::class); + $search->parseQuery($query); + $words = $search->getWordsAsString(); + $operators = $search->getOperators()->toArray(); + if ('' !== $words) { + session()->flash('warning', trans('firefly.rule_from_search_words', ['string' => $words])); + array_push($operators, ['type' => 'description_contains', 'value' => $words]); + } + $oldTriggers = $this->parseFromOperators($operators); + } + // restore actions and triggers from old input: if ($request->old()) { $oldTriggers = $this->getPreviousTriggers($request); @@ -183,8 +202,8 @@ class CreateController extends Controller $subTitle = (string) trans('firefly.make_new_rule_no_group'); // get triggers and actions for journal. - $oldTriggers = $this->getTriggersForJournal($journal); - $oldActions = []; + $oldTriggers = $this->getTriggersForJournal($journal); + $oldActions = []; $this->createDefaultRuleGroup(); $this->createDefaultRule(); @@ -271,4 +290,45 @@ class CreateController extends Controller return $redirect; } + + /** + * @param array $submittedOperators + * @return array + */ + private function parseFromOperators(array $submittedOperators): array + { + // TODO duplicated code. + $operators = config('firefly.search.operators'); + $renderedEntries = []; + $triggers = []; + foreach ($operators as $key => $operator) { + if ('user_action' !== $key && false === $operator['alias']) { + + $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); + } + } + asort($triggers); + + $index = 0; + foreach ($submittedOperators as $operator) { + try { + $renderedEntries[] = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => OperatorQuerySearch::getRootOperator($operator['type']), + 'oldValue' => $operator['value'], + 'oldChecked' => 1 === (int) ($oldTrigger['stop_processing'] ?? '0'), + 'count' => $index + 1, + 'triggers' => $triggers, + ] + )->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage())); + Log::error($e->getTraceAsString()); + } + $index++; + } + + return $renderedEntries; + } } diff --git a/app/Http/Controllers/Rule/EditController.php b/app/Http/Controllers/Rule/EditController.php index bdeea2771b..5f842af2d3 100644 --- a/app/Http/Controllers/Rule/EditController.php +++ b/app/Http/Controllers/Rule/EditController.php @@ -30,6 +30,8 @@ use FireflyIII\Models\Rule; use FireflyIII\Repositories\Rule\RuleRepositoryInterface; use FireflyIII\Support\Http\Controllers\RenderPartialViews; use FireflyIII\Support\Http\Controllers\RuleManagement; +use FireflyIII\Support\Search\OperatorQuerySearch; +use FireflyIII\Support\Search\SearchInterface; use Illuminate\Contracts\View\Factory; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; @@ -81,15 +83,31 @@ class EditController extends Controller $actionCount = 0; $oldActions = []; $oldTriggers = []; + + // build triggers from query, if present. + $query = (string) $request->get('from_query'); + if ('' !== $query) { + $search = app(SearchInterface::class); + $search->parseQuery($query); + $words = $search->getWordsAsString(); + $operators = $search->getOperators()->toArray(); + if ('' !== $words) { + session()->flash('warning', trans('firefly.rule_from_search_words', ['string' => $words])); + array_push($operators, ['type' => 'description_contains', 'value' => $words]); + } + $oldTriggers = $this->parseFromOperators($operators); + } + + // has old input? if (count($request->old()) > 0) { $oldTriggers = $this->getPreviousTriggers($request); - $triggerCount = count($oldTriggers); $oldActions = $this->getPreviousActions($request); - $actionCount = count($oldActions); } + $triggerCount = count($oldTriggers); + $actionCount = count($oldActions); - // overrule old input when it has no rule data: + // overrule old input and query data when it has no rule data: if (0 === $triggerCount && 0 === $actionCount) { $oldTriggers = $this->getCurrentTriggers($rule); $triggerCount = count($oldTriggers); @@ -146,4 +164,45 @@ class EditController extends Controller return $redirect; } + + /** + * @param array $submittedOperators + * @return array + */ + private function parseFromOperators(array $submittedOperators): array + { + // TODO duplicated code. + $operators = config('firefly.search.operators'); + $renderedEntries = []; + $triggers = []; + foreach ($operators as $key => $operator) { + if ('user_action' !== $key && false === $operator['alias']) { + + $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); + } + } + asort($triggers); + + $index = 0; + foreach ($submittedOperators as $operator) { + try { + $renderedEntries[] = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => OperatorQuerySearch::getRootOperator($operator['type']), + 'oldValue' => $operator['value'], + 'oldChecked' => 1 === (int) ($oldTrigger['stop_processing'] ?? '0'), + 'count' => $index + 1, + 'triggers' => $triggers, + ] + )->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage())); + Log::error($e->getTraceAsString()); + } + $index++; + } + + return $renderedEntries; + } } diff --git a/app/Support/Twig/General.php b/app/Support/Twig/General.php index b5aec234fc..d0c1a5c6b0 100644 --- a/app/Support/Twig/General.php +++ b/app/Support/Twig/General.php @@ -26,6 +26,7 @@ use Carbon\Carbon; use FireflyIII\Models\Account; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface; +use FireflyIII\Support\Search\OperatorQuerySearch; use League\CommonMark\CommonMarkConverter; use Route; use Twig\Extension\AbstractExtension; @@ -64,9 +65,20 @@ class General extends AbstractExtension $this->formatDate(), $this->getMetaField(), $this->hasRole(), + $this->getRootSearchOperator(), ]; } + protected function getRootSearchOperator(): TwigFunction + { + return new TwigFunction( + 'getRootSearchOperator', + static function (string $operator): string { + return OperatorQuerySearch::getRootOperator($operator); + } + ); + } + /** * Will return "active" when a part of the route matches the argument. * ie. "accounts" will match "accounts.index". diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 03a0247207..537a7767cb 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -320,6 +320,8 @@ return [ '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', + 'rule_from_search_words' => 'The rule engine has a hard time handling ":string". The suggested rule that fits your search query may give different results. Please verify the rule triggers carefully.', + // 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 4b1901c8e5..2e4bcb4072 100644 --- a/resources/views/v1/rules/index.twig +++ b/resources/views/v1/rules/index.twig @@ -128,7 +128,8 @@ {% if not rule.active %} class="text-muted" {% endif %} - data-id="{{ trigger.id }}">{{ trans(('firefly.rule_trigger_' ~ trigger.trigger_type), {trigger_value: trigger.trigger_value}) }} + data-id="{{ trigger.id }}"> + {{ trans(('firefly.rule_trigger_' ~ getRootSearchOperator(trigger.trigger_type)), {trigger_value: trigger.trigger_value}) }} {% if trigger.stop_processing %} diff --git a/resources/views/v1/search/index.twig b/resources/views/v1/search/index.twig index fd1c2d9b94..3448d8270e 100644 --- a/resources/views/v1/search/index.twig +++ b/resources/views/v1/search/index.twig @@ -28,9 +28,9 @@