diff --git a/app/Http/Controllers/PreferencesController.php b/app/Http/Controllers/PreferencesController.php
index 529993a8df..becfd42819 100644
--- a/app/Http/Controllers/PreferencesController.php
+++ b/app/Http/Controllers/PreferencesController.php
@@ -9,13 +9,16 @@
* See the LICENSE file for details.
*/
-declare(strict_types = 1);
+declare(strict_types=1);
+
namespace FireflyIII\Http\Controllers;
use FireflyIII\Http\Requests\TokenFormRequest;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use FireflyIII\Repositories\User\UserRepositoryInterface;
use Illuminate\Http\Request;
+use Log;
use PragmaRX\Google2FA\Contracts\Google2FA;
use Preferences;
use Session;
@@ -131,7 +134,7 @@ class PreferencesController extends Controller
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
- public function postIndex(Request $request)
+ public function postIndex(Request $request, UserRepositoryInterface $repository)
{
// front page accounts
$frontPageAccounts = [];
@@ -168,7 +171,7 @@ class PreferencesController extends Controller
$twoFactorAuthEnabled = false;
$hasTwoFactorAuthSecret = false;
- if (!auth()->user()->hasRole('demo')) {
+ if (!$repository->hasRole(auth()->user(), 'demo')) {
// two factor auth
$twoFactorAuthEnabled = intval($request->get('twoFactorAuthEnabled'));
$hasTwoFactorAuthSecret = !is_null(Preferences::get('twoFactorAuthSecret'));
diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php
index e2f7516dd8..b816a1e5bd 100644
--- a/app/Http/Controllers/ProfileController.php
+++ b/app/Http/Controllers/ProfileController.php
@@ -9,14 +9,16 @@
* See the LICENSE file for details.
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use FireflyIII\Exceptions\ValidationException;
+use FireflyIII\Http\Middleware\IsLimitedUser;
use FireflyIII\Http\Requests\DeleteAccountFormRequest;
use FireflyIII\Http\Requests\ProfileFormRequest;
use FireflyIII\Repositories\User\UserRepositoryInterface;
+use FireflyIII\User;
use Hash;
use Log;
use Session;
@@ -45,6 +47,8 @@ class ProfileController extends Controller
return $next($request);
}
);
+ $this->middleware(IsLimitedUser::class);
+
}
/**
@@ -52,16 +56,6 @@ class ProfileController extends Controller
*/
public function changePassword()
{
- if (intval(getenv('SANDSTORM')) === 1) {
- return view('error')->with('message', strval(trans('firefly.sandstorm_not_available')));
- }
-
- if (auth()->user()->hasRole('demo')) {
- Session::flash('info', strval(trans('firefly.cannot_change_demo')));
-
- return redirect(route('profile.index'));
- }
-
$title = auth()->user()->email;
$subTitle = strval(trans('firefly.change_your_password'));
$subTitleIcon = 'fa-key';
@@ -74,16 +68,6 @@ class ProfileController extends Controller
*/
public function deleteAccount()
{
- if (intval(getenv('SANDSTORM')) === 1) {
- return view('error')->with('message', strval(trans('firefly.sandstorm_not_available')));
- }
-
- if (auth()->user()->hasRole('demo')) {
- Session::flash('info', strval(trans('firefly.cannot_delete_demo')));
-
- return redirect(route('profile.index'));
- }
-
$title = auth()->user()->email;
$subTitle = strval(trans('firefly.delete_account'));
$subTitleIcon = 'fa-trash';
@@ -111,32 +95,18 @@ class ProfileController extends Controller
*/
public function postChangePassword(ProfileFormRequest $request, UserRepositoryInterface $repository)
{
- if (intval(getenv('SANDSTORM')) === 1) {
- return view('error')->with('message', strval(trans('firefly.sandstorm_not_available')));
- }
-
- if (auth()->user()->hasRole('demo')) {
- Session::flash('info', strval(trans('firefly.cannot_change_demo')));
-
- return redirect(route('profile.index'));
- }
-
- // old, new1, new2
- if (!Hash::check($request->get('current_password'), auth()->user()->password)) {
- Session::flash('error', strval(trans('firefly.invalid_current_password')));
-
- return redirect(route('profile.change-password'));
- }
+ // the request has already validated both new passwords must be equal.
+ $current = $request->get('current_password');
+ $new = $request->get('new_password');
try {
- $this->validatePassword($request->get('current_password'), $request->get('new_password'));
+ $this->validatePassword(auth()->user(), $current, $new);
} catch (ValidationException $e) {
Session::flash('error', $e->getMessage());
return redirect(route('profile.change-password'));
}
- // update the user with the new password.
$repository->changePassword(auth()->user(), $request->get('new_password'));
Session::flash('success', strval(trans('firefly.password_changed')));
@@ -151,17 +121,6 @@ class ProfileController extends Controller
*/
public function postDeleteAccount(UserRepositoryInterface $repository, DeleteAccountFormRequest $request)
{
- if (intval(getenv('SANDSTORM')) === 1) {
- return view('error')->with('message', strval(trans('firefly.sandstorm_not_available')));
- }
-
- if (auth()->user()->hasRole('demo')) {
- Session::flash('info', strval(trans('firefly.cannot_delete_demo')));
-
- return redirect(route('profile.index'));
- }
-
- // old, new1, new2
if (!Hash::check($request->get('password'), auth()->user()->password)) {
Session::flash('error', strval(trans('firefly.invalid_password')));
@@ -182,15 +141,21 @@ class ProfileController extends Controller
}
/**
- * @param string $old
+ * @param User $user
+ * @param string $current
* @param string $new
+ * @param string $newConfirmation
*
* @return bool
* @throws ValidationException
*/
- protected function validatePassword(string $old, string $new): bool
+ protected function validatePassword(User $user, string $current, string $new): bool
{
- if ($new === $old) {
+ if (!Hash::check($current, auth()->user()->password)) {
+ throw new ValidationException(strval(trans('firefly.invalid_current_password')));
+ }
+
+ if ($current === $new) {
throw new ValidationException(strval(trans('firefly.should_change')));
}
diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php
index a3ac8ab74a..92fd5c98cd 100644
--- a/app/Http/Controllers/ReportController.php
+++ b/app/Http/Controllers/ReportController.php
@@ -26,6 +26,7 @@ use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Collection;
+use Log;
use Preferences;
use Response;
use Session;
@@ -73,7 +74,7 @@ class ReportController extends Controller
public function auditReport(Collection $accounts, Carbon $start, Carbon $end)
{
if ($end < $start) {
- return view('error')->with('message', trans('firefly.end_after_start_date'));
+ return view('error')->with('message', trans('firefly.end_after_start_date')); // @codeCoverageIgnore
}
if ($start < session('first')) {
$start = session('first');
@@ -109,7 +110,7 @@ class ReportController extends Controller
public function budgetReport(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end)
{
if ($end < $start) {
- return view('error')->with('message', trans('firefly.end_after_start_date'));
+ return view('error')->with('message', trans('firefly.end_after_start_date')); // @codeCoverageIgnore
}
if ($start < session('first')) {
$start = session('first');
@@ -145,7 +146,7 @@ class ReportController extends Controller
public function categoryReport(Collection $accounts, Collection $categories, Carbon $start, Carbon $end)
{
if ($end < $start) {
- return view('error')->with('message', trans('firefly.end_after_start_date'));
+ return view('error')->with('message', trans('firefly.end_after_start_date')); // @codeCoverageIgnore
}
if ($start < session('first')) {
$start = session('first');
@@ -251,10 +252,9 @@ class ReportController extends Controller
/**
* @param ReportFormRequest $request
*
- * @return RedirectResponse
- * @throws FireflyException
+ * @return RedirectResponse|\Illuminate\Routing\Redirector
*/
- public function postIndex(ReportFormRequest $request): RedirectResponse
+ public function postIndex(ReportFormRequest $request)
{
// report type:
$reportType = $request->get('report_type');
@@ -266,6 +266,7 @@ class ReportController extends Controller
$tags = join(',', $request->getTagList()->pluck('tag')->toArray());
if ($request->getAccountList()->count() === 0) {
+ Log::debug('Account count is zero');
Session::flash('error', trans('firefly.select_more_than_one_account'));
return redirect(route('reports.index'));
@@ -293,14 +294,7 @@ class ReportController extends Controller
return view('error')->with('message', trans('firefly.end_after_start_date'));
}
- // lower threshold
- if ($start < session('first')) {
- $start = session('first');
- }
-
switch ($reportType) {
- default:
- throw new FireflyException(sprintf('Firefly does not support the "%s"-report yet.', $reportType));
case 'category':
$uri = route('reports.report.category', [$accounts, $categories, $start, $end]);
break;
@@ -332,7 +326,7 @@ class ReportController extends Controller
public function tagReport(Collection $accounts, Collection $tags, Carbon $start, Carbon $end)
{
if ($end < $start) {
- return view('error')->with('message', trans('firefly.end_after_start_date'));
+ return view('error')->with('message', trans('firefly.end_after_start_date')); // @codeCoverageIgnore
}
if ($start < session('first')) {
$start = session('first');
diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php
index cc8e896156..60461e1c53 100644
--- a/app/Http/Controllers/RuleController.php
+++ b/app/Http/Controllers/RuleController.php
@@ -9,7 +9,7 @@
* See the LICENSE file for details.
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
@@ -255,10 +255,11 @@ class RuleController extends Controller
Preferences::mark();
if (intval($request->get('create_another')) === 1) {
- // set value so create routine will not overwrite URL:
+ // @codeCoverageIgnoreStart
Session::put('rules.create.fromStore', true);
return redirect(route('rules.create', [$ruleGroup]))->withInput();
+ // @codeCoverageIgnoreEnd
}
return redirect($this->getPreviousUri('rules.create.uri'));
@@ -340,10 +341,11 @@ class RuleController extends Controller
Preferences::mark();
if (intval($request->get('return_to_edit')) === 1) {
- // set value so edit routine will not overwrite URL:
+ // @codeCoverageIgnoreStart
Session::put('rules.edit.fromUpdate', true);
return redirect(route('rules.edit', [$rule->id]))->withInput(['return_to_edit' => 1]);
+ // @codeCoverageIgnoreEnd
}
return redirect($this->getPreviousUri('rules.edit.uri'));
@@ -473,7 +475,7 @@ class RuleController extends Controller
$actions[] = view(
'rules.partials.action',
[
- 'oldTrigger' => $entry,
+ 'oldAction' => $entry,
'oldValue' => $request->old('rule-action-value')[$index],
'oldChecked' => $checked,
'count' => $count,
@@ -531,7 +533,7 @@ class RuleController extends Controller
if (is_array($data['rule-triggers'])) {
foreach ($data['rule-triggers'] as $index => $triggerType) {
$data['rule-trigger-stop'][$index] = $data['rule-trigger-stop'][$index] ?? 0;
- $triggers[] = [
+ $triggers[] = [
'type' => $triggerType,
'value' => $data['rule-trigger-values'][$index],
'stopProcessing' => intval($data['rule-trigger-stop'][$index]) === 1 ? true : false,
diff --git a/app/Http/Controllers/RuleGroupController.php b/app/Http/Controllers/RuleGroupController.php
index e0bc8b7476..12f9a0bb58 100644
--- a/app/Http/Controllers/RuleGroupController.php
+++ b/app/Http/Controllers/RuleGroupController.php
@@ -9,7 +9,7 @@
* See the LICENSE file for details.
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
@@ -217,10 +217,11 @@ class RuleGroupController extends Controller
Preferences::mark();
if (intval($request->get('create_another')) === 1) {
- // set value so create routine will not overwrite URL:
+ // @codeCoverageIgnoreStart
Session::put('rule-groups.create.fromStore', true);
return redirect(route('rule-groups.create'))->withInput();
+ // @codeCoverageIgnoreEnd
}
return redirect($this->getPreviousUri('rule-groups.create.uri'));
@@ -261,10 +262,11 @@ class RuleGroupController extends Controller
Preferences::mark();
if (intval($request->get('return_to_edit')) === 1) {
- // set value so edit routine will not overwrite URL:
+ // @codeCoverageIgnoreStart
Session::put('rule-groups.edit.fromUpdate', true);
return redirect(route('rule-groups.edit', [$ruleGroup->id]))->withInput(['return_to_edit' => 1]);
+ // @codeCoverageIgnoreEnd
}
// redirect to previous URL.
diff --git a/app/Http/Middleware/IsLimitedUser.php b/app/Http/Middleware/IsLimitedUser.php
new file mode 100644
index 0000000000..6b22eccda8
--- /dev/null
+++ b/app/Http/Middleware/IsLimitedUser.php
@@ -0,0 +1,61 @@
+guest()) {
+ if ($request->ajax()) {
+ return response('Unauthorized.', 401);
+ }
+
+ return redirect()->guest('login');
+ }
+ /** @var User $user */
+ $user = auth()->user();
+ if ($user->hasRole('demo')) {
+ Session::flash('warning', strval(trans('firefly.not_available_demo_user')));
+
+ return redirect(route('index'));
+ }
+
+ if (intval(getenv('SANDSTORM')) === 1) {
+ Session::flash('warning', strval(trans('firefly.sandstorm_not_available')));
+
+ return redirect(route('index'));
+ }
+
+ return $next($request);
+ }
+}
diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php
index f38a164993..ef8982988c 100644
--- a/app/Validation/FireflyValidator.php
+++ b/app/Validation/FireflyValidator.php
@@ -29,6 +29,7 @@ use Google2FA;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Translation\Translator;
use Illuminate\Validation\Validator;
+use Log;
use Session;
/**
diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php
index 38cea0b744..bb82214b04 100644
--- a/resources/lang/en_US/firefly.php
+++ b/resources/lang/en_US/firefly.php
@@ -124,7 +124,7 @@ return [
'journals_in_period_for_account' => 'All transactions for account :name between :start and :end',
'transferred' => 'Transferred',
'all_withdrawal' => 'All expenses',
- 'all_transactions' => 'All transactions',
+ 'all_transactions' => 'All transactions',
'title_withdrawal_between' => 'All expenses between :start and :end',
'all_deposit' => 'All revenue',
'title_deposit_between' => 'All revenue between :start and :end',
@@ -134,6 +134,7 @@ return [
'title_transfer_between' => 'All transfers between :start and :end',
'all_journals_for_category' => 'All transactions for category :name',
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
+ 'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
// repeat frequencies:
diff --git a/resources/views/rules/partials/action.twig b/resources/views/rules/partials/action.twig
index f7e7a0886d..a9927e7e15 100644
--- a/resources/views/rules/partials/action.twig
+++ b/resources/views/rules/partials/action.twig
@@ -10,11 +10,7 @@
diff --git a/tests/Feature/Controllers/PreferencesControllerTest.php b/tests/Feature/Controllers/PreferencesControllerTest.php
index bb23853f60..ca74cb177e 100644
--- a/tests/Feature/Controllers/PreferencesControllerTest.php
+++ b/tests/Feature/Controllers/PreferencesControllerTest.php
@@ -7,7 +7,7 @@
* See the LICENSE file for details.
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Tests\Feature\Controllers;
@@ -15,8 +15,10 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
+use FireflyIII\Repositories\User\UserRepositoryInterface;
use Illuminate\Support\Collection;
use PragmaRX\Google2FA\Contracts\Google2FA;
+use Preferences;
use Tests\TestCase;
/**
@@ -81,6 +83,34 @@ class PreferencesControllerTest extends TestCase
$response->assertSee('
');
}
+ /**
+ *
+ */
+ public function testPostCode()
+ {
+ $secret = '0123456789abcde';
+ $key = '123456';
+ $google = $this->mock(Google2FA::class);
+
+ $this->withoutMiddleware();
+ $this->session(['two-factor-secret' => $secret]);
+
+ Preferences::shouldReceive('set')->withArgs(['twoFactorAuthEnabled', 1])->once();
+ Preferences::shouldReceive('set')->withArgs(['twoFactorAuthSecret', $secret])->once();
+ Preferences::shouldReceive('mark')->once();
+
+ $google->shouldReceive('verifyKey')->withArgs([$secret, $key])->andReturn(true);
+
+ $data = [
+ 'code' => $key,
+ ];
+
+ $this->be($this->user());
+ $response = $this->post(route('preferences.code.store'), $data);
+ $response->assertStatus(302);
+ $response->assertSessionHas('success');
+ }
+
/**
* @covers \FireflyIII\Http\Controllers\PreferencesController::postIndex
*/
@@ -88,11 +118,13 @@ class PreferencesControllerTest extends TestCase
{
// mock stuff
$journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $userRepos = $this->mock(UserRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+ $userRepos->shouldReceive('hasRole')->andReturn(false);
$data = [
'fiscalYearStart' => '2016-01-01',
- 'frontPageAccounts' => [],
+ 'frontPageAccounts' => [1],
'viewRange' => '1M',
'customFiscalYear' => 0,
'showDepositsFrontpage' => 0,
@@ -109,4 +141,80 @@ class PreferencesControllerTest extends TestCase
$response->assertRedirect(route('preferences.index'));
}
+ /**
+ * User wants 2FA and has secret already.
+ *
+ * @covers \FireflyIII\Http\Controllers\PreferencesController::postIndex
+ */
+ public function testPostIndexWith2FA()
+ {
+ $this->withoutMiddleware();
+ // mock stuff
+ $userRepos = $this->mock(UserRepositoryInterface::class);
+ $userRepos->shouldReceive('hasRole')->andReturn(false);
+
+ // mock preferences (in a useful way?)
+ Preferences::shouldReceive('get')->withArgs(['twoFactorAuthSecret'])->andReturn('12345');
+ Preferences::shouldReceive('set');
+ Preferences::shouldReceive('mark');
+
+ $data = [
+ 'fiscalYearStart' => '2016-01-01',
+ 'frontPageAccounts' => [1],
+ 'viewRange' => '1M',
+ 'customFiscalYear' => 0,
+ 'showDepositsFrontpage' => 0,
+ 'transactionPageSize' => 100,
+ 'twoFactorAuthEnabled' => 1,
+ 'language' => 'en_US',
+ 'tj' => [],
+ ];
+
+ $this->be($this->user());
+ $response = $this->post(route('preferences.update'), $data);
+ $response->assertStatus(302);
+ $response->assertSessionHas('success');
+
+ // go to code to get a secret.
+ $response->assertRedirect(route('preferences.index'));
+ }
+
+ /**
+ * User wants 2FA and has no secret.
+ *
+ * @covers \FireflyIII\Http\Controllers\PreferencesController::postIndex
+ */
+ public function testPostIndexWithEmpty2FA()
+ {
+ $this->withoutMiddleware();
+ // mock stuff
+ $userRepos = $this->mock(UserRepositoryInterface::class);
+ $userRepos->shouldReceive('hasRole')->andReturn(false);
+
+ // mock preferences (in a useful way?)
+ Preferences::shouldReceive('get')->withArgs(['twoFactorAuthSecret'])->andReturn(null);
+ Preferences::shouldReceive('set');
+ Preferences::shouldReceive('mark');
+
+ $data = [
+ 'fiscalYearStart' => '2016-01-01',
+ 'frontPageAccounts' => [1],
+ 'viewRange' => '1M',
+ 'customFiscalYear' => 0,
+ 'showDepositsFrontpage' => 0,
+ 'transactionPageSize' => 100,
+ 'twoFactorAuthEnabled' => 1,
+ 'language' => 'en_US',
+ 'tj' => [],
+ ];
+
+ $this->be($this->user());
+ $response = $this->post(route('preferences.update'), $data);
+ $response->assertStatus(302);
+ $response->assertSessionHas('success');
+
+ // go to code to get a secret.
+ $response->assertRedirect(route('preferences.code'));
+ }
+
}
diff --git a/tests/Feature/Controllers/ProfileControllerTest.php b/tests/Feature/Controllers/ProfileControllerTest.php
index 3f682ee97b..6285462a39 100644
--- a/tests/Feature/Controllers/ProfileControllerTest.php
+++ b/tests/Feature/Controllers/ProfileControllerTest.php
@@ -7,7 +7,7 @@
* See the LICENSE file for details.
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Tests\Feature\Controllers;
@@ -72,6 +72,7 @@ class ProfileControllerTest extends TestCase
/**
* @covers \FireflyIII\Http\Controllers\ProfileController::postChangePassword
+ * @covers \FireflyIII\Http\Controllers\ProfileController::validatePassword
*/
public function testPostChangePassword()
{
@@ -92,6 +93,52 @@ class ProfileControllerTest extends TestCase
$response->assertSessionHas('success');
}
+ /**
+ * @covers \FireflyIII\Http\Controllers\ProfileController::postChangePassword
+ * @covers \FireflyIII\Http\Controllers\ProfileController::validatePassword
+ */
+ public function testPostChangePasswordNotCorrect()
+ {
+ // mock stuff
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+ $repository = $this->mock(UserRepositoryInterface::class);
+ $repository->shouldReceive('changePassword');
+
+ $data = [
+ 'current_password' => 'james3',
+ 'new_password' => 'james2',
+ 'new_password_confirmation' => 'james2',
+ ];
+ $this->be($this->user());
+ $response = $this->post(route('profile.change-password.post'), $data);
+ $response->assertStatus(302);
+ $response->assertSessionHas('error');
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\ProfileController::postChangePassword
+ * @covers \FireflyIII\Http\Controllers\ProfileController::validatePassword
+ */
+ public function testPostChangePasswordSameNew()
+ {
+ // mock stuff
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+ $repository = $this->mock(UserRepositoryInterface::class);
+ $repository->shouldReceive('changePassword');
+
+ $data = [
+ 'current_password' => 'james',
+ 'new_password' => 'james',
+ 'new_password_confirmation' => 'james',
+ ];
+ $this->be($this->user());
+ $response = $this->post(route('profile.change-password.post'), $data);
+ $response->assertStatus(302);
+ $response->assertSessionHas('error');
+ }
+
/**
* @covers \FireflyIII\Http\Controllers\ProfileController::postDeleteAccount
*/
@@ -101,7 +148,7 @@ class ProfileControllerTest extends TestCase
$journalRepos = $this->mock(JournalRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
$repository = $this->mock(UserRepositoryInterface::class);
- $repository->shouldReceive('destroy');
+ $repository->shouldReceive('destroy')->once();
$data = [
'password' => 'james',
];
@@ -111,4 +158,23 @@ class ProfileControllerTest extends TestCase
$response->assertRedirect(route('index'));
}
+ /**
+ * @covers \FireflyIII\Http\Controllers\ProfileController::postDeleteAccount
+ */
+ public function testPostDeleteAccountWrong()
+ {
+ // mock stuff
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+ $repository = $this->mock(UserRepositoryInterface::class);
+ $data = [
+ 'password' => 'james2',
+ ];
+ $this->be($this->user());
+ $response = $this->post(route('profile.delete-account.post'), $data);
+ $response->assertStatus(302);
+ $response->assertRedirect(route('profile.delete-account'));
+ $response->assertSessionHas('error');
+ }
+
}
diff --git a/tests/Feature/Controllers/ReportControllerTest.php b/tests/Feature/Controllers/ReportControllerTest.php
index f79d9c251b..fda8ce4aaf 100644
--- a/tests/Feature/Controllers/ReportControllerTest.php
+++ b/tests/Feature/Controllers/ReportControllerTest.php
@@ -7,7 +7,7 @@
* See the LICENSE file for details.
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Tests\Feature\Controllers;
@@ -51,7 +51,7 @@ class ReportControllerTest extends TestCase
$generator->shouldReceive('setStartDate')->once();
$generator->shouldReceive('setEndDate')->once();
$generator->shouldReceive('setAccounts')->once();
- $generator->shouldReceive('generate')->andReturn('here-be-report');
+ $generator->shouldReceive('generate')->andReturn('here-be-report')->once();
$this->be($this->user());
@@ -71,7 +71,7 @@ class ReportControllerTest extends TestCase
$generator->shouldReceive('setEndDate')->once();
$generator->shouldReceive('setAccounts')->once();
$generator->shouldReceive('setBudgets')->once();
- $generator->shouldReceive('generate')->andReturn('here-be-report');
+ $generator->shouldReceive('generate')->andReturn('here-be-report')->once();
$this->be($this->user());
$response = $this->get(route('reports.report.budget', [1, 1, '20160101', '20160131']));
@@ -90,7 +90,7 @@ class ReportControllerTest extends TestCase
$generator->shouldReceive('setEndDate')->once();
$generator->shouldReceive('setAccounts')->once();
$generator->shouldReceive('setCategories')->once();
- $generator->shouldReceive('generate')->andReturn('here-be-report');
+ $generator->shouldReceive('generate')->andReturn('here-be-report')->once();
$this->be($this->user());
$response = $this->get(route('reports.report.category', [1, 1, '20160101', '20160131']));
@@ -108,13 +108,28 @@ class ReportControllerTest extends TestCase
$generator->shouldReceive('setStartDate')->once();
$generator->shouldReceive('setEndDate')->once();
$generator->shouldReceive('setAccounts')->once();
- $generator->shouldReceive('generate')->andReturn('here-be-report');
+ $generator->shouldReceive('generate')->andReturn('here-be-report')->once();
$this->be($this->user());
$response = $this->get(route('reports.report.default', [1, '20160101', '20160131']));
$response->assertStatus(200);
}
+ /**
+ * @covers \FireflyIII\Http\Controllers\ReportController::defaultReport
+ */
+ public function testDefaultReportBadDate()
+ {
+ $generator = $this->mock(SYRG::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $this->be($this->user());
+ $response = $this->get(route('reports.report.default', [1, '20160101', '20150131']));
+ $response->assertStatus(200);
+ $response->assertSee('End date of report must be after start date.');
+ }
+
/**
* @covers \FireflyIII\Http\Controllers\ReportController::index
* @covers \FireflyIII\Http\Controllers\ReportController::__construct
@@ -204,14 +219,211 @@ class ReportControllerTest extends TestCase
/**
* @covers \FireflyIII\Http\Controllers\ReportController::postIndex
*/
- public function testPostIndex()
+ public function testPostIndexAuditOK()
{
$journalRepos = $this->mock(JournalRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+ $data = [
+ 'accounts' => ['1'],
+ 'daterange' => '2016-01-01 - 2016-01-31',
+ 'report_type' => 'audit',
+ ];
+
$this->be($this->user());
- $response = $this->post(route('reports.index.post'));
+ $response = $this->post(route('reports.index.post'), $data);
$response->assertStatus(302);
+ $response->assertRedirect(route('reports.report.audit', ['1', '20160101', '20160131']));
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\ReportController::postIndex
+ */
+ public function testPostIndexBudgetError()
+ {
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $data = [
+ 'accounts' => ['1'],
+ 'budget' => [],
+ 'daterange' => '2016-01-01 - 2016-01-31',
+ 'report_type' => 'budget',
+ ];
+
+ $this->be($this->user());
+ $response = $this->post(route('reports.index.post'), $data);
+ $response->assertStatus(302);
+ $response->assertRedirect(route('reports.index'));
+ $response->assertSessionHas('error');
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\ReportController::postIndex
+ */
+ public function testPostIndexBudgetOK()
+ {
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $data = [
+ 'accounts' => ['1'],
+ 'budget' => ['1'],
+ 'daterange' => '2016-01-01 - 2016-01-31',
+ 'report_type' => 'budget',
+ ];
+
+ $this->be($this->user());
+ $response = $this->post(route('reports.index.post'), $data);
+ $response->assertStatus(302);
+ $response->assertRedirect(route('reports.report.budget', ['1', '1', '20160101', '20160131']));
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\ReportController::postIndex
+ */
+ public function testPostIndexCategoryError()
+ {
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $data = [
+ 'accounts' => ['1'],
+ 'category' => [],
+ 'daterange' => '2016-01-01 - 2016-01-31',
+ 'report_type' => 'category',
+ ];
+
+ $this->be($this->user());
+ $response = $this->post(route('reports.index.post'), $data);
+ $response->assertStatus(302);
+ $response->assertRedirect(route('reports.index'));
+ $response->assertSessionHas('error');
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\ReportController::postIndex
+ */
+ public function testPostIndexCategoryOK()
+ {
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $data = [
+ 'accounts' => ['1'],
+ 'category' => ['1'],
+ 'daterange' => '2016-01-01 - 2016-01-31',
+ 'report_type' => 'category',
+ ];
+
+ $this->be($this->user());
+ $response = $this->post(route('reports.index.post'), $data);
+ $response->assertStatus(302);
+ $response->assertRedirect(route('reports.report.category', ['1', '1', '20160101', '20160131']));
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\ReportController::postIndex
+ */
+ public function testPostIndexDefaultOK()
+ {
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $data = [
+ 'accounts' => ['1'],
+ 'daterange' => '2016-01-01 - 2016-01-31',
+ 'report_type' => 'default',
+ ];
+
+ $this->be($this->user());
+ $response = $this->post(route('reports.index.post'), $data);
+ $response->assertStatus(302);
+ $response->assertRedirect(route('reports.report.default', ['1', '20160101', '20160131']));
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\ReportController::postIndex
+ */
+ public function testPostIndexDefaultStartEnd()
+ {
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $data = [
+ 'accounts' => ['1'],
+ 'daterange' => '2016-01-01 - 2015-01-31',
+ 'report_type' => 'default',
+ ];
+
+ $this->be($this->user());
+ $response = $this->post(route('reports.index.post'), $data);
+ $response->assertStatus(200);
+ $response->assertSee('End date of report must be after start date.');
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\ReportController::postIndex
+ */
+ public function testPostIndexTagError()
+ {
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $data = [
+ 'accounts' => ['1'],
+ 'tag' => [],
+ 'daterange' => '2016-01-01 - 2016-01-31',
+ 'report_type' => 'tag',
+ ];
+
+ $this->be($this->user());
+ $response = $this->post(route('reports.index.post'), $data);
+ $response->assertStatus(302);
+ $response->assertRedirect(route('reports.index'));
+ $response->assertSessionHas('error');
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\ReportController::postIndex
+ */
+ public function testPostIndexTagOK()
+ {
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $data = [
+ 'accounts' => ['1'],
+ 'tag' => ['housing'],
+ 'daterange' => '2016-01-01 - 2016-01-31',
+ 'report_type' => 'tag',
+ ];
+
+ $this->be($this->user());
+ $response = $this->post(route('reports.index.post'), $data);
+ $response->assertStatus(302);
+ $response->assertRedirect(route('reports.report.tag', ['1', 'housing', '20160101', '20160131']));
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\ReportController::postIndex
+ */
+ public function testPostIndexZeroAccounts()
+ {
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $data = [
+ 'accounts' => [],
+ 'daterange' => '2016-01-01 - 2016-01-31',
+ 'report_type' => 'default',
+ ];
+
+ $this->be($this->user());
+ $response = $this->post(route('reports.index.post'), $data);
+ $response->assertStatus(302);
+ $response->assertRedirect(route('reports.index'));
+ $response->assertSessionHas('error');
}
/**
diff --git a/tests/Feature/Controllers/RuleControllerTest.php b/tests/Feature/Controllers/RuleControllerTest.php
index 2927871e46..9ce386446b 100644
--- a/tests/Feature/Controllers/RuleControllerTest.php
+++ b/tests/Feature/Controllers/RuleControllerTest.php
@@ -7,16 +7,18 @@
* See the LICENSE file for details.
*/
-declare(strict_types = 1);
+declare(strict_types=1);
namespace Tests\Feature\Controllers;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup;
+use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
+use FireflyIII\Rules\TransactionMatcher;
use Illuminate\Support\Collection;
use Tests\TestCase;
@@ -30,13 +32,39 @@ class RuleControllerTest extends TestCase
/**
* @covers \FireflyIII\Http\Controllers\RuleController::create
- * @covers \FireflyIII\Http\Controllers\RuleController::getPreviousTriggers
- * @covers \FireflyIII\Http\Controllers\RuleController::getPreviousActions
*/
public function testCreate()
{
// mock stuff
- $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $this->be($this->user());
+ $response = $this->get(route('rules.create', [1]));
+ $response->assertStatus(200);
+ $response->assertSee('');
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\RuleController::create
+ * @covers \FireflyIII\Http\Controllers\RuleController::getPreviousTriggers
+ * @covers \FireflyIII\Http\Controllers\RuleController::getPreviousActions
+ */
+ public function testCreatePreviousInput()
+ {
+ $old = [
+ 'rule-trigger' => ['description_is'],
+ 'rule-trigger-stop' => ['1'],
+ 'rule-trigger-value' => ['X'],
+ 'rule-action' => ['set_category'],
+ 'rule-action-stop' => ['1'],
+ 'rule-action-value' => ['x'],
+ ];
+ $this->session(['_old_input' => $old]);
+
+
+ // mock stuff
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
$this->be($this->user());
@@ -51,7 +79,7 @@ class RuleControllerTest extends TestCase
public function testDelete()
{
// mock stuff
- $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
$this->be($this->user());
@@ -66,8 +94,8 @@ class RuleControllerTest extends TestCase
public function testDestroy()
{
// mock stuff
- $repository = $this->mock(RuleRepositoryInterface::class);
- $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $repository = $this->mock(RuleRepositoryInterface::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
$repository->shouldReceive('destroy');
@@ -85,8 +113,8 @@ class RuleControllerTest extends TestCase
public function testDown()
{
// mock stuff
- $repository = $this->mock(RuleRepositoryInterface::class);
- $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $repository = $this->mock(RuleRepositoryInterface::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
$repository->shouldReceive('moveDown');
@@ -98,12 +126,43 @@ class RuleControllerTest extends TestCase
/**
* @covers \FireflyIII\Http\Controllers\RuleController::edit
+ * @covers \FireflyIII\Http\Controllers\RuleController::getCurrentActions
+ * @covers \FireflyIII\Http\Controllers\RuleController::getCurrentTriggers
*/
public function testEdit()
{
// mock stuff
- $repository = $this->mock(RuleRepositoryInterface::class);
- $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $repository = $this->mock(RuleRepositoryInterface::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+ $repository->shouldReceive('getPrimaryTrigger')->andReturn(new Rule);
+
+ $this->be($this->user());
+ $response = $this->get(route('rules.edit', [1]));
+ $response->assertStatus(200);
+ $response->assertSee('');
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\RuleController::edit
+ * @covers \FireflyIII\Http\Controllers\RuleController::getPreviousActions
+ * @covers \FireflyIII\Http\Controllers\RuleController::getPreviousTriggers
+ */
+ public function testEditPreviousInput()
+ {
+ $old = [
+ 'rule-trigger' => ['description_is'],
+ 'rule-trigger-stop' => ['1'],
+ 'rule-trigger-value' => ['X'],
+ 'rule-action' => ['set_category'],
+ 'rule-action-stop' => ['1'],
+ 'rule-action-value' => ['x'],
+ ];
+ $this->session(['_old_input' => $old]);
+
+ // mock stuff
+ $repository = $this->mock(RuleRepositoryInterface::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
$repository->shouldReceive('getPrimaryTrigger')->andReturn(new Rule);
@@ -116,6 +175,8 @@ class RuleControllerTest extends TestCase
/**
* @covers \FireflyIII\Http\Controllers\RuleController::index
* @covers \FireflyIII\Http\Controllers\RuleController::__construct
+ * @covers \FireflyIII\Http\Controllers\RuleController::createDefaultRule
+ * @covers \FireflyIII\Http\Controllers\RuleController::createDefaultRuleGroup
*/
public function testIndex()
{
@@ -143,12 +204,12 @@ class RuleControllerTest extends TestCase
public function testReorderRuleActions()
{
// mock stuff
- $repository = $this->mock(RuleRepositoryInterface::class);
- $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $repository = $this->mock(RuleRepositoryInterface::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
- $data = ['triggers' => [1, 2, 3],];
- $repository->shouldReceive('reorderRuleActions');
+ $data = ['actions' => [1, 2, 3],];
+ $repository->shouldReceive('reorderRuleActions')->once();
$this->be($this->user());
$response = $this->post(route('rules.reorder-actions', [1]), $data);
@@ -161,12 +222,12 @@ class RuleControllerTest extends TestCase
public function testReorderRuleTriggers()
{
// mock stuff
- $repository = $this->mock(RuleRepositoryInterface::class);
- $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $repository = $this->mock(RuleRepositoryInterface::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
$data = ['triggers' => [1, 2, 3],];
- $repository->shouldReceive('reorderRuleTriggers');
+ $repository->shouldReceive('reorderRuleTriggers')->once();
$this->be($this->user());
$response = $this->post(route('rules.reorder-triggers', [1]), $data);
@@ -179,8 +240,8 @@ class RuleControllerTest extends TestCase
public function testStore()
{
// mock stuff
- $repository = $this->mock(RuleRepositoryInterface::class);
- $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $repository = $this->mock(RuleRepositoryInterface::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
$ruleGroupRepos = $this->mock(RuleGroupRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
@@ -217,15 +278,73 @@ class RuleControllerTest extends TestCase
* This actually hits an error and not the actually code but OK.
*
* @covers \FireflyIII\Http\Controllers\RuleController::testTriggers
+ * @covers \FireflyIII\Http\Controllers\RuleController::getValidTriggerList
*/
- public function testTestTriggers()
+ public function testTestTriggersError()
{
- // mock stuff
$journalRepos = $this->mock(JournalRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
$this->be($this->user());
- $response = $this->get(route('rules.test-triggers', [1]));
+ $uri = route('rules.test-triggers');
+ $response = $this->get($uri);
+ $response->assertStatus(200);
+ }
+ /**
+ *
+ * @covers \FireflyIII\Http\Controllers\RuleController::testTriggers
+ * @covers \FireflyIII\Http\Controllers\RuleController::getValidTriggerList
+ */
+ public function testTestTriggers()
+ {
+ $data = [
+ 'rule-trigger' => ['description_is'],
+ 'rule-trigger-value' => ['Bla bla'],
+ 'rule-trigger-stop' => ['1'],
+ ];
+
+ // mock stuff
+ $matcher = $this->mock(TransactionMatcher::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $matcher->shouldReceive('setLimit')->withArgs([10])->andReturnSelf()->once();
+ $matcher->shouldReceive('setRange')->withArgs([200])->andReturnSelf()->once();
+ $matcher->shouldReceive('setTriggers')->andReturnSelf()->once();
+ $matcher->shouldReceive('findMatchingTransactions')->andReturn(new Collection);
+
+ $this->be($this->user());
+ $uri = route('rules.test-triggers') . '?' . http_build_query($data);
+ $response = $this->get($uri);
+ $response->assertStatus(200);
+ }
+
+ /**
+ * @covers \FireflyIII\Http\Controllers\RuleController::testTriggers
+ * @covers \FireflyIII\Http\Controllers\RuleController::getValidTriggerList
+ */
+ public function testTestTriggersMax()
+ {
+ $data = [
+ 'rule-trigger' => ['description_is'],
+ 'rule-trigger-value' => ['Bla bla'],
+ 'rule-trigger-stop' => ['1'],
+ ];
+ $set = factory(Transaction::class, 10)->make();
+
+ // mock stuff
+ $matcher = $this->mock(TransactionMatcher::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
+
+ $matcher->shouldReceive('setLimit')->withArgs([10])->andReturnSelf()->once();
+ $matcher->shouldReceive('setRange')->withArgs([200])->andReturnSelf()->once();
+ $matcher->shouldReceive('setTriggers')->andReturnSelf()->once();
+ $matcher->shouldReceive('findMatchingTransactions')->andReturn($set);
+
+ $this->be($this->user());
+ $uri = route('rules.test-triggers') . '?' . http_build_query($data);
+ $response = $this->get($uri);
$response->assertStatus(200);
}
@@ -252,8 +371,8 @@ class RuleControllerTest extends TestCase
public function testUpdate()
{
// mock stuff
- $repository = $this->mock(RuleRepositoryInterface::class);
- $journalRepos = $this->mock(JournalRepositoryInterface::class);
+ $repository = $this->mock(RuleRepositoryInterface::class);
+ $journalRepos = $this->mock(JournalRepositoryInterface::class);
$ruleGroupRepos = $this->mock(RuleGroupRepositoryInterface::class);
$journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal);
diff --git a/tests/Feature/Controllers/SearchControllerTest.php b/tests/Feature/Controllers/SearchControllerTest.php
index f36cd66c3b..da2426d5cf 100644
--- a/tests/Feature/Controllers/SearchControllerTest.php
+++ b/tests/Feature/Controllers/SearchControllerTest.php
@@ -25,7 +25,7 @@ class SearchControllerTest extends TestCase
/**
* @covers \FireflyIII\Http\Controllers\SearchController::index
- * Implement testIndex().
+ * @covers \FireflyIII\Http\Controllers\SearchController::__construct
*/
public function testIndex()
{