Refresh notes in various actions.

This commit is contained in:
James Cole 2024-03-10 08:11:58 +01:00
parent 0b45c1aa76
commit 3413b9b5b5
No known key found for this signature in database
GPG Key ID: B49A324B7EAD6D80
14 changed files with 54 additions and 53 deletions

View File

@ -105,8 +105,8 @@ class StoreRequest extends FormRequest
*/
public function rules(): array
{
$validTriggers = $this->getTriggers();
$validActions = array_keys(config('firefly.rule-actions'));
$validTriggers = $this->getTriggers();
$validActions = array_keys(config('firefly.rule-actions'));
// some triggers and actions require text:
$contextTriggers = implode(',', $this->getTriggersWithContext());
@ -118,11 +118,11 @@ class StoreRequest extends FormRequest
'rule_group_id' => 'belongsToUser:rule_groups|required_without:rule_group_title',
'rule_group_title' => 'nullable|min:1|max:255|required_without:rule_group_id|belongsToUser:rule_groups,title',
'trigger' => 'required|in:store-journal,update-journal',
'triggers.*.type' => 'required|in:' . implode(',', $validTriggers),
'triggers.*.value' => 'required_if:actions.*.type,' . $contextTriggers . '|min:1|ruleTriggerValue|max:1024',
'triggers.*.type' => 'required|in:'.implode(',', $validTriggers),
'triggers.*.value' => 'required_if:actions.*.type,'.$contextTriggers.'|min:1|ruleTriggerValue|max:1024',
'triggers.*.stop_processing' => [new IsBoolean()],
'triggers.*.active' => [new IsBoolean()],
'actions.*.type' => 'required|in:' . implode(',', $validActions),
'actions.*.type' => 'required|in:'.implode(',', $validActions),
'actions.*.value' => [sprintf('required_if:actions.*.type,%s', $contextActions), new IsValidActionExpression(), 'ruleActionValue'],
'actions.*.stop_processing' => [new IsBoolean()],
'actions.*.active' => [new IsBoolean()],
@ -181,10 +181,10 @@ class StoreRequest extends FormRequest
*/
protected function atLeastOneActiveTrigger(Validator $validator): void
{
$data = $validator->getData();
$data = $validator->getData();
/** @var null|array|int|string $triggers */
$triggers = $data['triggers'] ?? [];
$triggers = $data['triggers'] ?? [];
// need at least one trigger
if (!is_countable($triggers) || 0 === count($triggers)) {
return;
@ -210,10 +210,10 @@ class StoreRequest extends FormRequest
*/
protected function atLeastOneActiveAction(Validator $validator): void
{
$data = $validator->getData();
$data = $validator->getData();
/** @var null|array|int|string $actions */
$actions = $data['actions'] ?? [];
$actions = $data['actions'] ?? [];
// need at least one trigger
if (!is_countable($actions) || 0 === count($actions)) {
return;

View File

@ -141,7 +141,7 @@ class UpdateRequest extends FormRequest
'triggers.*.stop_processing' => [new IsBoolean()],
'triggers.*.active' => [new IsBoolean()],
'actions.*.type' => 'required|in:'.implode(',', $validActions),
'actions.*.value' => [sprintf('required_if:actions.*.type,%s',$contextActions), new IsValidActionExpression(), 'ruleActionValue'],
'actions.*.value' => [sprintf('required_if:actions.*.type,%s', $contextActions), new IsValidActionExpression(), 'ruleActionValue'],
'actions.*.stop_processing' => [new IsBoolean()],
'actions.*.active' => [new IsBoolean()],
'strict' => [new IsBoolean()],

View File

@ -26,9 +26,7 @@ namespace FireflyIII\Api\V1\Requests\Models\Rule;
use FireflyIII\Rules\IsValidActionExpression;
use FireflyIII\Support\Request\ChecksLogin;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\ValidationException;
/**
* Class ValidateExpressionRequest
@ -41,6 +39,4 @@ class ValidateExpressionRequest extends FormRequest
{
return ['expression' => ['required', new IsValidActionExpression()]];
}
}

View File

@ -31,7 +31,6 @@ use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Log;
/**
* FireflyIII\Models\RuleAction
@ -67,7 +66,7 @@ class RuleAction extends Model
use ReturnsIntegerIdTrait;
protected $casts
= [
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'active' => 'boolean',
@ -80,12 +79,14 @@ class RuleAction extends Model
public function getValue(array $journal): string
{
if (false === config('firefly.feature_flags.expression_engine')) {
Log::debug('Expression engine is disabled, returning action value as string.');
\Log::debug('Expression engine is disabled, returning action value as string.');
return (string)$this->action_value;
}
$expr = new ActionExpression($this->action_value);
$result = $expr->evaluate($journal);
Log::debug(sprintf('Expression engine is enabled, result of expression "%s" is "%s".', $this->action_value, $result));
\Log::debug(sprintf('Expression engine is enabled, result of expression "%s" is "%s".', $this->action_value, $result));
return $result;
}
@ -97,14 +98,14 @@ class RuleAction extends Model
protected function order(): Attribute
{
return Attribute::make(
get: static fn($value) => (int)$value,
get: static fn ($value) => (int)$value,
);
}
protected function ruleId(): Attribute
{
return Attribute::make(
get: static fn($value) => (int)$value,
get: static fn ($value) => (int)$value,
);
}
}

View File

@ -44,7 +44,7 @@ class IsValidActionExpression implements ValidationRule
return;
}
$value ??= '';
$expr = new ActionExpression($value);
$expr = new ActionExpression($value);
if (!$expr->isValid()) {
$fail('validation.rule_action_expression')->translate(

View File

@ -34,8 +34,8 @@ use FireflyIII\TransactionRules\Traits\RefreshNotesTrait;
*/
class AppendDescription implements ActionInterface
{
private RuleAction $action;
use RefreshNotesTrait;
private RuleAction $action;
/**
* TriggerInterface constructor.

View File

@ -51,6 +51,7 @@ class AppendDescriptionToNotes implements ActionInterface
public function actOnArray(array $journal): bool
{
$this->refreshNotes($journal);
/** @var null|TransactionJournal $object */
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
if (null === $object) {

View File

@ -27,6 +27,7 @@ use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\Note;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\TransactionRules\Traits\RefreshNotesTrait;
/**
* Class AppendNotes.
@ -34,6 +35,7 @@ use FireflyIII\Models\TransactionJournal;
*/
class AppendNotes implements ActionInterface
{
use RefreshNotesTrait;
private RuleAction $action;
/**
@ -46,6 +48,7 @@ class AppendNotes implements ActionInterface
public function actOnArray(array $journal): bool
{
$this->refreshNotes($journal);
$dbNote = Note::where('noteable_id', (int)$journal['transaction_journal_id'])
->where('noteable_type', TransactionJournal::class)
->first(['notes.*'])

View File

@ -30,6 +30,7 @@ use FireflyIII\Models\Note;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\TransactionRules\Traits\RefreshNotesTrait;
/**
* Class AppendNotesToDescription
@ -38,7 +39,7 @@ use FireflyIII\Support\Request\ConvertsDataTypes;
class AppendNotesToDescription implements ActionInterface
{
use ConvertsDataTypes;
use RefreshNotesTrait;
private RuleAction $action;
/**
@ -52,6 +53,7 @@ class AppendNotesToDescription implements ActionInterface
public function actOnArray(array $journal): bool
{
app('log')->debug('Now in AppendNotesToDescription');
$this->refreshNotes($journal);
/** @var null|TransactionJournal $object */
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);

View File

@ -26,12 +26,14 @@ namespace FireflyIII\TransactionRules\Actions;
use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\TransactionRules\Traits\RefreshNotesTrait;
/**
* Class SetDescription.
*/
class SetDescription implements ActionInterface
{
use RefreshNotesTrait;
private RuleAction $action;
/**
@ -44,6 +46,8 @@ class SetDescription implements ActionInterface
public function actOnArray(array $journal): bool
{
$this->refreshNotes($journal);
/** @var TransactionJournal $object */
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
$before = $object->description;

View File

@ -53,10 +53,10 @@ class SearchRuleEngine implements RuleEngineInterface
public function __construct()
{
$this->rules = new Collection();
$this->groups = new Collection();
$this->operators = [];
$this->resultCount = [];
$this->rules = new Collection();
$this->groups = new Collection();
$this->operators = [];
$this->resultCount = [];
// always collect the triggers from the database, unless indicated otherwise.
$this->refreshTriggers = true;
@ -73,7 +73,7 @@ class SearchRuleEngine implements RuleEngineInterface
app('log')->debug('SearchRuleEngine::find()');
$collection = new Collection();
foreach ($this->rules as $rule) {
$found = new Collection();
$found = new Collection();
if (true === $rule->strict) {
$found = $this->findStrictRule($rule);
}
@ -82,8 +82,9 @@ class SearchRuleEngine implements RuleEngineInterface
}
$collection = $collection->merge($found);
}
$result = $collection->unique();
$result = $collection->unique();
app('log')->debug(sprintf('SearchRuleEngine::find() returns %d unique transactions.', $result->count()));
return $result;
}
@ -93,8 +94,8 @@ class SearchRuleEngine implements RuleEngineInterface
private function findStrictRule(Rule $rule): Collection
{
app('log')->debug(sprintf('Now in findStrictRule(#%d)', $rule->id ?? 0));
$searchArray = [];
$triggers = [];
$searchArray = [];
$triggers = [];
if ($this->refreshTriggers) {
$triggers = $rule->ruleTriggers()->orderBy('order', 'ASC')->get();
}
@ -125,7 +126,7 @@ class SearchRuleEngine implements RuleEngineInterface
app('log')->debug(sprintf('SearchRuleEngine:: add local added operator: %s:"%s"', $operator['type'], $operator['value']));
$searchArray[$operator['type']][] = sprintf('"%s"', $operator['value']);
}
$date = today(config('app.timezone'));
$date = today(config('app.timezone'));
if ($this->hasSpecificJournalTrigger($searchArray)) {
$date = $this->setDateFromJournalTrigger($searchArray);
}
@ -145,7 +146,7 @@ class SearchRuleEngine implements RuleEngineInterface
}
}
$result = $searchEngine->searchTransactions();
$result = $searchEngine->searchTransactions();
return $result->getCollection();
}
@ -170,7 +171,7 @@ class SearchRuleEngine implements RuleEngineInterface
$dateTrigger = true;
}
}
$result = $journalTrigger && $dateTrigger;
$result = $journalTrigger && $dateTrigger;
app('log')->debug(sprintf('Result of hasSpecificJournalTrigger is %s.', var_export($result, true)));
return $result;
@ -189,7 +190,7 @@ class SearchRuleEngine implements RuleEngineInterface
if (0 !== $journalId) {
$repository = app(JournalRepositoryInterface::class);
$repository->setUser($this->user);
$journal = $repository->find($journalId);
$journal = $repository->find($journalId);
if (null !== $journal) {
$date = $journal->date;
app('log')->debug(sprintf('Found journal #%d with date %s.', $journal->id, $journal->date->format('Y-m-d')));
@ -265,10 +266,10 @@ class SearchRuleEngine implements RuleEngineInterface
$searchEngine->parseQuery(sprintf('%s:%s', $type, $value));
}
$result = $searchEngine->searchTransactions();
$collection = $result->getCollection();
$result = $searchEngine->searchTransactions();
$collection = $result->getCollection();
app('log')->debug(sprintf('Found in this run, %d transactions', $collection->count()));
$total = $total->merge($collection);
$total = $total->merge($collection);
app('log')->debug(sprintf('Total collection is now %d transactions', $total->count()));
++$count;
// if trigger says stop processing, do so.
@ -282,7 +283,7 @@ class SearchRuleEngine implements RuleEngineInterface
app('log')->debug(sprintf('Done running %d trigger(s)', $count));
// make collection unique
$unique = $total->unique(
$unique = $total->unique(
static function (array $group) {
$str = '';
foreach ($group['transactions'] as $transaction) {
@ -373,7 +374,7 @@ class SearchRuleEngine implements RuleEngineInterface
$this->processResults($rule, $collection);
app('log')->debug(sprintf('SearchRuleEngine:: done processing strict rule #%d', $rule->id));
$result = $collection->count() > 0;
$result = $collection->count() > 0;
if (true === $result) {
app('log')->debug(sprintf('SearchRuleEngine:: rule #%d was triggered (on %d transaction(s)).', $rule->id, $collection->count()));
@ -546,6 +547,7 @@ class SearchRuleEngine implements RuleEngineInterface
$transaction['notes'] = $dbNote->text;
}
Log::debug(sprintf('Notes of journal #%d filled in.', $transaction['transaction_journal_id']));
return $transaction;
}
}

View File

@ -31,26 +31,24 @@ class ActionExpressionLanguageProvider implements ExpressionFunctionProviderInte
{
public function getFunctions(): array
{
return [
new ExpressionFunction('constant', function ($str): string {
return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str . '!');
return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str.'!');
}, function ($arguments, $str): string {
if (!is_string($str)) {
return $str;
}
return strtolower($str . '!');
return strtolower($str.'!');
}),
new ExpressionFunction('enum', function ($str): string {
return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str . '?');
return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str.'?');
}, function ($arguments, $str): string {
if (!is_string($str)) {
return $str;
}
return strtolower($str) . '?';
return strtolower($str).'?';
}),
ExpressionFunction::fromPhp('substr'),

View File

@ -29,11 +29,6 @@ use Illuminate\Support\Facades\Log;
trait RefreshNotesTrait
{
/**
* @param array $transaction
*
* @return array
*/
final protected function refreshNotes(array $transaction): array
{
$transaction['notes'] = '';
@ -42,7 +37,7 @@ trait RefreshNotesTrait
$transaction['notes'] = $dbNote->text;
}
Log::debug(sprintf('Notes of journal #%d refreshed.', $transaction['transaction_journal_id']));
return $transaction;
}
}

View File

@ -607,7 +607,6 @@ Route::group(
Route::put('{rule}', ['uses' => 'UpdateController@update', 'as' => 'update']);
Route::delete('{rule}', ['uses' => 'DestroyController@destroy', 'as' => 'delete']);
Route::get('{rule}/test', ['uses' => 'TriggerController@testRule', 'as' => 'test']);
// TODO give results back
Route::post('{rule}/trigger', ['uses' => 'TriggerController@triggerRule', 'as' => 'trigger']);