diff --git a/README.md b/README.md index 352f3728fb..bc71424d42 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Firefly III (v3.3.8) +Firefly III (v3.3.9) =========== [![Build Status](https://travis-ci.org/JC5/firefly-iii.svg?branch=develop)](https://travis-ci.org/JC5/firefly-iii) @@ -22,7 +22,9 @@ laptop and [Firefly II](https://github.com/JC5/Firefly) is live. If you're not sure if this tool is for you, please read the [full description](https://github.com/JC5/firefly-iii/wiki/full-description). To install and use Firefly III, please read [the installation guide](https://github.com/JC5/firefly-iii/wiki/Installation), - [the upgrade guide](https://github.com/JC5/firefly-iii/wiki/Upgrade-instructions) (if applicable) and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)** + [the upgrade guide](https://github.com/JC5/firefly-iii/wiki/Upgrade-instructions) (if applicable) and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)**. + +If you want to try out Firefly III, you can do so on [this dedicated website](https://geld.nder.be/). This site always runs the latest version of Firefly III. If you want to use it, please read the [privacy considerations](https://github.com/JC5/firefly-iii/wiki/Privacy-on-demo-site) for this demo-site. ## Current features diff --git a/app/Helpers/Report/ReportQuery.php b/app/Helpers/Report/ReportQuery.php index f2ab84ea62..908c2c546b 100644 --- a/app/Helpers/Report/ReportQuery.php +++ b/app/Helpers/Report/ReportQuery.php @@ -230,7 +230,7 @@ class ReportQuery implements ReportQueryInterface // any deposit is fine. $query->where('transaction_types.type', 'Deposit'); } - $query->groupBy('t_from.account_id')->orderBy('transaction_journals.date'); + $query->groupBy('transaction_journals.id')->orderBy('transaction_journals.date'); // get everything, decrypt and return $data = $query->get( diff --git a/app/Http/Controllers/PiggyBankController.php b/app/Http/Controllers/PiggyBankController.php index d219359656..82960a5dc9 100644 --- a/app/Http/Controllers/PiggyBankController.php +++ b/app/Http/Controllers/PiggyBankController.php @@ -1,12 +1,12 @@ accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']) - ); + $periods = Config::get('firefly.piggy_bank_periods'); + $accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account'])); + //Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']) + // ); $subTitle = 'Create new piggy bank'; $subTitleIcon = 'fa-plus'; @@ -95,11 +95,12 @@ class PiggyBankController extends Controller * * @return \Illuminate\Http\RedirectResponse */ - public function destroy(PiggyBank $piggyBank) + public function destroy(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository) { + Session::flash('success', 'Piggy bank "' . e($piggyBank->name) . '" deleted.'); - $piggyBank->delete(); + $repository->destroy($piggyBank); return Redirect::to(Session::get('piggy-banks.delete.url')); } @@ -111,13 +112,11 @@ class PiggyBankController extends Controller * * @return $this */ - public function edit(PiggyBank $piggyBank) + public function edit(PiggyBank $piggyBank, AccountRepositoryInterface $repository) { $periods = Config::get('firefly.piggy_bank_periods'); - $accounts = ExpandedForm::makeSelectList( - Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']) - ); + $accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account'])); $subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"'; $subTitleIcon = 'fa-pencil'; @@ -151,16 +150,16 @@ class PiggyBankController extends Controller /** * @return $this */ - public function index(AccountRepositoryInterface $repository) + public function index(AccountRepositoryInterface $repository, PiggyBankRepositoryInterface $piggyRepository) { /** @var Collection $piggyBanks */ - $piggyBanks = Auth::user()->piggyBanks()->orderBy('order', 'ASC')->get(); + $piggyBanks = $piggyRepository->getPiggyBanks(); $accounts = []; /** @var PiggyBank $piggyBank */ foreach ($piggyBanks as $piggyBank) { $piggyBank->savedSoFar = floatval($piggyBank->currentRelevantRep()->currentamount); - $piggyBank->percentage = intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100); + $piggyBank->percentage = $piggyBank->savedSoFar != 0 ? intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100) : 0; $piggyBank->leftToSave = $piggyBank->targetamount - $piggyBank->savedSoFar; /* @@ -223,8 +222,8 @@ class PiggyBankController extends Controller $repetition->currentamount += $amount; $repetition->save(); - // create event. - PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]); + // create event + $repository->createEvent($piggyBank, $amount); /* * Create event! @@ -244,7 +243,7 @@ class PiggyBankController extends Controller * * @return \Illuminate\Http\RedirectResponse */ - public function postRemove(PiggyBank $piggyBank) + public function postRemove(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository) { $amount = floatval(Input::get('amount')); @@ -255,12 +254,8 @@ class PiggyBankController extends Controller $repetition->currentamount -= $amount; $repetition->save(); - PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount * -1, 'piggy_bank_id' => $piggyBank->id]); - - /* - * Create event! - */ - //Event::fire('piggy_bank.removeMoney', [$piggyBank, $amount]); // new and used. + // create event + $repository->createEvent($piggyBank, $amount * -1); Session::flash('success', 'Removed ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".'); } else { @@ -287,10 +282,9 @@ class PiggyBankController extends Controller * * @return $this */ - public function show(PiggyBank $piggyBank) + public function show(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository) { - - $events = $piggyBank->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get(); + $events = $repository->getEvents($piggyBank); /* * Number of reminders: @@ -310,6 +304,7 @@ class PiggyBankController extends Controller */ public function store(PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository) { + $piggyBankData = [ 'name' => $request->get('name'), 'startdate' => new Carbon, @@ -354,7 +349,6 @@ class PiggyBankController extends Controller 'remind_me' => $request->get('remind_me') ]; - $piggyBank = $repository->update($piggyBank, $piggyBankData); Session::flash('success', 'Updated piggy bank "' . e($piggyBank->name) . '".'); diff --git a/app/Http/Controllers/PreferencesController.php b/app/Http/Controllers/PreferencesController.php index 298b14d8f5..7df980e19f 100644 --- a/app/Http/Controllers/PreferencesController.php +++ b/app/Http/Controllers/PreferencesController.php @@ -1,6 +1,6 @@ accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']); + $accounts = $repository->getAccounts(['Default account', 'Asset account']); $viewRange = Preferences::get('viewRange', '1M'); $viewRangeValue = $viewRange->data; $frontPage = Preferences::get('frontPageAccounts', []); diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index a74e6a0960..2c61ff4bdd 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -2,6 +2,7 @@ use Auth; use FireflyIII\Http\Requests; +use FireflyIII\Http\Requests\DeleteAccountFormRequest; use FireflyIII\Http\Requests\ProfileFormRequest; use Hash; use Redirect; @@ -34,6 +35,36 @@ class ProfileController extends Controller return view('profile.index')->with('title', 'Profile')->with('subTitle', Auth::user()->email)->with('mainTitleIcon', 'fa-user'); } + + /** + * @return \Illuminate\View\View + */ + public function deleteAccount() + { + return view('profile.delete-account')->with('title', Auth::user()->email)->with('subTitle', 'Delete account')->with( + 'mainTitleIcon', 'fa-user' + ); + } + + /** + * + */ + public function postDeleteAccount(DeleteAccountFormRequest $request) { + // old, new1, new2 + if (!Hash::check($request->get('password'), Auth::user()->password)) { + Session::flash('error', 'Invalid password!'); + + return Redirect::route('delete-account'); + } + + // DELETE! + Auth::user()->delete(); + Session::flush(); + return Redirect::route('index'); + } + + + /** * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View */ diff --git a/app/Http/Requests/DeleteAccountFormRequest.php b/app/Http/Requests/DeleteAccountFormRequest.php new file mode 100644 index 0000000000..05f928ab8b --- /dev/null +++ b/app/Http/Requests/DeleteAccountFormRequest.php @@ -0,0 +1,32 @@ + 'required', + ]; + } +} diff --git a/app/Http/routes.php b/app/Http/routes.php index 274cc21d5a..117edea60e 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -282,6 +282,8 @@ Route::group( */ Route::get('/profile', ['uses' => 'ProfileController@index', 'as' => 'profile']); Route::get('/profile/change-password', ['uses' => 'ProfileController@changePassword', 'as' => 'change-password']); + Route::get('/profile/delete-account', ['uses' => 'ProfileController@deleteAccount', 'as' => 'delete-account']); + Route::post('/profile/delete-account', ['uses' => 'ProfileController@postDeleteAccount', 'as' => 'delete-account-post']); Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword', 'as' => 'change-password-post']); /** diff --git a/app/Repositories/PiggyBank/PiggyBankRepository.php b/app/Repositories/PiggyBank/PiggyBankRepository.php index ecabb40237..de620494c8 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepository.php +++ b/app/Repositories/PiggyBank/PiggyBankRepository.php @@ -3,8 +3,10 @@ namespace FireflyIII\Repositories\PiggyBank; use Auth; +use Carbon\Carbon; use DB; use FireflyIII\Models\PiggyBank; +use FireflyIII\Models\PiggyBankEvent; use FireflyIII\Models\PiggyBankRepetition; use Illuminate\Support\Collection; use Navigation; @@ -69,6 +71,19 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface return $bars; } + /** + * @param PiggyBank $piggyBank + * @param $amount + * + * @return bool + */ + public function createEvent(PiggyBank $piggyBank, $amount) + { + PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]); + + return true; + } + /** * @param array $data * @@ -87,6 +102,16 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface return $part; } + /** + * @param PiggyBank $piggyBank + * + * @return bool + */ + public function destroy(PiggyBank $piggyBank) + { + return $piggyBank->delete(); + } + /** * @param PiggyBank $piggyBank * @@ -97,7 +122,32 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface return DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]); } + /** + * @param PiggyBank $piggyBank + * + * @return Collection + */ + public function getEvents(PiggyBank $piggyBank) + { + return $piggyBank->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get(); + } + /** + * @return Collection + */ + public function getPiggyBanks() + { + /** @var Collection $set */ + $set = Auth::user()->piggyBanks()->orderBy('order', 'ASC')->get(); + + $set->sortBy( + function (PiggyBank $piggyBank) { + return $piggyBank->name; + } + ); + + return $set; + } /** * Set all piggy banks to order 0. diff --git a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php index bc445cad87..b34345795f 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php +++ b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php @@ -27,6 +27,18 @@ interface PiggyBankRepositoryInterface */ public function calculateParts(PiggyBankRepetition $repetition); + /** + * @return Collection + */ + public function getPiggyBanks(); + + /** + * @param PiggyBank $piggyBank + * + * @return Collection + */ + public function getEvents(PiggyBank $piggyBank); + /** * @param array $data * @@ -34,6 +46,14 @@ interface PiggyBankRepositoryInterface */ public function createPiggyBankPart(array $data); + /** + * @param PiggyBank $piggyBank + * @param $amount + * + * @return bool + */ + public function createEvent(PiggyBank $piggyBank, $amount); + /** * @param PiggyBank $piggyBank * @@ -41,6 +61,13 @@ interface PiggyBankRepositoryInterface */ public function getEventSummarySet(PiggyBank $piggyBank); + /** + * @param PiggyBank $piggyBank + * + * @return bool + */ + public function destroy(PiggyBank $piggyBank); + /** * Set all piggy banks to order 0. * diff --git a/composer.lock b/composer.lock index ed45ccf657..f1bab601ca 100644 --- a/composer.lock +++ b/composer.lock @@ -8,20 +8,20 @@ "packages": [ { "name": "classpreloader/classpreloader", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/ClassPreloader/ClassPreloader.git", - "reference": "f0bfbf71fb3335c9473f695d4d966ba2fb879a9f" + "reference": "0544616ba33fb2a6b792b3a7822650810c6d65d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/f0bfbf71fb3335c9473f695d4d966ba2fb879a9f", - "reference": "f0bfbf71fb3335c9473f695d4d966ba2fb879a9f", + "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/0544616ba33fb2a6b792b3a7822650810c6d65d9", + "reference": "0544616ba33fb2a6b792b3a7822650810c6d65d9", "shasum": "" }, "require": { - "nikic/php-parser": "~1.0", + "nikic/php-parser": "^1.2.2", "php": ">=5.3.3", "symfony/console": "~2.1", "symfony/filesystem": "~2.1", @@ -36,7 +36,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -64,7 +64,7 @@ "class", "preload" ], - "time": "2015-01-26 22:06:19" + "time": "2015-04-15 21:59:30" }, { "name": "danielstjules/stringy", @@ -206,16 +206,16 @@ }, { "name": "doctrine/annotations", - "version": "v1.2.3", + "version": "v1.2.4", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "eeda578cbe24a170331a1cfdf78be723412df7a4" + "reference": "b5202eb9e83f8db52e0e58867e0a46e63be8332e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/eeda578cbe24a170331a1cfdf78be723412df7a4", - "reference": "eeda578cbe24a170331a1cfdf78be723412df7a4", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/b5202eb9e83f8db52e0e58867e0a46e63be8332e", + "reference": "b5202eb9e83f8db52e0e58867e0a46e63be8332e", "shasum": "" }, "require": { @@ -270,20 +270,20 @@ "docblock", "parser" ], - "time": "2014-12-20 20:49:38" + "time": "2014-12-23 22:40:37" }, { "name": "doctrine/cache", - "version": "v1.4.0", + "version": "v1.4.1", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "2346085d2b027b233ae1d5de59b07440b9f288c8" + "reference": "c9eadeb743ac6199f7eec423cb9426bc518b7b03" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/2346085d2b027b233ae1d5de59b07440b9f288c8", - "reference": "2346085d2b027b233ae1d5de59b07440b9f288c8", + "url": "https://api.github.com/repos/doctrine/cache/zipball/c9eadeb743ac6199f7eec423cb9426bc518b7b03", + "reference": "c9eadeb743ac6199f7eec423cb9426bc518b7b03", "shasum": "" }, "require": { @@ -294,13 +294,13 @@ }, "require-dev": { "phpunit/phpunit": ">=3.7", - "predis/predis": "~0.8", + "predis/predis": "~1.0", "satooshi/php-coveralls": "~0.6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "1.5.x-dev" } }, "autoload": { @@ -340,25 +340,28 @@ "cache", "caching" ], - "time": "2015-01-15 20:38:55" + "time": "2015-04-15 00:11:59" }, { "name": "doctrine/collections", - "version": "v1.2", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "b99c5c46c87126201899afe88ec490a25eedd6a2" + "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/b99c5c46c87126201899afe88ec490a25eedd6a2", - "reference": "b99c5c46c87126201899afe88ec490a25eedd6a2", + "url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a", + "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a", "shasum": "" }, "require": { "php": ">=5.3.2" }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, "type": "library", "extra": { "branch-alias": { @@ -375,17 +378,6 @@ "MIT" ], "authors": [ - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com", - "homepage": "http://www.jwage.com/", - "role": "Creator" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com", - "homepage": "http://www.instaclick.com" - }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -394,11 +386,17 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, { "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "https://github.com/schmittjoh", - "role": "Developer of wrapped JMSSerializerBundle" + "email": "schmittjoh@gmail.com" } ], "description": "Collections Abstraction library", @@ -408,7 +406,7 @@ "collections", "iterator" ], - "time": "2014-02-03 23:07:43" + "time": "2015-04-14 22:21:58" }, { "name": "doctrine/common", @@ -3027,23 +3025,23 @@ }, { "name": "phpspec/phpspec", - "version": "2.1.1", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/phpspec/phpspec.git", - "reference": "66a1df93099282b1514e9e001fcf6e9393f7783d" + "reference": "9727d75919a00455433e867565bc022f0b985a39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/phpspec/zipball/66a1df93099282b1514e9e001fcf6e9393f7783d", - "reference": "66a1df93099282b1514e9e001fcf6e9393f7783d", + "url": "https://api.github.com/repos/phpspec/phpspec/zipball/9727d75919a00455433e867565bc022f0b985a39", + "reference": "9727d75919a00455433e867565bc022f0b985a39", "shasum": "" }, "require": { - "doctrine/instantiator": "~1.0,>=1.0.1", + "doctrine/instantiator": "^1.0.1", "php": ">=5.3.3", "phpspec/php-diff": "~1.0.0", - "phpspec/prophecy": "~1.1", + "phpspec/prophecy": "~1.4", "sebastian/exporter": "~1.0", "symfony/console": "~2.3", "symfony/event-dispatcher": "~2.1", @@ -3052,9 +3050,11 @@ "symfony/yaml": "~2.1" }, "require-dev": { - "behat/behat": "~3.0,>=3.0.11", + "behat/behat": "^3.0.11", "bossa/phpspec2-expect": "~1.0", - "symfony/filesystem": "~2.1" + "phpunit/phpunit": "~4.4", + "symfony/filesystem": "~2.1", + "symfony/process": "~2.1" }, "suggest": { "phpspec/nyan-formatters": "~1.0 – Adds Nyan formatters" @@ -3065,7 +3065,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "2.2.x-dev" } }, "autoload": { @@ -3099,7 +3099,7 @@ "testing", "tests" ], - "time": "2015-01-09 13:21:45" + "time": "2015-04-18 16:22:51" }, { "name": "phpspec/prophecy", @@ -3163,16 +3163,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "2.0.15", + "version": "2.0.16", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "34cc484af1ca149188d0d9e91412191e398e0b67" + "reference": "934fd03eb6840508231a7f73eb8940cf32c3b66c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/34cc484af1ca149188d0d9e91412191e398e0b67", - "reference": "34cc484af1ca149188d0d9e91412191e398e0b67", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/934fd03eb6840508231a7f73eb8940cf32c3b66c", + "reference": "934fd03eb6840508231a7f73eb8940cf32c3b66c", "shasum": "" }, "require": { @@ -3221,7 +3221,7 @@ "testing", "xunit" ], - "time": "2015-01-24 10:06:35" + "time": "2015-04-11 04:35:00" }, { "name": "phpunit/php-file-iterator", @@ -3360,16 +3360,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74" + "reference": "eab81d02569310739373308137284e0158424330" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/db32c18eba00b121c145575fcbcd4d4d24e6db74", - "reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/eab81d02569310739373308137284e0158424330", + "reference": "eab81d02569310739373308137284e0158424330", "shasum": "" }, "require": { @@ -3405,20 +3405,20 @@ "keywords": [ "tokenizer" ], - "time": "2015-01-17 09:51:32" + "time": "2015-04-08 04:46:07" }, { "name": "phpunit/phpunit", - "version": "4.6.1", + "version": "4.6.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "08b2aacdd8433abbba468f995d6d64b76a7a62ec" + "reference": "163232991e652e6efed2f8470326fffa61e848e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/08b2aacdd8433abbba468f995d6d64b76a7a62ec", - "reference": "08b2aacdd8433abbba468f995d6d64b76a7a62ec", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/163232991e652e6efed2f8470326fffa61e848e2", + "reference": "163232991e652e6efed2f8470326fffa61e848e2", "shasum": "" }, "require": { @@ -3457,9 +3457,6 @@ "autoload": { "classmap": [ "src/" - ], - "files": [ - "src/Framework/Assert/Functions.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3480,7 +3477,7 @@ "testing", "xunit" ], - "time": "2015-04-03 13:46:59" + "time": "2015-04-11 05:23:21" }, { "name": "phpunit/phpunit-mock-objects", diff --git a/config/database.php b/config/database.php index c57b4735b2..5f203d8743 100644 --- a/config/database.php +++ b/config/database.php @@ -48,7 +48,7 @@ return [ 'sqlite' => [ 'driver' => 'sqlite', - 'database' => ':memory:', + 'database' => __DIR__.'/../storage/database/testing.db', 'prefix' => '', ], diff --git a/database/migrations/2014_11_10_172053_create_account_meta_table.php b/database/migrations/2014_11_10_172053_create_account_meta_table.php index 24f92af144..5ca584d007 100644 --- a/database/migrations/2014_11_10_172053_create_account_meta_table.php +++ b/database/migrations/2014_11_10_172053_create_account_meta_table.php @@ -41,6 +41,9 @@ class CreateAccountMetaTable extends Migration $table->unique(['account_id', 'name']); + // link to account! + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + } ); diff --git a/phpunit.xml b/phpunit.xml index 0410acac89..677b0226c7 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -24,7 +24,6 @@ - diff --git a/pu.sh b/pu.sh index a532d9ecf0..26c595cfb4 100755 --- a/pu.sh +++ b/pu.sh @@ -18,4 +18,4 @@ then fi # restore .env file -mv .env.backup .env +cp .env.local .env diff --git a/resources/views/profile/delete-account.blade.php b/resources/views/profile/delete-account.blade.php new file mode 100644 index 0000000000..a181f16a68 --- /dev/null +++ b/resources/views/profile/delete-account.blade.php @@ -0,0 +1,49 @@ +@extends('layouts.default') +@section('content') +{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!} +
+
+
+
+ Delete your account +
+
+ +

+ Deleting your account will also delete any accounts, transactions, anything + you might have saved into Firefly III. It'll be GONE. +

+

+ Enter your password to continue. +

+ + @if($errors->count() > 0) +
    + @foreach($errors->all() as $err) +
  • {{$err}}
  • + @endforeach +
+ + @endif + + {!! Form::open(['class' => 'form-horizontal','id' => 'change-password']) !!} +
+ +
+ +
+
+ +
+
+ +
+
+ {!! Form::close() !!} +
+
+
+
+@stop +@section('scripts') +@stop diff --git a/resources/views/profile/index.blade.php b/resources/views/profile/index.blade.php index e6eab98606..660cd54bcc 100644 --- a/resources/views/profile/index.blade.php +++ b/resources/views/profile/index.blade.php @@ -8,7 +8,10 @@ Options diff --git a/resources/views/reports/month.blade.php b/resources/views/reports/month.blade.php index a7a9504352..a906fd2019 100644 --- a/resources/views/reports/month.blade.php +++ b/resources/views/reports/month.blade.php @@ -25,15 +25,15 @@ {{{$entry->description}}} - amount);?> + queryAmount);?> @if($entry->type == 'Withdrawal') - {{Amount::format($entry->amount,false)}} + {{Amount::format($entry->queryAmount,false)}} @endif @if($entry->type == 'Deposit') - {{Amount::format($entry->amount,false)}} + {{Amount::format($entry->queryAmount,false)}} @endif @if($entry->type == 'Transfer') - {{Amount::format($entry->amount,false)}} + {{Amount::format($entry->queryAmount,false)}} @endif diff --git a/storage/database/.gitignore b/storage/database/.gitignore new file mode 100644 index 0000000000..3997beadf8 --- /dev/null +++ b/storage/database/.gitignore @@ -0,0 +1 @@ +*.db \ No newline at end of file diff --git a/tests/TestCase.php b/tests/TestCase.php index 336e5f2a9a..cc436f7446 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -29,7 +29,22 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase public function setUp() { parent::setUp(); - Artisan::call('migrate'); + + // if the database copy does not exist, call migrate. + $copy = __DIR__.'/../storage/database/testing-copy.db'; + $original = __DIR__.'/../storage/database/testing.db'; + if (!file_exists($copy)) { + Log::debug('Created new database.'); + touch($original); + Artisan::call('migrate'); + copy($original, $copy); + } else { + if (file_exists($copy)) { + copy($copy, $original); + } + } + // if the database copy does exists, copy back as original. + FactoryMuffin::loadFactories(__DIR__ . '/factories'); } @@ -44,10 +59,24 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase parent::setUpBeforeClass(); } + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + public function tearDown() + { + parent::tearDown(); + + // delete copy original. + //$original = __DIR__.'/../storage/database/testing.db'; + //unlink($original); + + } + /** * @param string $class * - * @return mixed + * @return Mockery\MockInterface */ public function mock($class) { diff --git a/tests/controllers/JsonControllerTest.php b/tests/controllers/JsonControllerTest.php index 4a902079f6..0f8390d6cc 100644 --- a/tests/controllers/JsonControllerTest.php +++ b/tests/controllers/JsonControllerTest.php @@ -35,7 +35,6 @@ class JsonControllerTest extends TestCase public function tearDown() { parent::tearDown(); - } public function testBoxBillsPaid() diff --git a/tests/controllers/PiggyBankControllerTest.php b/tests/controllers/PiggyBankControllerTest.php new file mode 100644 index 0000000000..63964eb163 --- /dev/null +++ b/tests/controllers/PiggyBankControllerTest.php @@ -0,0 +1,399 @@ +be($piggyBank->account->user); + + + // mock + /** @var Mockery\MockInterface $repository */ + $repository = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface'); + $repository->shouldReceive('leftOnAccount')->withAnyArgs()->andReturn(12); + Amount::shouldReceive('format')->andReturn('XXxx'); + + $this->call('GET', '/piggy-banks/add/' . $piggyBank->id); + $this->assertResponseOk(); + } + + public function testCreate() + { + $account = FactoryMuffin::create('FireflyIII\Models\Account'); + $collection = new Collection([$account]); + $user = FactoryMuffin::create('FireflyIII\User'); + $this->be($user); + + // mock + $repository = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface'); + $repository->shouldReceive('getAccounts')->once()->with(['Default account', 'Asset account'])->andReturn($collection); + ExpandedForm::shouldReceive('makeSelectList')->with($collection)->andReturn([]); + + // also cover the view now that we've touched ExpandedForm: + ExpandedForm::shouldReceive('text')->andReturn(''); + ExpandedForm::shouldReceive('select')->andReturn(''); + ExpandedForm::shouldReceive('amount')->andReturn(''); + ExpandedForm::shouldReceive('date')->andReturn(''); + ExpandedForm::shouldReceive('checkbox')->andReturn(''); + ExpandedForm::shouldReceive('optionsList')->andReturn(''); + + $this->call('GET', '/piggy-banks/create'); + $this->assertResponseOk(); + } + + public function testDelete() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $this->be($piggyBank->account->user); + + + $this->call('GET', '/piggy-banks/delete/' . $piggyBank->id); + $this->assertResponseOk(); + $this->assertViewHas('subTitle', 'Delete "' . e($piggyBank->name) . '"'); + } + + public function testDestroy() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $user = FactoryMuffin::create('FireflyIII\User'); + $this->be($user); + + $repository = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + $repository->shouldReceive('destroy')->once()->withAnyArgs()->andReturn(true); + + + $this->call('POST', '/piggy-banks/destroy/' . $piggyBank->id, ['_token' => 'replaceMe']); + $this->assertResponseStatus(302); + $this->assertSessionHas('success'); + + } + + public function testEdit() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $user = FactoryMuffin::create('FireflyIII\User'); + $this->be($user); + $account = FactoryMuffin::create('FireflyIII\Models\Account'); + $collection = new Collection([$account]); + + // mock! + $repository = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface'); + $repository->shouldReceive('getAccounts')->once()->with(['Default account', 'Asset account'])->andReturn($collection); + ExpandedForm::shouldReceive('makeSelectList')->with($collection)->andReturn([]); + + // also cover the view now that we've touched ExpandedForm: + ExpandedForm::shouldReceive('text')->andReturn(''); + ExpandedForm::shouldReceive('select')->andReturn(''); + ExpandedForm::shouldReceive('amount')->andReturn(''); + ExpandedForm::shouldReceive('date')->andReturn(''); + ExpandedForm::shouldReceive('checkbox')->andReturn(''); + ExpandedForm::shouldReceive('optionsList')->andReturn(''); + + + $this->call('GET', '/piggy-banks/edit/' . $piggyBank->id); + $this->assertResponseOk(); + } + + public function testEditNullDate() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $user = FactoryMuffin::create('FireflyIII\User'); + $this->be($user); + $piggyBank->targetdate = null; + $piggyBank->save(); + $account = FactoryMuffin::create('FireflyIII\Models\Account'); + $collection = new Collection([$account]); + + // mock! + $repository = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface'); + $repository->shouldReceive('getAccounts')->once()->with(['Default account', 'Asset account'])->andReturn($collection); + ExpandedForm::shouldReceive('makeSelectList')->with($collection)->andReturn([]); + + // also cover the view now that we've touched ExpandedForm: + ExpandedForm::shouldReceive('text')->andReturn(''); + ExpandedForm::shouldReceive('select')->andReturn(''); + ExpandedForm::shouldReceive('amount')->andReturn(''); + ExpandedForm::shouldReceive('date')->andReturn(''); + ExpandedForm::shouldReceive('checkbox')->andReturn(''); + ExpandedForm::shouldReceive('optionsList')->andReturn(''); + + + $this->call('GET', '/piggy-banks/edit/' . $piggyBank->id); + $this->assertResponseOk(); + } + + public function testIndex() + { + $piggyBank1 = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $piggyBank2 = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $piggyBank3 = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $piggyBank2->account_id = $piggyBank1->account_id; + $user = FactoryMuffin::create('FireflyIII\User'); + + $piggyBank2->save(); + + $collection = new Collection([$piggyBank1, $piggyBank2, $piggyBank3]); + $this->be($user); + + // mock! + $accounts = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface'); + $piggyBanks = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + + // act! + $piggyBanks->shouldReceive('getPiggyBanks')->once()->andReturn($collection); + Steam::shouldReceive('balance')->andReturn(20); + $accounts->shouldReceive('leftOnAccount')->andReturn(12); + Amount::shouldReceive('format')->andReturn('123'); + + + $this->call('GET', '/piggy-banks'); + $this->assertResponseOk(); + + } + + public function testOrder() + { + $piggyBank1 = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $piggyBank2 = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $user = FactoryMuffin::create('FireflyIII\User'); + $this->be($user); + + // mock! + $piggyBanks = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + $piggyBanks->shouldReceive('reset')->once(); + $piggyBanks->shouldReceive('setOrder'); + $array = [ + $piggyBank1->id => 0, + $piggyBank2->id => 1, + ]; + + $this->call('POST', '/piggy-banks/sort', ['_token' => 'replaceMe', 'order' => $array]); + $this->assertResponseOk(); + } + + public function testPostAdd() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $this->be($piggyBank->account->user); + + // mock! + $accounts = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface'); + $piggyBanks = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + $accounts->shouldReceive('leftOnAccount')->andReturn(20); + $piggyBanks->shouldReceive('createEvent')->once(); + + Amount::shouldReceive('format')->andReturn('something'); + + $this->call('POST', '/piggy-banks/add/' . $piggyBank->id, ['_token' => 'replaceMe']); + $this->assertResponseStatus(302); + } + + public function testPostAddOverdraw() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $this->be($piggyBank->account->user); + + // mock! + $accounts = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface'); + $piggyBanks = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + $accounts->shouldReceive('leftOnAccount')->andReturn(20); + $piggyBanks->shouldReceive('createEvent')->once(); + + Amount::shouldReceive('format')->andReturn('something'); + + $this->call('POST', '/piggy-banks/add/' . $piggyBank->id, ['_token' => 'replaceMe', 'amount' => '10000']); + $this->assertResponseStatus(302); + } + + public function testPostRemove() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $this->be($piggyBank->account->user); + + // mock! + $accounts = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface'); + $piggyBanks = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + $accounts->shouldReceive('leftOnAccount')->andReturn(20); + $piggyBanks->shouldReceive('createEvent')->once(); + + Amount::shouldReceive('format')->andReturn('something'); + Amount::shouldReceive('getCurrencySymbol')->andReturn('something'); + + $this->call('POST', '/piggy-banks/remove/' . $piggyBank->id, ['_token' => 'replaceMe']); + $this->assertResponseStatus(302); + } + + public function testPostRemoveOverdraw() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $this->be($piggyBank->account->user); + + // mock! + $accounts = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface'); + $piggyBanks = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + $accounts->shouldReceive('leftOnAccount')->andReturn(20); + $piggyBanks->shouldReceive('createEvent')->once(); + + Amount::shouldReceive('format')->andReturn('something'); + Amount::shouldReceive('getCurrencySymbol')->andReturn('something'); + + $this->call('POST', '/piggy-banks/remove/' . $piggyBank->id, ['_token' => 'replaceMe', 'amount' => '10000']); + $this->assertResponseStatus(302); + } + + + public function testRemove() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $this->be($piggyBank->account->user); + + Amount::shouldReceive('format')->andReturn('something'); + + $this->call('GET', '/piggy-banks/remove/' . $piggyBank->id); + $this->assertResponseOk(); + } + + public function testShow() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $this->be($piggyBank->account->user); + + $piggyBanks = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + $piggyBanks->shouldReceive('getEvents')->andReturn(new Collection); + Amount::shouldReceive('format')->andReturn('something'); + Amount::shouldReceive('getCurrencySymbol')->andReturn('something'); + Amount::shouldReceive('getCurrencyCode')->andReturn('something'); + + + $this->call('GET', '/piggy-banks/show/' . $piggyBank->id); + $this->assertResponseOk(); + } + + public function testStore() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $this->be($piggyBank->account->user); + + $piggyBankData = [ + 'name' => 'Some name' . rand(1, 100), + 'account_id' => $piggyBank->account_id, + 'targetamount' => 100, + 'targetdate' => '', + 'reminder' => 'month', + '_token' => 'replaceMe' + ]; + + // mock! + $piggyBanks = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + $piggyBanks->shouldReceive('store')->once()->andReturn($piggyBank); + + $this->call('POST', '/piggy-banks/store', $piggyBankData); + $this->assertResponseStatus(302); + } + + public function testStoreCreateAnother() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $this->be($piggyBank->account->user); + + $piggyBankData = [ + 'name' => 'Some name' . rand(1, 100), + 'account_id' => $piggyBank->account_id, + 'targetamount' => 100, + 'targetdate' => '', + 'reminder' => 'month', + 'create_another' => 1, + '_token' => 'replaceMe' + ]; + + // mock! + $piggyBanks = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + $piggyBanks->shouldReceive('store')->once()->andReturn($piggyBank); + + $this->call('POST', '/piggy-banks/store', $piggyBankData); + $this->assertResponseStatus(302); + } + + public function testUpdate() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $this->be($piggyBank->account->user); + + $piggyBankData = [ + 'name' => 'Some name' . rand(1, 100), + 'account_id' => $piggyBank->account_id, + 'targetamount' => 200, + 'targetdate' => '', + 'reminder' => 'month', + '_token' => 'replaceMe' + ]; + + // mock! + $piggyBanks = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + $piggyBanks->shouldReceive('update')->once()->andReturn($piggyBank); + + $this->call('POST', '/piggy-banks/update/' . $piggyBank->id, $piggyBankData); + $this->assertResponseStatus(302); + } + + public function testUpdateReturnToEdit() + { + $piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank'); + $this->be($piggyBank->account->user); + + $piggyBankData = [ + 'name' => 'Some name' . rand(1, 100), + 'account_id' => $piggyBank->account_id, + 'targetamount' => 200, + 'targetdate' => '', + 'return_to_edit' => 1, + 'reminder' => 'month', + '_token' => 'replaceMe' + ]; + + // mock! + $piggyBanks = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + $piggyBanks->shouldReceive('update')->once()->andReturn($piggyBank); + + $this->call('POST', '/piggy-banks/update/' . $piggyBank->id, $piggyBankData); + $this->assertResponseStatus(302); + } +} diff --git a/tests/controllers/PreferencesControllerTest.php b/tests/controllers/PreferencesControllerTest.php new file mode 100644 index 0000000000..02f61910d6 --- /dev/null +++ b/tests/controllers/PreferencesControllerTest.php @@ -0,0 +1,84 @@ +be($user); + + + // mock: + $repository = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface'); + + // fake! + $repository->shouldReceive('getAccounts')->with(['Default account', 'Asset account'])->andReturn(new Collection); + Preferences::shouldReceive('get')->once()->withArgs(['viewRange', '1M'])->andReturn($pref); + Preferences::shouldReceive('get')->once()->withArgs(['frontPageAccounts', []])->andReturn($pref); + Preferences::shouldReceive('get')->once()->withArgs(['budgetMaximum', 1000])->andReturn($pref); + Preferences::shouldReceive('get')->once()->withArgs(['currencyPreference', 'EUR'])->andReturn($pref); + Amount::shouldReceive('format')->andReturn('xx'); + Amount::shouldReceive('getAllCurrencies')->andReturn(new Collection); + Amount::shouldReceive('getDefaultCurrency')->andReturn($currency); + + $this->call('GET', '/preferences'); + $this->assertResponseOk(); + } + + public function testPostIndex() + { + $user = FactoryMuffin::create('FireflyIII\User'); + $this->be($user); + + $data = [ + 'frontPageAccounts' => [1, 2, 3], + '_token' => 'replaceMe', + 'viewRange' => '1M' + ]; + + Preferences::shouldReceive('set')->once()->withArgs(['frontPageAccounts', [1, 2, 3]]); + Preferences::shouldReceive('set')->once()->withArgs(['viewRange', '1M']); + Preferences::shouldReceive('set')->once()->withArgs(['budgetMaximum', 0]); + + + $this->call('POST', '/preferences', $data); + $this->assertResponseStatus(302); + } +} \ No newline at end of file