diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php index f378bc448d..92f1a8e152 100644 --- a/app/Http/Controllers/RuleController.php +++ b/app/Http/Controllers/RuleController.php @@ -62,15 +62,45 @@ class RuleController extends Controller } /** - * @param RuleGroup $ruleGroup + * @param RuleFormRequest $request + * @param RuleRepositoryInterface $repository + * @param RuleGroup $ruleGroup * - * @return View + * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function storeRule(RuleFormRequest $request, RuleGroup $ruleGroup) + public function storeRule(RuleFormRequest $request, RuleRepositoryInterface $repository, RuleGroup $ruleGroup) { - echo '
';
- var_dump(Input::all());
- exit();
+
+
+ // process the rule itself:
+ $data = [
+ 'rule_group_id' => intval($request->get('rule_group_id')),
+ 'title' => $request->get('title'),
+ 'trigger' => $request->get('trigger'),
+ 'description' => $request->get('description'),
+ 'rule-triggers' => $request->get('rule-trigger'),
+ 'rule-trigger-values' => $request->get('rule-trigger-value'),
+ 'rule-trigger-stop' => $request->get('rule-trigger-stop'),
+ 'rule-actions' => $request->get('rule-action'),
+ 'rule-action-values' => $request->get('rule-action-value'),
+ 'rule-action-stop' => $request->get('rule-action-stop'),
+ 'stop_processing' => $request->get('stop_processing')
+ ];
+
+ $rule = $repository->storeRule($data);
+ Session::flash('success', trans('firefly.stored_new_rule', ['title' => $rule->title]));
+ Preferences::mark();
+
+ if (intval(Input::get('create_another')) === 1) {
+ // set value so create routine will not overwrite URL:
+ Session::put('rules.rule.create.fromStore', true);
+
+ return redirect(route('rules.rule.create', [$request->input('what')]))->withInput();
+ }
+
+ // redirect to previous URL.
+ return redirect(Session::get('rules.rule.create.url'));
+
}
/**
@@ -260,9 +290,29 @@ class RuleController extends Controller
}
/**
- * @param RuleGroup $budget
+ * @param RuleRepositoryInterface $repository
+ * @param Rule $rule
*
- * @return \Illuminate\View\View
+ * @return View
+ */
+ public function deleteRule(Rule $rule)
+ {
+ $subTitle = trans('firefly.delete_rule', ['title' => $rule->title]);
+
+ // put previous url in session
+ Session::put('rules.rule.delete.url', URL::previous());
+ Session::flash('gaEventCategory', 'rules');
+ Session::flash('gaEventAction', 'delete-rule');
+
+ return view('rules.rule.delete', compact('rule', 'subTitle'));
+ }
+
+
+ /**
+ * @param RuleRepositoryInterface $repository
+ * @param RuleGroup $ruleGroup
+ *
+ * @return View
*/
public function deleteRuleGroup(RuleRepositoryInterface $repository, RuleGroup $ruleGroup)
{
@@ -279,6 +329,25 @@ class RuleController extends Controller
return view('rules.rule-group.delete', compact('ruleGroup', 'subTitle', 'ruleGroupList'));
}
+ /**
+ * @param Rule $rule
+ * @param RuleRepositoryInterface $repository
+ *
+ * @return \Illuminate\Http\RedirectResponse
+ */
+ public function destroyRule(RuleRepositoryInterface $repository, Rule $rule)
+ {
+
+ $title = $rule->title;
+ $repository->destroyRule($rule);
+
+ Session::flash('success', trans('firefly.deleted_rule', ['title' => $title]));
+ Preferences::mark();
+
+
+ return redirect(Session::get('rules.rule.delete.url'));
+ }
+
/**
* @param RuleGroup $ruleGroup
* @param RuleRepositoryInterface $repository
diff --git a/app/Http/Requests/RuleFormRequest.php b/app/Http/Requests/RuleFormRequest.php
index e8f18055ab..be60f0e06a 100644
--- a/app/Http/Requests/RuleFormRequest.php
+++ b/app/Http/Requests/RuleFormRequest.php
@@ -41,7 +41,7 @@ class RuleFormRequest extends Request
$validActions = array_keys(Config::get('firefly.rule-actions'));
// some actions require text:
- $contextActions = Config::get('firefly.rule-actions-text');
+ $contextActions = join(',', Config::get('firefly.rule-actions-text'));
$titleRule = 'required|between:1,100|uniqueObjectForUser:rule_groups,title';
if (RuleGroup::find(Input::get('id'))) {
@@ -52,12 +52,17 @@ class RuleFormRequest extends Request
'title' => $titleRule,
'description' => 'between:1,5000',
'stop_processing' => 'boolean',
+ 'rule_group_id' => 'required|belongsToUser:rule_groups',
'trigger' => 'required|in:store-journal,update-journal',
'rule-trigger.*' => 'required|in:' . join(',', $validTriggers),
- 'rule-trigger-value.*' => 'required|min:1',
+ 'rule-trigger-value.*' => 'required|min:1|ruleTriggerValue',
'rule-action.*' => 'required|in:' . join(',', $validActions),
- 'rule-action-value.*' => 'required_if:rule-action.*,' . join(',', $contextActions)
];
+ // since Laravel does not support this stuff yet, here's a trick.
+ for ($i = 0; $i < 10; $i++) {
+ $rules['rule-action-value.' . $i] = 'required_if:rule-action.' . $i . ',' . $contextActions . '|ruleActionValue';
+ }
+ return $rules;
}
}
diff --git a/app/Repositories/Rule/RuleRepository.php b/app/Repositories/Rule/RuleRepository.php
index dbd61abd40..2c5cc8cc5d 100644
--- a/app/Repositories/Rule/RuleRepository.php
+++ b/app/Repositories/Rule/RuleRepository.php
@@ -11,10 +11,10 @@ namespace FireflyIII\Repositories\Rule;
use Auth;
use FireflyIII\Models\Rule;
+use FireflyIII\Models\RuleAction;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Models\RuleTrigger;
use Illuminate\Support\Collection;
-use Log;
/**
* Class RuleRepository
@@ -80,6 +80,7 @@ class RuleRepository implements RuleRepositoryInterface
/**
* @param Rule $rule
* @param array $ids
+ *
* @return bool
*/
public function reorderRuleTriggers(Rule $rule, array $ids)
@@ -101,6 +102,7 @@ class RuleRepository implements RuleRepositoryInterface
/**
* @param Rule $rule
* @param array $ids
+ *
* @return bool
*/
public function reorderRuleActions(Rule $rule, array $ids)
@@ -172,6 +174,7 @@ class RuleRepository implements RuleRepositoryInterface
/**
* @param Rule $rule
+ *
* @return bool
*/
public function moveRuleUp(Rule $rule)
@@ -192,6 +195,7 @@ class RuleRepository implements RuleRepositoryInterface
/**
* @param Rule $rule
+ *
* @return bool
*/
public function moveRuleDown(Rule $rule)
@@ -234,6 +238,7 @@ class RuleRepository implements RuleRepositoryInterface
/**
* @param RuleGroup $ruleGroup
+ *
* @return bool
*/
public function moveRuleGroupUp(RuleGroup $ruleGroup)
@@ -254,6 +259,7 @@ class RuleRepository implements RuleRepositoryInterface
/**
* @param RuleGroup $ruleGroup
+ *
* @return bool
*/
public function moveRuleGroupDown(RuleGroup $ruleGroup)
@@ -279,4 +285,128 @@ class RuleRepository implements RuleRepositoryInterface
{
return Auth::user()->ruleGroups()->orderBy('order', 'ASC')->get();
}
+
+ /**
+ * @param array $data
+ *
+ * @return Rule
+ */
+ public function storeRule(array $data)
+ {
+ /** @var RuleGroup $ruleGroup */
+ $ruleGroup = Auth::user()->ruleGroups()->find($data['rule_group_id']);
+
+ // get max order:
+ $order = $this->getHighestOrderInRuleGroup($ruleGroup);
+
+ // start by creating a new rule:
+ $rule = new Rule;
+ $rule->user()->associate(Auth::user());
+
+ $rule->rule_group_id = $data['rule_group_id'];
+ $rule->order = ($order + 1);
+ $rule->active = 1;
+ $rule->stop_processing = intval($data['stop_processing']) == 1;
+ $rule->title = $data['title'];
+ $rule->description = strlen($data['description']) > 0 ? $data['description'] : null;
+
+ $rule->save();
+
+ // start storing triggers:
+ $order = 1;
+ $stopProcessing = false;
+ $this->storeTrigger($rule, 'user_action', $data['trigger'], $stopProcessing, $order);
+ foreach ($data['rule-triggers'] as $index => $trigger) {
+ $value = $data['rule-trigger-values'][$index];
+ $stopProcessing = isset($data['rule-trigger-stop'][$index]) ? true : false;
+ $this->storeTrigger($rule, $trigger, $value, $stopProcessing, $order);
+ $order++;
+ }
+
+ // same for actions.
+ $order = 1;
+ foreach ($data['rule-actions'] as $index => $action) {
+ $value = $data['rule-action-values'][$index];
+ $stopProcessing = isset($data['rule-action-stop'][$index]) ? true : false;
+ $this->storeAction($rule, $action, $value, $stopProcessing, $order);
+ }
+
+ return $rule;
+ }
+
+ /**
+ * @param Rule $rule
+ * @param string $action
+ * @param string $value
+ * @param bool $stopProcessing
+ * @param int $order
+ *
+ * @return RuleTrigger
+ */
+ public function storeTrigger(Rule $rule, $action, $value, $stopProcessing, $order)
+ {
+ $ruleTrigger = new RuleTrigger;
+ $ruleTrigger->rule()->associate($rule);
+ $ruleTrigger->order = $order;
+ $ruleTrigger->active = 1;
+ $ruleTrigger->stop_processing = $stopProcessing;
+ $ruleTrigger->trigger_type = $action;
+ $ruleTrigger->trigger_value = $value;
+ $ruleTrigger->save();
+
+ return $ruleTrigger;
+ }
+
+ /**
+ * @param Rule $rule
+ *
+ * @return bool
+ */
+ public function destroyRule(Rule $rule)
+ {
+ foreach ($rule->ruleTriggers as $trigger) {
+ $trigger->delete();
+ }
+ foreach ($rule->ruleActions as $action) {
+ $action->delete();
+ }
+ $rule->delete();
+
+ return true;
+ }
+
+
+ /**
+ * @param RuleGroup $ruleGroup
+ *
+ * @return int
+ */
+ public function getHighestOrderInRuleGroup(RuleGroup $ruleGroup)
+ {
+ return intval($ruleGroup->rules()->max('order'));
+ }
+
+ /**
+ * @param Rule $rule
+ * @param string $action
+ * @param string $value
+ * @param bool $stopProcessing
+ * @param int $order
+ *
+ * @return RuleAction
+ */
+ public function storeAction(Rule $rule, $action, $value, $stopProcessing, $order)
+ {
+ $ruleAction = new RuleAction;
+ $ruleAction->rule()->associate($rule);
+ $ruleAction->order = $order;
+ $ruleAction->active = 1;
+ $ruleAction->stop_processing = $stopProcessing;
+ $ruleAction->action_type = $action;
+ $ruleAction->action_value = $value;
+ $ruleAction->save();
+
+
+ return $ruleAction;
+ }
}
\ No newline at end of file
diff --git a/app/Repositories/Rule/RuleRepositoryInterface.php b/app/Repositories/Rule/RuleRepositoryInterface.php
index 429cf79911..7980a473e1 100644
--- a/app/Repositories/Rule/RuleRepositoryInterface.php
+++ b/app/Repositories/Rule/RuleRepositoryInterface.php
@@ -10,7 +10,9 @@
namespace FireflyIII\Repositories\Rule;
use FireflyIII\Models\Rule;
+use FireflyIII\Models\RuleAction;
use FireflyIII\Models\RuleGroup;
+use FireflyIII\Models\RuleTrigger;
use Illuminate\Support\Collection;
/**
@@ -46,10 +48,17 @@ interface RuleRepositoryInterface
* @param RuleGroup $ruleGroup
* @param RuleGroup $moveTo
*
- * @return boolean
+ * @return bool
*/
public function destroyRuleGroup(RuleGroup $ruleGroup, RuleGroup $moveTo = null);
+ /**
+ * @param Rule $rule
+ *
+ * @return bool
+ */
+ public function destroyRule(Rule $rule);
+
/**
* @param Rule $rule
* @param array $ids
@@ -103,4 +112,41 @@ interface RuleRepositoryInterface
*/
public function getRuleGroups();
+ /**
+ * @param array $data
+ *
+ * @return Rule
+ */
+ public function storeRule(array $data);
+
+ /**
+ * @param RuleGroup $ruleGroup
+ *
+ * @return int
+ */
+ public function getHighestOrderInRuleGroup(RuleGroup $ruleGroup);
+
+
+ /**
+ * @param Rule $rule
+ * @param string $action
+ * @param string $value
+ * @param bool $stopProcessing
+ * @param int $order
+ *
+ * @return RuleTrigger
+ */
+ public function storeTrigger(Rule $rule, $action, $value, $stopProcessing, $order);
+
+ /**
+ * @param Rule $rule
+ * @param string $action
+ * @param string $value
+ * @param bool $stopProcessing
+ * @param int $order
+ *
+ * @return RuleAction
+ */
+ public function storeAction(Rule $rule, $action, $value, $stopProcessing, $order);
+
}
\ No newline at end of file
diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php
index 1503518a1d..4d1b62321e 100644
--- a/app/Validation/FireflyValidator.php
+++ b/app/Validation/FireflyValidator.php
@@ -8,7 +8,9 @@ use Crypt;
use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
+use FireflyIII\Models\Budget;
use FireflyIII\Models\PiggyBank;
+use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Validation\Validator;
@@ -39,7 +41,71 @@ class FireflyValidator extends Validator
* @param $value
* @param $parameters
*
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ * @return bool
+ */
+ public function validateRuleTriggerValue($attribute, $value, $parameters)
+ {
+ // loop all rule-triggers.
+ // check if rule-value matches the thing.
+ if (is_array($this->data['rule-trigger'])) {
+ foreach ($this->data['rule-trigger'] as $index => $name) {
+ $value = $this->data['rule-trigger-value'][$index] ?? false;
+ switch ($name) {
+ default:
+ return true;
+ case 'amount_less':
+ return is_numeric($value);
+ break;
+ case 'transaction_type':
+ echo 'Implement me!';
+ exit;
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param $attribute
+ * @param $value
+ * @param $parameters
+ *
+ * @return bool
+ */
+ public function validateRuleActionValue($attribute, $value, $parameters)
+ {
+ // loop all rule-actions.
+ // check if rule-action-value matches the thing.
+ if (is_array($this->data['rule-action'])) {
+ foreach ($this->data['rule-action'] as $index => $name) {
+ $value = $this->data['rule-action-value'][$index] ?? false;
+ switch ($name) {
+ default:
+ return true;
+ case 'set_budget':
+ /** @var BudgetRepositoryInterface $repository */
+ $repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
+ $budgets = $repository->getBudgets();
+ // count budgets, should have at least one
+ $count = $budgets->filter(
+ function (Budget $budget) use ($value) {
+ return $budget->name == $value;
+ }
+ )->count();
+
+ return ($count === 1);
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * @param $attribute
+ * @param $value
+ * @param $parameters
*
* @return bool
*/
diff --git a/public/js/rules/create-edit.js b/public/js/rules/create-edit.js
index 6ba0fa2c2f..13c4027f10 100644
--- a/public/js/rules/create-edit.js
+++ b/public/js/rules/create-edit.js
@@ -30,7 +30,7 @@ function addNewTrigger() {
function addNewAction() {
"use strict";
- triggerCount++;
+ actionCount++;
$.getJSON('json/action', {count: actionCount}).success(function (data) {
//console.log(data.html);
diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php
index b48de632fb..39cc843309 100644
--- a/resources/lang/en_US/firefly.php
+++ b/resources/lang/en_US/firefly.php
@@ -62,6 +62,8 @@ return [
'save_rules_by_moving' => 'Save these rule(s) by moving them to another rule group:',
'make_new_rule' => 'Make new rule in rule group ":title"',
'rule_help_stop_processing' => 'When you check this box, later rules in this group will not be executed.',
+ 'stored_new_rule' => 'Stored new rule with title ":title"',
+ 'deleted_rule' => 'Deleted rule with title ":title"',
'trigger' => 'Trigger',
'trigger_value' => 'Trigger on value',
diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php
index a8d6c60f32..ec273e435e 100644
--- a/resources/lang/en_US/form.php
+++ b/resources/lang/en_US/form.php
@@ -78,12 +78,14 @@ return [
'delete_currency' => 'Delete currency ":name"',
'delete_journal' => 'Delete transaction with description ":description"',
'delete_attachment' => 'Delete attachment ":name"',
+ 'delete_rule' => 'Delete rule ":title"',
'delete_rule_group' => 'Delete rule group ":title"',
'attachment_areYouSure' => 'Are you sure you want to delete the attachment named ":name"?',
'account_areYouSure' => 'Are you sure you want to delete the account named ":name"?',
'bill_areYouSure' => 'Are you sure you want to delete the bill named ":name"?',
- 'ruleGroup_areYouSure' => 'Are you sure you want to delete the rule group titles ":title"?',
+ 'rule_areYouSure' => 'Are you sure you want to delete the rule titled ":title"?',
+ 'ruleGroup_areYouSure' => 'Are you sure you want to delete the rule group titled ":title"?',
'budget_areYouSure' => 'Are you sure you want to delete the budget named ":name"?',
'category_areYouSure' => 'Are you sure you want to delete the category named ":name"?',
'currency_areYouSure' => 'Are you sure you want to delete the currency named ":name"?',
diff --git a/resources/lang/en_US/validation.php b/resources/lang/en_US/validation.php
index 21dbc4ed0e..88e58d3a19 100644
--- a/resources/lang/en_US/validation.php
+++ b/resources/lang/en_US/validation.php
@@ -1,6 +1,8 @@
'This value is invalid for the selected trigger.',
+ 'rule_action_value' => 'This value is invalid for the selected action.',
'invalid_domain' => 'Due to security constraints, you cannot register from this domain.',
'file_already_attached' => 'Uploaded file ":name" is already attached to this object.',
'file_attached' => 'Succesfully uploaded file ":name".',
diff --git a/resources/views/rules/rule/delete.twig b/resources/views/rules/rule/delete.twig
new file mode 100644
index 0000000000..45571583a4
--- /dev/null
+++ b/resources/views/rules/rule/delete.twig
@@ -0,0 +1,33 @@
+
+{% extends "./layout/default.twig" %}
+
+{% block breadcrumbs %}
+ {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, rule) }}
+{% endblock %}
+
+{% block content %}
+ {{ Form.open({'class' : 'form-horizontal','id' : 'destroy','url' : route('rules.rule.destroy',rule.id) }) }}
+
+
+
+
+ {{ trans('form.delete_rule', {'title': rule.title}) }}
+
+
+
+ {{ trans('form.permDeleteWarning') }}
+
+
+
+ {{ trans('form.rule_areYouSure', {'title': rule.title}) }}
+
+
+
+
+
+
+ {{ Form.close|raw }}
+{% endblock %}