Compare commits

..

266 Commits
3.9.1 ... 4.0.0

Author SHA1 Message Date
James Cole
9bdfecbfdc Merge branch 'release/4.0.0' 2016-09-26 18:37:33 +02:00
James Cole
f85e4a24e5 New license information. 2016-09-26 18:37:20 +02:00
James Cole
0dda87c78e New license. 2016-09-26 18:34:31 +02:00
James Cole
2fc09ff9d7 Fix empty pop-ups in report. 2016-09-25 14:47:55 +02:00
James Cole
e4e0e21293 Smaller method. 2016-09-25 08:59:27 +02:00
James Cole
15089f0d7e Some issues fixed for scrutiniser. 2016-09-25 08:50:12 +02:00
James Cole
7232c1d7bb partial fix for #307 2016-09-25 08:46:57 +02:00
James Cole
9a53d8c21c Some array_keys fixes. 2016-09-25 08:46:42 +02:00
James Cole
0d198193db Some issues fixed for scrutiniser. 2016-09-25 08:36:35 +02:00
James Cole
45bc23b8af Some issues fixed for scrutiniser. 2016-09-25 08:32:53 +02:00
James Cole
3323c31765 Some issues fixed for scrutiniser. 2016-09-25 08:24:03 +02:00
James Cole
bb7c26b77c Some issues fixed for scrutiniser. 2016-09-25 08:20:17 +02:00
James Cole
9101d6a2c0 Add lines to configuration on wiki. [skip ci] 2016-09-24 19:32:00 +02:00
James Cole
ad2b254be0 Fix for issue #328. Turns out the import routine converts accounts back and forth instead of creating new entries. 2016-09-24 18:59:31 +02:00
James Cole
abc4f856ce Fix nullable fields. 2016-09-24 17:22:42 +02:00
James Cole
b3b66a8f92 Merge pull request #329 from niekvanderkooy/develop
Fix assignment of array variables
2016-09-24 17:04:32 +02:00
Niek van der Kooy
2f7cf9b916 Fix assignment of array variables 2016-09-24 17:01:41 +02:00
James Cole
b822e0c6e7 Upgrade stuff for 4.0.0 2016-09-24 15:30:08 +02:00
James Cole
6fef9ee72b #315 2016-09-24 10:58:48 +02:00
James Cole
ab6dd0a1ec #314 2016-09-24 10:55:13 +02:00
James Cole
9deef5ac92 #325 2016-09-24 10:53:39 +02:00
James Cole
577187babe Fix #324 [skip ci] 2016-09-24 10:52:13 +02:00
James Cole
577290e813 add strtolower [skip ci] 2016-09-24 09:14:47 +02:00
James Cole
f3b9798216 Fix some rule things. 2016-09-24 09:12:17 +02:00
James Cole
4dcaa96d16 Fix group error. I hope. 2016-09-24 08:59:29 +02:00
James Cole
0dcbf451d6 Add verify command to composer.json 2016-09-24 08:59:14 +02:00
James Cole
e87f6ca40e Fix some possible NULL values. 2016-09-24 08:55:01 +02:00
James Cole
1f34e33d8c Update composer, improve verify routine. 2016-09-23 22:31:01 +02:00
James Cole
258e87e127 Merge pull request #323 from Mortalife/master
Adding GBP to Seed
2016-09-22 07:58:21 +02:00
Matthew Peck
3ec8efcfc1 Adding GBP to Seed 2016-09-21 20:45:36 +01:00
James Cole
70ea227bd0 Add logging to processor #322 2016-09-21 21:01:10 +02:00
James Cole
27c832ed58 Logging for rule triggers #322 2016-09-21 20:58:12 +02:00
James Cole
a31b4ccf01 Basic logging for willMatchEverything #322 2016-09-21 20:30:09 +02:00
James Cole
d221ea68d0 Gave all rule actions some logging. #322 2016-09-21 20:12:04 +02:00
James Cole
dc9fe58536 Fix tags input width. 2016-09-21 19:23:50 +02:00
James Cole
f871e29bdb Quick fix for broken attachments. 2016-09-21 19:16:47 +02:00
James Cole
1357352276 Merge pull request #320 from Mortalife/master
Decimal place fix on import
2016-09-20 20:21:02 +02:00
James Cole
e169754693 Fix display bug for attachments 2016-09-20 17:23:12 +02:00
James Cole
1cfe4f40ba Fix display bug for attachments 2016-09-20 17:22:07 +02:00
James Cole
5545d1c1ba Fix display bug for attachments 2016-09-20 17:21:26 +02:00
James Cole
e5f7228fa9 Fix future query problems (current users not affected either way) [skip ci] 2016-09-20 09:32:58 +02:00
James Cole
11385494eb Fix for income entry. 2016-09-20 08:57:08 +02:00
James Cole
ae328de469 Fix bug in year report. 2016-09-20 08:26:42 +02:00
James Cole
0574a706c8 Error in decrypt error (yes) 2016-09-20 07:57:04 +02:00
Matthew Peck
70bb85a75b Cleanup 2016-09-20 00:00:11 +01:00
Matthew Peck
8cd901b57b Added support for multiple decimal places 2016-09-19 23:53:51 +01:00
James Cole
8b9818c48e This will fix #316 2016-09-18 20:00:13 +02:00
James Cole
a95099fa46 Update FF configuration. 2016-09-18 19:57:21 +02:00
James Cole
221e4b7fc0 Fix some migrations [skip ci] 2016-09-18 18:14:07 +02:00
James Cole
6cff3eb61e Fix some migrations [skip ci] 2016-09-18 17:52:31 +02:00
James Cole
e4fd97ae77 Some code fixes. [skip ci] 2016-09-17 09:52:28 +02:00
James Cole
5ca9099654 Some code fixes. 2016-09-17 09:50:40 +02:00
James Cole
6e33e26ddf Update copyright notices, update German language. 2016-09-17 07:57:32 +02:00
James Cole
04461a4ab8 Updated composer.lock [skip ci] 2016-09-17 07:22:39 +02:00
James Cole
a4b9bbff54 Update AdminLTE template. 2016-09-17 07:19:09 +02:00
James Cole
4ad4252a77 Extend exclude path. Trigger a new inspection. 2016-09-17 07:10:29 +02:00
James Cole
aac0c9ab98 Various layout updates and tiny upgrade fixes [skip ci] 2016-09-16 13:29:56 +02:00
James Cole
c123e1044a Expand config so people won't get errors here [skip ci] 2016-09-16 12:19:29 +02:00
James Cole
d25d0454fc Code clean up 2016-09-16 12:15:58 +02:00
James Cole
f38984398d Code clean up [skip ci] 2016-09-16 12:07:45 +02:00
James Cole
a07799cfa4 MySQL 5.7 compatible query fixing. [skip ci] 2016-09-16 11:16:31 +02:00
James Cole
7c52f297ee MySQL 5.7 compatible query fixing. [skip ci] 2016-09-16 11:06:21 +02:00
James Cole
50a3279b30 MySQL 5.7 compatible query fixing. [skip ci] 2016-09-16 11:04:24 +02:00
James Cole
0ea14eb987 MySQL 5.7 compatible grouping. [skip ci] 2016-09-16 11:01:35 +02:00
James Cole
cf1b98e569 MySQL 5.7 compatible grouping. 2016-09-16 10:55:26 +02:00
James Cole
63fb435002 Expand code. 2016-09-16 10:50:19 +02:00
James Cole
2f8263f53a Possible fix for reports [skip ci] 2016-09-16 09:36:08 +02:00
James Cole
fb649779d6 Do not need to sort. Fix MySQL 5.7 compatibility. 2016-09-16 09:31:40 +02:00
James Cole
bb58f605f7 Some new login / logout routes 2016-09-16 09:21:36 +02:00
James Cole
fccdf56c5d Fixed some query things. 2016-09-16 09:09:54 +02:00
James Cole
bd53410c71 Some changes in login routes for 5.3 2016-09-16 09:02:35 +02:00
James Cole
7d63f124c4 Fixing some login routes 2016-09-16 07:22:57 +02:00
James Cole
9ffc5d857c Fixed some db bugs. These will only pop up when developing. 2016-09-16 07:16:09 +02:00
James Cole
2f93784acd More code for 5.3 2016-09-16 07:05:34 +02:00
James Cole
d00fbe4eb3 More code for 5.3 2016-09-16 06:48:38 +02:00
James Cole
51d9f041ae Changes for login routes. 2016-09-16 06:43:13 +02:00
James Cole
b872ab8b86 New code and new routes for 5.3 2016-09-16 06:40:45 +02:00
James Cole
3d25fd79ca First set of upgrade to 5.3 stuff. 2016-09-16 06:19:40 +02:00
James Cole
3aad78e6ef Lots of updated libraries.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-15 19:14:55 +02:00
James Cole
7d5bb72b0c Fix for #312
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-15 19:14:22 +02:00
James Cole
46e5aae8bb Fix changelog. [skip ci]
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-15 19:00:22 +02:00
James Cole
b9e2ee7af3 Merge branch 'release/3.10.4' 2016-09-14 20:40:52 +02:00
James Cole
c1a2892788 New changelog.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-14 20:40:12 +02:00
James Cole
2078183e0d Update version and composer file. 2016-09-14 20:37:12 +02:00
James Cole
fab1d53714 Simplified upgrade instructions. 2016-09-14 20:35:45 +02:00
James Cole
3fe831c7d8 Bit of code cleanup courtesy of PHPStorm. 2016-09-13 19:20:09 +02:00
James Cole
6958f71cfd @fuf discovered a bug where FF3 will fall back to the hard-coded system default currency and not the set default currency. See #307 2016-09-13 19:19:58 +02:00
James Cole
a7351f348d Fixed a bug mentioned by @vissert and added some logging for @sandermulders
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-12 18:43:10 +02:00
James Cole
5379e03447 Merge pull request #311 from sandermulders/fix/nullable-values
add migration that correctly sets nullable for description fields on rules and rule_groups
2016-09-12 16:52:14 +02:00
Sander Mulders
539058e32d Fix for #310: add migration that correctly sets nullable for description fields on rules and rule_groups 2016-09-12 14:24:01 +02:00
James Cole
11b6b5a63c Merge branch 'release/3.10.3' into develop 2016-09-11 08:17:42 +02:00
James Cole
1155096226 Merge branch 'release/3.10.3' 2016-09-11 08:17:41 +02:00
James Cole
2920dd356e Updated translations.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-11 08:17:35 +02:00
James Cole
9c3dac8170 Config for new version.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-11 08:13:22 +02:00
James Cole
49f9909b15 New changelog.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-11 08:13:14 +02:00
James Cole
e4fef6dfc3 Fixed an import bug where a new transaction validation rule would break storing of the transaction, while the import would not notice this error happening. The importer will now also correctly set a date on the "import tag" and will not tag an incomplete journal as already imported.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-11 08:08:01 +02:00
James Cole
2da087401e Extend audit report
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-10 18:37:16 +02:00
James Cole
629baf9de5 Added invoice date
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-10 18:36:52 +02:00
James Cole
29a930dae5 Updated translations.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-09 11:36:19 +02:00
James Cole
d920537dd2 Updated translations.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-09 11:29:19 +02:00
James Cole
106b04a5da Update composer.lock [skip ci]
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-09 11:19:50 +02:00
James Cole
176752e219 Code for optional fields #301
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-09 11:19:40 +02:00
James Cole
8d19f60091 Various translation updates.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-09 11:19:19 +02:00
James Cole
e937aa2f74 Fix a bug in piggy bank display [skip ci]
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-09 06:17:50 +02:00
James Cole
c3ccc4ccdf This should fix #308
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-08 21:10:24 +02:00
James Cole
6c5cd705c0 Some code for new optional fields, see #301
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-04 16:21:51 +02:00
James Cole
ce003f217b Removed unused "budget maximum" preference 2016-09-03 21:13:08 +02:00
James Cole
8c7ef49eb6 New code by @vissert that allows category edit (see #282)
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-03 05:01:48 +02:00
James Cole
29af4bd1b9 This fixes #303 2016-09-03 04:54:57 +02:00
James Cole
2ce5142b06 Small fix for #303
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-01 19:01:08 +02:00
James Cole
f3a8a25872 Fixed #303
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-09-01 18:31:39 +02:00
James Cole
598e97d028 Forgot to escape things, which causes havoc in the Dutch translation.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-31 18:50:46 +02:00
James Cole
fa110279de Merge branch 'release/3.10.2' 2016-08-29 19:32:49 +02:00
James Cole
8fdeaf73cc Update composer.lock [skip ci]
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-29 19:32:03 +02:00
James Cole
a7ffdf062a Update changelog. [skip ci]
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-29 19:26:31 +02:00
James Cole
3bad92dd6d Upgrade instructions and new version.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-29 19:25:21 +02:00
James Cole
2e88024bca Close #290
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-29 19:21:40 +02:00
James Cole
ca2301959c Merge pull request #298 from Bonno/develop
Fixed wrong conversion to revenue account
2016-08-29 14:49:46 +02:00
Bonno Nachtegaal-Karels
3285fae7f0 Fixed wrong conversion to revenue account 2016-08-29 14:39:43 +02:00
James Cole
312079657b Include files from new import routine in export routine. 2016-08-28 07:05:42 +02:00
James Cole
18c183afd6 Remove form tags in favour of raw html.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-27 09:38:58 +02:00
James Cole
f424d9cf20 Update change log
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-27 04:37:04 +02:00
James Cole
5c3da9fd9e New language files.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-27 04:34:59 +02:00
James Cole
1f321fadd4 Removed some form-tags in favour of plain HTML
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-27 04:18:02 +02:00
James Cole
65f5d27b12 New pages for administration. More settings will be web-based.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-27 04:00:48 +02:00
James Cole
cdb591de7f Remove unnecessary setting.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-27 04:00:19 +02:00
James Cole
a0ea3882e1 Various code cleanup.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-27 03:50:35 +02:00
James Cole
a9444ac702 Code cleanup.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-26 09:30:52 +02:00
James Cole
d0c6afc3a9 Various code clean up. [skip ci] 2016-08-26 08:21:31 +02:00
James Cole
e7a0a5937c Extend git ignore. [skip ci]
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-26 07:41:13 +02:00
James Cole
08992b5298 Extend test-import data set to contain some rules.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-26 07:38:00 +02:00
James Cole
6490a4240d Remove references to ImportResult. Add the application of user rules.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-26 07:37:47 +02:00
James Cole
43a7544dd7 Catch empty (null) descriptions. Which never happens.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-26 07:37:27 +02:00
James Cole
0fe70dae17 Referring to Auth::user will not work from the command line.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-26 07:37:09 +02:00
James Cole
7079e76886 Remove some commented code.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-26 07:36:33 +02:00
James Cole
0ec021c375 No need to grab journals we don't need.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-26 07:36:26 +02:00
James Cole
ff3396e286 Removed the ImportResult class because it was lame.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-26 07:36:13 +02:00
James Cole
78912903ce Change signature of importstorage. 2016-08-26 06:47:12 +02:00
James Cole
4c015e2d12 Re-arrange code. No changes. 2016-08-26 06:44:24 +02:00
James Cole
172634a55a Add some comments. 2016-08-26 06:43:38 +02:00
James Cole
58ca7d551a Rename import procedure method name 2016-08-26 06:43:23 +02:00
James Cole
fd8ed4c9aa Fixed a bug in strict typing.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-25 19:19:12 +02:00
James Cole
c03f5f5ff0 Merge branch 'release/3.10.1' 2016-08-25 11:20:39 +02:00
James Cole
6775fc58c8 Change log and updated config.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-25 11:20:13 +02:00
James Cole
9f250fc61b Renamed migration. 2016-08-25 11:16:17 +02:00
James Cole
94609f1419 Clean up some code. 2016-08-25 06:44:48 +02:00
James Cole
53402aa5e2 Update composer file. 2016-08-25 06:44:41 +02:00
James Cole
5aadb29905 Add some forgotten code to the mobile piggy bank controller things.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-24 20:06:45 +02:00
James Cole
d4f8c41d80 This should fix a bug in the verification routine.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-24 19:36:09 +02:00
James Cole
a2e14f8b8d Various code clean up.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-24 19:33:58 +02:00
James Cole
98c4ac955a Finetune user feedback during import and add a tag to collect transactions. 2016-08-14 11:31:09 +02:00
James Cole
70b63e1736 Better report for finished import. 2016-08-14 10:11:49 +02:00
James Cole
106665a468 Better reporting for double imported rows. See also #164 2016-08-14 09:49:04 +02:00
James Cole
da5e48d769 More language lines. Add a check for double lines. 2016-08-14 09:10:47 +02:00
James Cole
85f484e73c Divide by zero. 2016-08-14 09:10:08 +02:00
James Cole
d287ae97f8 Prep for translations in JS. 2016-08-14 08:34:59 +02:00
James Cole
117bb602dc Extend ImportObject with row hash. 2016-08-14 08:34:51 +02:00
James Cole
e440d55034 Finetune import status page. 2016-08-14 08:10:42 +02:00
James Cole
7f5b94fe43 Fixed a bug in the verify routine. 2016-08-13 23:31:42 +02:00
James Cole
c58eea6654 Fine-tuning the import routine. 2016-08-13 23:28:01 +02:00
James Cole
bbed5d0701 First version of a web-based import status thing. 2016-08-13 21:51:01 +02:00
James Cole
2775690fc8 Extend model to allow for more data during the import. 2016-08-13 18:53:16 +02:00
James Cole
1fd9f6e724 First user interface elements and routes for web import. 2016-08-13 16:38:58 +02:00
James Cole
3d63903128 Make sure import errors end up where the user can read them. 2016-08-13 16:29:24 +02:00
James Cole
ef876a165a Some better feedback in the import process. 2016-08-13 14:22:40 +02:00
James Cole
c4d6aaeef3 Extend scrutinizer config. 2016-08-12 16:06:27 +02:00
James Cole
37b735c2e3 Remove code climate config 2016-08-12 16:06:17 +02:00
James Cole
62d30c7b0e Fix migration (call to empty table name) 2016-08-12 16:06:11 +02:00
James Cole
9cac7d46c0 Merge branch 'release/3.10' 2016-08-12 16:03:30 +02:00
James Cole
99b3e24836 Code optimalization 2016-08-12 15:50:52 +02:00
James Cole
ffb699cb06 Clean up code. 2016-08-12 15:34:15 +02:00
James Cole
2947ec0002 Small optimisations. 2016-08-12 15:27:44 +02:00
James Cole
5c4d010bde Code cleanup. 2016-08-12 15:10:03 +02:00
James Cole
955306d877 Remove travis file and fix NULL error in sqlite. 2016-08-12 14:50:25 +02:00
James Cole
015935ed55 Implemented ABN Amro specific import code. 2016-08-12 12:55:52 +02:00
James Cole
48f4cceb19 Mention new version. 2016-08-12 10:47:09 +02:00
James Cole
9850220aac Add new languages. 2016-08-12 10:46:22 +02:00
James Cole
c4ac1460f0 Expanded translations 2016-08-12 10:44:27 +02:00
James Cole
b9e1e01337 New translations. 2016-08-12 10:34:45 +02:00
James Cole
76649cb7de Extended views and language. 2016-08-12 10:07:53 +02:00
James Cole
5e310776b4 New change log 2016-08-12 09:50:54 +02:00
James Cole
4d7fa11172 Upgrade instructions for 3.10 2016-08-12 09:35:09 +02:00
James Cole
28962007c1 More code for new importer 2016-08-12 09:27:09 +02:00
James Cole
2111873bcf Fixed a bug in tag creation. 2016-08-11 19:01:23 +02:00
James Cole
0aaf9a6fda Extend rule set for import. 2016-08-11 18:44:11 +02:00
James Cole
186b704509 Lots of new code to test the import routine.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-11 10:21:32 +02:00
James Cole
efe9933721 Import storage routine is creating the first transaction journals.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-11 08:00:02 +02:00
James Cole
200366f5be Extended the validator and created more code to handle exceptions.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-10 18:49:16 +02:00
James Cole
c9bd72337d Some notes on the import process. 2016-08-06 09:31:32 +02:00
James Cole
d4510440b8 Split the importer and the setup routine. 2016-08-06 06:28:21 +02:00
James Cole
5a9cf698f7 Configuration for import routine. 2016-08-06 06:21:46 +02:00
James Cole
5826fec519 Some new import stuff. 2016-08-06 06:21:25 +02:00
James Cole
7035600984 Add some logging for #283 2016-08-05 21:50:49 +02:00
James Cole
b1dfb5811f Merge pull request #286 from niekvanderkooy/develop
Generalise Steam::phpBytes
2016-08-05 21:42:40 +02:00
Niek van der Kooy
51570a5d08 Allow phpBytes to work with configs where gigabyte file sizes are allowed 2016-08-05 20:54:59 +02:00
Niek van der Kooy
f065f3a0b8 Make phpBytes case insensitive, since php.ini can contain both capitals and small letters 2016-08-05 20:53:09 +02:00
James Cole
47376f1f35 Fix a problem mentioned in issue #283
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-05 19:29:44 +02:00
James Cole
bcfe2c6410 Fixes #284
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-05 18:52:16 +02:00
James Cole
09d63b584d Save old data; bread crumbs 2016-08-04 06:14:08 +02:00
James Cole
5f5469a7d4 Moved some files around. 2016-08-04 06:10:30 +02:00
James Cole
38800d61b0 New user related code. 2016-08-04 06:07:53 +02:00
James Cole
1186e95c51 Admin view will show some IP addresses.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-03 20:57:01 +02:00
James Cole
d870e0f42e Fix split query. 2016-08-02 19:42:41 +02:00
James Cole
0db9852769 This should fix a bug in split expenses. 2016-08-02 19:12:18 +02:00
James Cole
7e3f9048fe Fixed some fields in split thing. 2016-08-01 20:14:23 +02:00
James Cole
1ba88f182b Various CSV bugs and a config bug fixed. 2016-07-31 17:17:45 +02:00
James Cole
c8f5a6b7ad Ignore deleted columns. 2016-07-30 20:04:24 +02:00
James Cole
d26bbf3cdc Handling import values. This is a dead end but it seemed a good idea. 2016-07-30 19:09:58 +02:00
James Cole
0de72b6914 Ignore result.html 2016-07-30 16:29:49 +02:00
James Cole
e41c89bd59 Does not belong. 2016-07-30 16:29:17 +02:00
James Cole
541d9ebdd9 Optimised some code. 2016-07-30 16:29:04 +02:00
James Cole
1e724712e0 Bug fix in converter 2016-07-29 21:42:12 +02:00
James Cole
3682467ae3 Each CSV converter can set the certainty of their conversion. 2016-07-29 21:40:58 +02:00
James Cole
7707c81b2d Each CSV converter can set the certainty of their conversion. 2016-07-29 21:29:46 +02:00
James Cole
e434de72a3 Expand fields. 2016-07-26 20:40:46 +02:00
James Cole
ce191fa6d3 Fix split deposit. 2016-07-26 20:26:46 +02:00
James Cole
90865a5284 Fix recursive. 2016-07-24 19:24:02 +02:00
James Cole
684f6e0b5c Don't need these. 2016-07-24 19:07:47 +02:00
James Cole
c287bc139c Check new list. 2016-07-24 18:51:39 +02:00
James Cole
1392275b81 Lots of new code for importer and some preferences. 2016-07-24 18:47:55 +02:00
James Cole
87c0f1d86e More CSV related updates. 2016-07-23 21:37:06 +02:00
James Cole
a4a723cfc6 Fixed import error. 2016-07-20 15:57:42 +02:00
James Cole
921e2c06f4 Beta warning for import thing. 2016-07-20 15:47:30 +02:00
James Cole
cb9433f4b9 This should fix #280 2016-07-17 08:50:22 +02:00
James Cole
1be6af820e No map for tags. 2016-07-17 08:35:04 +02:00
James Cole
3b686b6d1c New but empty converters. 2016-07-16 08:25:39 +02:00
James Cole
697566fe42 New importers. 2016-07-16 07:58:25 +02:00
James Cole
5130ba7ea4 Working IBAN account import thing. 2016-07-15 22:37:47 +02:00
James Cole
c9e46a4dd1 Lots of import related code. 2016-07-15 22:26:08 +02:00
James Cole
f5b3dc36e3 Fix view. 2016-07-05 09:02:01 +02:00
James Cole
f1e8d1cf1e Show bill average. 2016-07-05 08:57:45 +02:00
James Cole
e8e7ab01d2 Merge branch 'develop' of github.com:JC5/firefly-iii into develop 2016-07-04 12:38:22 +02:00
James Cole
9244994233 Fix bug that would report wrong file size to browser. 2016-07-04 12:37:33 +02:00
James Cole
ae768a8525 Works up until actual import. 2016-07-02 23:08:47 +02:00
James Cole
162c762973 First set of data mappers. 2016-07-02 20:40:23 +02:00
James Cole
57b5981904 Fix #266 for period-chart. 2016-07-02 17:42:27 +02:00
James Cole
275d19e71d Fix #266 for all-chart. 2016-07-02 17:39:58 +02:00
James Cole
189b11befa Extra page number check for issue #276 2016-07-02 17:36:46 +02:00
James Cole
a56a5fc228 New code for import routine. 2016-07-02 17:33:57 +02:00
James Cole
cbe3fb73a8 Catch decrypt exceptions. 2016-06-27 16:36:28 +02:00
James Cole
3d58fbebec Should not have committed this. 2016-06-27 16:25:17 +02:00
James Cole
b947ff50ed Fix chart thing. 2016-06-27 16:11:49 +02:00
James Cole
18d2741814 More code for the new CSV import 2016-06-27 15:15:46 +02:00
James Cole
93a54780ab Fixes a bug in the 2FA activation thing. 2016-06-24 21:58:57 +02:00
James Cole
3d201db6fc More code for import. 2016-06-24 14:24:34 +02:00
James Cole
9ffc0936ee Merge branch 'feature/new-csv-import' into develop
# Conflicts:
#	app/Helpers/Csv/Importer.php
2016-06-23 12:15:19 +02:00
James Cole
fbf9e00208 Change preferences info. 2016-06-23 12:08:14 +02:00
James Cole
2c826451d1 Fix delete routine and some NULLs 2016-06-23 12:07:31 +02:00
James Cole
617a5c0606 Fix date range. 2016-06-23 08:01:15 +02:00
James Cole
8331a7e34a Rename stuff. 2016-06-18 07:37:12 +02:00
James Cole
8ee1676f0a New migrations. 2016-06-18 07:36:15 +02:00
James Cole
5dc8620c43 More new migrations. 2016-06-17 14:06:38 +02:00
James Cole
d2733a4df0 First attempt at rewriting all migrations. 2016-06-17 06:03:42 +02:00
James Cole
ae649223d8 Mobile add money to piggy routine 2016-06-16 20:52:59 +02:00
James Cole
6267930938 Work on new chart for year report. 2016-06-16 20:52:30 +02:00
James Cole
bdee8cde77 This fixes #273 2016-06-16 08:04:22 +02:00
James Cole
e63f216905 Fix small bug in reorder routine. 2016-06-15 09:58:33 +02:00
James Cole
ec18165698 Fixed #267 2016-06-11 07:38:30 +02:00
James Cole
307e6a2337 Renamed fields #267 2016-06-11 06:36:46 +02:00
James Cole
b80d8cf774 Move date picker stuff to new method. 2016-06-11 06:33:51 +02:00
James Cole
7a5ef6013a Fix #271 2016-06-11 06:31:56 +02:00
James Cole
13b92c47d9 Translations and fixes. 2016-06-11 06:31:40 +02:00
James Cole
5a79bc0a99 Initial code base for new CSV import. 2016-06-10 21:00:00 +02:00
James Cole
beda6ec3a9 Removed old CSV stuff. 2016-06-10 15:25:24 +02:00
James Cole
c619b8730b Implemented #264 2016-06-07 12:22:46 +02:00
James Cole
c14ec8b006 New change log. 2016-06-07 12:22:30 +02:00
610 changed files with 24733 additions and 14102 deletions

View File

@@ -1,50 +0,0 @@
---
engines:
csslint:
enabled: true
duplication:
enabled: true
config:
languages:
- ruby
- javascript
- python
- php
eslint:
enabled: true
fixme:
enabled: true
phpmd:
enabled: true
ratings:
paths:
- "**.css"
- "**.inc"
- "**.js"
- "**.jsx"
- "**.module"
- "**.php"
- "**.py"
- "**.rb"
exclude_paths:
- gulpfile.js
- public/packages/maximebf/php-debugbar/debugbar.js
- public/packages/maximebf/php-debugbar/widgets.js
- public/packages/maximebf/php-debugbar/openhandler.js
- public/packages/maximebf/php-debugbar/widgets/sqlqueries/widget.js
- public/js/bootstrap3-typeahead.min.js
- public/js/bootstrap-sortable.js
- public/js/bootstrap-tagsinput.min.js
- public/js/bootstrap-tagsinput.min.js.map
- public/js/daterangepicker.js
- public/js/jquery-2.1.3.min.js
- public/js/jquery-2.1.3.min.js.map
- public/js/jquery-ui.min.js
- public/js/metisMenu.js
- public/js/moment.min.js
- public/js/sb-admin-2.js
- public/bootstrap/*
- resources/lang/*
- tests/*
- database/*
- storage/*

View File

@@ -1,15 +1,19 @@
APP_ENV=production
APP_DEBUG=false
APP_FORCE_SSL=false
APP_FORCE_ROOT=
APP_KEY=SomeRandomStringOf32CharsExactly
LOG_LEVEL=warning
APP_LOG_LEVEL=warning
APP_URL=http://localhost
DB_CONNECTION=mysql
DB_HOST=localhost
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
@@ -18,17 +22,14 @@ COOKIE_PATH="/"
COOKIE_DOMAIN=
COOKIE_SECURE=false
DEFAULT_CURRENCY=EUR
DEFAULT_LANGUAGE=en_US
REDIS_HOST=localhost
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_FROM=enter_your_email_here
MAIL_FROM=changeme@example.com
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
@@ -37,10 +38,10 @@ SEND_REGISTRATION_MAIL=true
MUST_CONFIRM_ACCOUNT=false
SHOW_INCOMPLETE_TRANSLATIONS=false
SHOW_DEMO_WARNING=false
ANALYTICS_ID=
RUNCLEANUP=true
SITE_OWNER=mail@example.com
BLOCKED_DOMAINS=
PUSHER_KEY=
PUSHER_SECRET=
PUSHER_APP_ID=

View File

@@ -1,38 +0,0 @@
APP_ENV=testing
APP_DEBUG=true
APP_FORCE_SSL=false
APP_KEY=SomeRandomStringOf32CharsExactly
LOG_LEVEL=debug
DB_CONNECTION=sqlite
DB_HOST=localhost
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
CACHE_DRIVER=array
SESSION_DRIVER=array
QUEUE_DRIVER=array
DEFAULT_CURRENCY=EUR
DEFAULT_LANGUAGE=en_US
REDIS_HOST=localhost
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=log
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_FROM=your_address_here@example.com
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
SHOW_INCOMPLETE_TRANSLATIONS=false
ANALYTICS_ID=abcde
RUNCLEANUP=false
SITE_OWNER=your_address_here@example.com
BLOCKED_DOMAINS=

2
.gitattributes vendored
View File

@@ -1,3 +1,3 @@
* text=auto
*.css linguist-vendored
*.less linguist-vendored
*.scss linguist-vendored

10
.gitignore vendored Normal file → Executable file
View File

@@ -1,5 +1,13 @@
/vendor
/node_modules
/public/storage
/vendor
/.idea
Homestead.json
Homestead.yaml
.env
_development
.env.local
result.html
test-import.sh
test-import-report.txt
public/google*.html

View File

@@ -4,3 +4,5 @@ tools:
filter:
excluded_paths:
- app/Support/Migration/*
- app/database/migrations/*
- database/migrations/*

View File

@@ -1,22 +0,0 @@
language: php
sudo: false
php:
- 7
install:
- phpenv config-rm xdebug.ini
- composer selfupdate
- rm composer.lock
- composer update --no-scripts
- php artisan clear-compiled
- php artisan optimize
- php artisan env
- mv -v .env.testing .env
- php artisan env
- touch storage/upload/at-1.data
- touch storage/upload/at-2.data
- touch storage/database/testing.db
- php artisan migrate --seed
script:
- phpunit

View File

@@ -2,8 +2,115 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
- No unreleased changes yet.
## [4.0.0] - 2015-05-25
### Added
- Upgraded to Laravel 5.3, most other libraries upgraded as well.
- Added GBP as currency, thanks to @Mortalife
### Changed
- Jump to version 4.0.0.
- Firefly III is now subject to a [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/) license. Previous versions of this software are still MIT licensed.
### Fixed
- Support for specific decimal places, thanks to @Mortalife
- Various CSS fixes
- Various bugs, thanks to @fuf, @sandermulders and @vissert
- Various queries optimized for MySQL 5.7
## [3.10.4] - 2015-09-14
### Fixed
- Migration fix by @sandermulders
- Tricky import bug fix thanks to @vissert
- Currency preference will be correctly pulled from user settings, thanks to @fuf
- Simplified code for upgrade instructions.
## [3.10.3] - 2016-08-29
### Added
- More fields for mass-edit, thanks to @Vissert (#282)
- First start of German translation
### Changed
- More optional fields for transactions and the ability to filter them.
### Removed
- Preference for budget maximum.
### Fixed
- A bug in the translation routine broke the import.
- It was possible to destroy your Firefly installation by removing all currencies. Thanks @mondjef
- Translation bugs.
- Import bug.
### Security
- Firefly will not accept registrations beyond the first one, by default.
## [3.10.2] - 2016-08-29
### Added
- New Chinese translations. Set Firefly III to show incomplete translations to follow the progress. Want to translate Firefly III in Chinese, or in any other language? Then check out [the Crowdin project](https://crowdin.com/project/firefly-iii).
- Added more admin pages. They do nothing yet.
### Changed
- Import routine will now also apply user rules.
- Various code cleanup.
- Some small HTML changes.
### Fixed
- Bug in the mass edit routines.
- Firefly III over a proxy will now work (see [issue #290](https://github.com/JC5/firefly-iii/issues/290)), thanks @dfiel for reporting.
- Sneaky bug in the import routine, fixed by @Bonno
## [3.10.1] - 2016-08-25
### Added
- More feedback in the import procedure.
- Extended model for import job.
- Web bases import procedure.
### Changed
- Scrutinizer configuration
- Various code clean up.
### Removed
- Code climate YAML file.
### Fixed
- Fixed a bug where a migration would check an empty table name.
- Fixed various bugs in the import routine.
- Fixed various bugs in the piggy banks pages.
- Fixed a bug in the ``firefly:verify`` routine
## [3.10] - 2015-05-25
### Added
- New charts in year report
- Can add / remove money from piggy bank on mobile device.
- Bill overview shows some useful things.
- Firefly will track registration / activation IP addresses.
### Changed
- Rewrote the import routine.
- The date picker now supports more ranges and periods.
- Rewrote all migrations. #272
### Fixed
- Issue #264
- Issue #265
- Fixed amount calculation problems, #266, thanks @xzaz
- Issue #271
- Issue #278, #273, thanks @StevenReitsma and @rubella
- Bug in attachment download routine would report the wrong size to the user's browser.
- Various NULL errors fixed.
- Various strict typing errors fixed.
- Fixed pagination problems, #276, thanks @xzaz
- Fixed a bug where an expense would be assigned to a piggy bank if you created a transfer first.
- Bulk update problems, #280, thanks @stickgrinder
- Fixed various problems with amount reporting of split transactions.
[3.9.1]
### Fixed
- Fixed a bug where removing money from a piggy bank would not work. See issue #265 and #269
[3.9.0]
### Added

View File

@@ -1,7 +1,7 @@
Copyright (C) 2016 thegrumpydictator@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
https://creativecommons.org/licenses/by-sa/4.0/
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -22,24 +22,40 @@ use Illuminate\Log\Writer;
*/
class ConfigureLogging extends IlluminateConfigureLogging
{
/**
* @param Application $app
* @param Writer $log
* Configure the Monolog handlers for the application.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @param \Illuminate\Log\Writer $log
*
* @return void
*/
protected function configureDailyHandler(Application $app, Writer $log)
{
$config = $app->make('config');
$maxFiles = $config->get('app.log_max_files');
$log->useDailyFiles(
$app->storagePath() . '/logs/firefly-iii.log',
$app->make('config')->get('app.log_max_files', 5)
$app->storagePath() . '/logs/firefly-iii.log', is_null($maxFiles) ? 5 : $maxFiles,
$config->get('app.log_level', 'debug')
);
}
/**
* @param Application $app
* @param Writer $log
* Configure the Monolog handlers for the application.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @param \Illuminate\Log\Writer $log
*
* @return void
*/
protected function configureSingleHandler(Application $app, Writer $log)
{
$log->useFiles($app->storagePath() . '/logs/firefly-iii.log');
$log->useFiles(
$app->storagePath() . '/logs/firefly-iii.log',
$app->make('config')->get('app.log_level', 'debug')
);
}
}

View File

@@ -0,0 +1,66 @@
<?php
/**
* EncryptFile.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Console\Commands;
use Crypt;
use Illuminate\Console\Command;
/**
* Class EncryptFile
*
* @package FireflyIII\Console\Commands
*/
class EncryptFile extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Encrypts a file and places it in the storage/upload directory.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly:encrypt {file} {key}';
/**
* Create a new command instance.
*
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*/
public function handle()
{
$file = e(strval($this->argument('file')));
if (!file_exists($file)) {
$this->error(sprintf('File "%s" does not seem to exist.', $file));
return;
}
$content = file_get_contents($file);
$content = Crypt::encrypt($content);
$newName = e(strval($this->argument('key'))) . '.upload';
$path = storage_path('upload') . '/' . $newName;
file_put_contents($path, $content);
$this->line(sprintf('Encrypted "%s" and put it in "%s"', $file, $path));
}
}

View File

@@ -0,0 +1,120 @@
<?php
/**
* Import.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Console\Commands;
use FireflyIII\Import\ImportProcedure;
use FireflyIII\Import\Logging\CommandHandler;
use FireflyIII\Models\ImportJob;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Console\Command;
use Log;
/**
* Class Import
*
* @package FireflyIII\Console\Commands
*/
class Import extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Import stuff into Firefly III.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly:import {key}';
/**
* Create a new command instance.
*
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$jobKey = $this->argument('key');
$job = ImportJob::whereKey($jobKey)->first();
if (!$this->isValid($job)) {
return;
}
$this->line('Going to import job with key "' . $job->key . '" of type ' . $job->file_type);
$monolog = Log::getMonolog();
$handler = new CommandHandler($this);
$monolog->pushHandler($handler);
$result = ImportProcedure::runImport($job);
/**
* @var int $index
* @var TransactionJournal $journal
*/
foreach ($result as $index => $journal) {
if (!is_null($journal->id)) {
$this->line(sprintf('Line #%d has been imported as transaction #%d.', $index, $journal->id));
continue;
}
$this->error(sprintf('Could not store line #%d', $index));
}
$this->line('The import has completed.');
// get any errors from the importer:
$extendedStatus = $job->extended_status;
if (isset($extendedStatus['errors']) && count($extendedStatus['errors']) > 0) {
$this->line(sprintf('The following %d error(s) occured during the import:', count($extendedStatus['errors'])));
foreach ($extendedStatus['errors'] as $error) {
$this->error($error);
}
}
return;
}
/**
* @param ImportJob $job
*
* @return bool
*/
private function isValid(ImportJob $job): bool
{
if (is_null($job)) {
$this->error('This job does not seem to exist.');
return false;
}
if ($job->status != 'settings_complete') {
$this->error('This job is not ready to be imported.');
return false;
}
return true;
}
}

View File

@@ -0,0 +1,99 @@
<?php
/**
* ScanAttachments.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Console\Commands;
use Crypt;
use FireflyIII\Models\Attachment;
use Illuminate\Console\Command;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Storage;
/**
* Class ScanAttachments
*
* @package FireflyIII\Console\Commands
*/
class ScanAttachments extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Rescan all attachments and re-set the MD5 hash and mime.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly:scan-attachments';
/**
* Create a new command instance.
*
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*/
public function handle()
{
$attachments = Attachment::get();
$disk = Storage::disk('upload');
/** @var Attachment $attachment */
foreach ($attachments as $attachment) {
$fileName = $attachment->fileName();
// try to grab file content:
try {
$content = $disk->get($fileName);
} catch (FileNotFoundException $e) {
$this->error(sprintf('Could not find data for attachment #%d', $attachment->id));
continue;
}
// try to decrypt content.
try {
$decrypted = Crypt::decrypt($content);
} catch (DecryptException $e) {
$this->error(sprintf('Could not decrypt data of attachment #%d', $attachment->id));
continue;
}
// make temp file:
$tmpfname = tempnam(sys_get_temp_dir(), 'FireflyIII');
// store content in temp file:
file_put_contents($tmpfname, $decrypted);
// get md5 and mime
$md5 = md5_file($tmpfname);
$mime = mime_content_type($tmpfname);
// update attachment:
$attachment->md5 = $md5;
$attachment->mime = $mime;
$attachment->save();
$this->line(sprintf('Fixed attachment #%d', $attachment->id));
// find file:
}
}
}

View File

@@ -25,7 +25,7 @@ class UpgradeFireflyInstructions extends Command
*
* @var string
*/
protected $description = 'Command description';
protected $description = 'Instructions in case of upgrade trouble.';
/**
* The name and signature of the console command.
*
@@ -44,8 +44,6 @@ class UpgradeFireflyInstructions extends Command
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
@@ -53,15 +51,22 @@ class UpgradeFireflyInstructions extends Command
/** @var string $version */
$version = config('firefly.version');
$config = config('upgrade.text');
$text = $config[$version] ?? null;
$text = null;
foreach (array_keys($config) as $compare) {
// if string starts with:
$len = strlen($compare);
if (substr($version, 0, $len) === $compare) {
$text = $config[$compare];
}
}
$this->line('+------------------------------------------------------------------------------+');
$this->line('');
if (is_null($text)) {
$this->line('Thank you for installing Firefly III, v' . $version);
$this->line('If you are upgrading from a previous version,');
$this->info('there are no extra upgrade instructions.');
$this->info('There are no extra upgrade instructions.');
$this->line('Firefly III should be ready for use.');
} else {
$this->line('Thank you for installing Firefly III, v' . $version);

View File

@@ -12,13 +12,13 @@ declare(strict_types = 1);
namespace FireflyIII\Console\Commands;
use Crypt;
use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User;
use Illuminate\Console\Command;
@@ -55,8 +55,6 @@ class VerifyDatabase extends Command
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
@@ -81,6 +79,9 @@ class VerifyDatabase extends Command
// report on journals with no transactions at all.
$this->reportNoTransactions();
// transfers with budgets.
$this->reportTransfersBudgets();
}
/**
@@ -91,14 +92,17 @@ class VerifyDatabase extends Command
$set = Account
::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
->leftJoin('users', 'accounts.user_id', '=', 'users.id')
->groupBy('accounts.id')
->having('transaction_count', '=', 0)
->get(['accounts.id', 'accounts.name', 'accounts.user_id', 'users.email', DB::raw('COUNT(`transactions`.`id`) AS `transaction_count`')]);
->groupBy(['accounts.id', 'accounts.encrypted', 'accounts.name', 'accounts.user_id', 'users.email'])
->whereNull('transactions.account_id')
->get(
['accounts.id', 'accounts.encrypted', 'accounts.name', 'accounts.user_id', 'users.email']
);
/** @var stdClass $entry */
foreach ($set as $entry) {
$line = 'User #' . $entry->user_id . ' (' . $entry->email . ') has account #' . $entry->id . ' ("' . Crypt::decrypt($entry->name)
. '") which has no transactions.';
$name = $entry->name;
$line = 'User #%d (%s) has account #%d ("%s") which has no transactions.';
$line = sprintf($line, $entry->user_id, $entry->email, $entry->id, $name);
$this->line($line);
}
}
@@ -111,9 +115,9 @@ class VerifyDatabase extends Command
$set = Budget
::leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id')
->leftJoin('users', 'budgets.user_id', '=', 'users.id')
->groupBy('budgets.id')
->having('budget_limit_count', '=', 0)
->get(['budgets.id', 'budgets.name', 'budgets.user_id', 'users.email', DB::raw('COUNT(`budget_limits`.`id`) AS `budget_limit_count`')]);
->groupBy(['budgets.id', 'budgets.name', 'budgets.user_id', 'users.email'])
->whereNull('budget_limits.id')
->get(['budgets.id', 'budgets.name', 'budgets.user_id', 'users.email']);
/** @var stdClass $entry */
foreach ($set as $entry) {
@@ -223,19 +227,16 @@ class VerifyDatabase extends Command
}
}
/**
*
*/
private function reportNoTransactions()
{
/*
* select transaction_journals.id, count(transactions.id) as transaction_count from transaction_journals
left join transactions ON transaction_journals.id = transactions.transaction_journal_id
group by transaction_journals.id
having transaction_count = 0
*/
$set = TransactionJournal
::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->groupBy('transaction_journals.id')
->having('transaction_count', '=', 0)
->get(['transaction_journals.id', DB::raw('COUNT(`transactions`.`id`) as `transaction_count`')]);
->whereNull('transactions.transaction_journal_id')
->get(['transaction_journals.id']);
foreach ($set as $entry) {
$this->error(
@@ -304,4 +305,29 @@ having transaction_count = 0
);
}
}
/**
*
*/
private function reportTransfersBudgets()
{
$set = TransactionJournal
::distinct()
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin('budget_transaction_journal', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id')
->where('transaction_types.type', TransactionType::TRANSFER)
->whereNotNull('budget_transaction_journal.budget_id')->get(['transaction_journals.id']);
/** @var TransactionJournal $entry */
foreach ($set as $entry) {
$this->error(
sprintf(
'Error: Transaction journal #%d is a transfer, but has a budget. Edit it without changing anything, so the budget will be removed.',
$entry->id
)
);
}
}
}

32
app/Console/Kernel.php Normal file → Executable file
View File

@@ -11,8 +11,12 @@ declare(strict_types = 1);
namespace FireflyIII\Console;
use FireflyIII\Console\Commands\EncryptFile;
use FireflyIII\Console\Commands\Import;
use FireflyIII\Console\Commands\ScanAttachments;
use FireflyIII\Console\Commands\UpgradeFireflyInstructions;
use FireflyIII\Console\Commands\VerifyDatabase;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
/**
@@ -22,11 +26,10 @@ use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
*/
class Kernel extends ConsoleKernel
{
/**
* The bootstrap classes for the application.
*
* This needs to be for with the next upgrade.
* Next upgrade verify these are the same.
*
* @var array
*/
@@ -51,5 +54,30 @@ class Kernel extends ConsoleKernel
= [
UpgradeFireflyInstructions::class,
VerifyDatabase::class,
Import::class,
EncryptFile::class,
ScanAttachments::class,
];
/**
* Register the Closure based commands for the application.
*
* @return void
*/
protected function commands()
{
require base_path('routes/console.php');
}
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
*
* @return void
*/
protected function schedule(Schedule $schedule)
{
}
}

View File

@@ -11,6 +11,7 @@ declare(strict_types = 1);
namespace FireflyIII\Crud\Account;
use Carbon\Carbon;
use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
@@ -26,6 +27,8 @@ use Log;
/**
* Class AccountCrud
*
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
*
* @package FireflyIII\Crud\Account
*/
class AccountCrud implements AccountCrudInterface
@@ -52,14 +55,14 @@ class AccountCrud implements AccountCrudInterface
*
* @return bool
*/
public function destroy(Account $account, Account $moveTo = null): bool
public function destroy(Account $account, Account $moveTo): bool
{
if (!is_null($moveTo)) {
// update all transactions:
if (!is_null($moveTo->id)) {
DB::table('transactions')->where('account_id', $account->id)->update(['account_id' => $moveTo->id]);
}
$account->delete();
if (!is_null($account)) {
$account->delete();
}
return true;
}
@@ -73,12 +76,96 @@ class AccountCrud implements AccountCrudInterface
{
$account = $this->user->accounts()->find($accountId);
if (is_null($account)) {
$account = new Account;
return new Account;
}
return $account;
}
/**
* @param string $number
* @param array $types
*
* @return Account
*/
public function findByAccountNumber(string $number, array $types): Account
{
$query = $this->user->accounts()
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
->where('account_meta.name', 'accountNumber')
->where('account_meta.data', json_encode($number));
if (count($types) > 0) {
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
$query->whereIn('account_types.type', $types);
}
/** @var Collection $accounts */
$accounts = $query->get(['accounts.*']);
if ($accounts->count() > 0) {
return $accounts->first();
}
return new Account;
}
/**
* @param string $iban
* @param array $types
*
* @return Account
*/
public function findByIban(string $iban, array $types): Account
{
$query = $this->user->accounts()->where('iban', '!=', '');
if (count($types) > 0) {
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
$query->whereIn('account_types.type', $types);
}
$accounts = $query->get(['accounts.*']);
/** @var Account $account */
foreach ($accounts as $account) {
if ($account->iban === $iban) {
return $account;
}
}
return new Account;
}
/**
* @param string $name
* @param array $types
*
* @return Account
*/
public function findByName(string $name, array $types): Account
{
$query = $this->user->accounts();
if (count($types) > 0) {
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
$query->whereIn('account_types.type', $types);
}
Log::debug(sprintf('Searching for account named %s of the following type(s)', $name), ['types' => $types]);
$accounts = $query->get(['accounts.*']);
/** @var Account $account */
foreach ($accounts as $account) {
if ($account->name === $name) {
Log::debug(sprintf('Found #%d (%s) with type id %d', $account->id, $account->name, $account->account_type_id));
return $account;
}
}
Log::debug('Found nothing.');
return new Account;
}
/**
* @param array $accountIds
*
@@ -98,7 +185,6 @@ class AccountCrud implements AccountCrudInterface
}
$result = $query->get(['accounts.*']);
$result = $result->sortBy(
function (Account $account) {
return strtolower($account->name);
@@ -126,7 +212,6 @@ class AccountCrud implements AccountCrudInterface
}
$result = $query->get(['accounts.*']);
$result = $result->sortBy(
function (Account $account) {
return strtolower($account->name);
@@ -140,31 +225,16 @@ class AccountCrud implements AccountCrudInterface
* @param array $data
*
* @return Account
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function store(array $data): Account
{
$newAccount = $this->storeAccount($data);
if (!is_null($newAccount)) {
if (!is_null($newAccount->id)) {
$this->storeMetadata($newAccount, $data);
}
// continue with the opposing account:
if ($data['openingBalance'] != 0) {
$opposingData = [
'user' => $data['user'],
'accountType' => 'initial',
'virtualBalance' => 0,
'name' => $data['name'] . ' initial balance',
'active' => false,
'iban' => '',
];
$opposing = $this->storeAccount($opposingData);
if (!is_null($opposing) && !is_null($newAccount)) {
$this->storeInitialBalance($newAccount, $opposing, $data);
}
$this->storeInitialBalance($newAccount, $data);
}
return $newAccount;
@@ -199,39 +269,29 @@ class AccountCrud implements AccountCrudInterface
$account->save();
$this->updateMetadata($account, $data);
$openingBalance = $this->openingBalanceTransaction($account);
if ($data['openingBalance'] != 0) {
if (!is_null($openingBalance->id)) {
$this->updateInitialBalance($account, $openingBalance, $data);
return $account;
}
$type = $data['openingBalance'] < 0 ? 'expense' : 'revenue';
$opposingData = [
'user' => $data['user'],
'accountType' => $type,
'name' => $data['name'] . ' initial balance',
'active' => false,
'iban' => '',
'virtualBalance' => 0,
];
$opposing = $this->storeAccount($opposingData);
if (!is_null($opposing)) {
$this->storeInitialBalance($account, $opposing, $data);
}
return $account;
}
if ($openingBalance) { // opening balance is zero, should we delete it?
$openingBalance->delete(); // delete existing opening balance.
}
$this->updateInitialBalance($account, $data);
return $account;
}
/**
* @param Account $account
* @param string $type
*
* @return Account
*/
public function updateAccountType(Account $account, string $type): Account
{
$type = AccountType::whereType($type)->first();
if (!is_null($type)) {
$account->accountType()->associate($type);
$account->save();
}
return $this->find($account->id);
}
/**
* @param array $data
*
@@ -263,8 +323,9 @@ class AccountCrud implements AccountCrudInterface
];
$existingAccount = Account::firstOrNullEncrypted($searchData);
if (!$existingAccount) {
Log::error('Account create error: ' . $newAccount->getErrors()->toJson());
abort(500);
Log::error('Account create error', $newAccount->getErrors()->toArray());
return new Account;
}
$newAccount = $existingAccount;
@@ -276,19 +337,21 @@ class AccountCrud implements AccountCrudInterface
/**
* @param Account $account
* @param Account $opposing
* @param array $data
*
* @return TransactionJournal
*/
protected function storeInitialBalance(Account $account, Account $opposing, array $data): TransactionJournal
protected function storeInitialBalance(Account $account, array $data): TransactionJournal
{
$amount = $data['openingBalance'];
$user = $data['user'];
$name = $data['name'];
$opposing = $this->storeOpposingAccount($amount, $user, $name);
$transactionType = TransactionType::whereType(TransactionType::OPENING_BALANCE)->first();
$journal = TransactionJournal::create(
[
'user_id' => $data['user'],
'transaction_type_id' => $transactionType->id,
'bill_id' => null,
'transaction_currency_id' => $data['openingBalanceCurrency'],
'description' => 'Initial balance for "' . $account->name . '"',
'completed' => true,
@@ -299,24 +362,22 @@ class AccountCrud implements AccountCrudInterface
$firstAccount = $account;
$secondAccount = $opposing;
$firstAmount = $data['openingBalance'];
$secondAmount = $data['openingBalance'] * -1;
$firstAmount = $amount;
$secondAmount = $amount * -1;
if ($data['openingBalance'] < 0) {
$firstAccount = $opposing;
$secondAccount = $account;
$firstAmount = $data['openingBalance'] * -1;
$secondAmount = $data['openingBalance'];
$firstAmount = $amount * -1;
$secondAmount = $amount;
}
$one = new Transaction(['account_id' => $firstAccount->id, 'transaction_journal_id' => $journal->id, 'amount' => $firstAmount]);
$one->save();// first transaction: from
$two = new Transaction(['account_id' => $secondAccount->id, 'transaction_journal_id' => $journal->id, 'amount' => $secondAmount]);
$two->save(); // second transaction: to
return $journal;
}
/**
@@ -336,36 +397,36 @@ class AccountCrud implements AccountCrudInterface
);
$metaData->save();
}
}
}
/**
* @param Account $account
* @param TransactionJournal $journal
* @param array $data
* @param Account $account
* @param array $data
*
* @return TransactionJournal
* @return bool
*/
protected function updateInitialBalance(Account $account, TransactionJournal $journal, array $data): TransactionJournal
protected function updateInitialBalance(Account $account, array $data): bool
{
$journal->date = $data['openingBalanceDate'];
$journal->save();
$openingBalance = $this->openingBalanceTransaction($account);
if ($data['openingBalance'] != 0) {
if (!is_null($openingBalance->id)) {
$date = $data['openingBalanceDate'];
$amount = $data['openingBalance'];
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
if ($account->id == $transaction->account_id) {
$transaction->amount = $data['openingBalance'];
$transaction->save();
}
if ($account->id != $transaction->account_id) {
$transaction->amount = $data['openingBalance'] * -1;
$transaction->save();
return $this->updateJournal($account, $openingBalance, $date, $amount);
}
$this->storeInitialBalance($account, $data);
return true;
}
// else, delete it:
if ($openingBalance) { // opening balance is zero, should we delete it?
$openingBalance->delete(); // delete existing opening balance.
}
return $journal;
return true;
}
/**
@@ -418,4 +479,56 @@ class AccountCrud implements AccountCrudInterface
return $journal;
}
}
/**
* @param float $amount
* @param int $user
* @param string $name
*
* @return Account
*/
private function storeOpposingAccount(float $amount, int $user, string $name):Account
{
$type = $amount < 0 ? 'expense' : 'revenue';
$opposingData = [
'user' => $user,
'accountType' => $type,
'name' => $name . ' initial balance',
'active' => false,
'iban' => '',
'virtualBalance' => 0,
];
return $this->storeAccount($opposingData);
}
/**
* @param Account $account
* @param TransactionJournal $journal
* @param Carbon $date
* @param float $amount
*
* @return bool
*/
private function updateJournal(Account $account, TransactionJournal $journal, Carbon $date, float $amount): bool
{
// update date:
$journal->date = $date;
$journal->save();
// update transactions:
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
if ($account->id == $transaction->account_id) {
$transaction->amount = $amount;
$transaction->save();
}
if ($account->id != $transaction->account_id) {
$transaction->amount = $amount * -1;
$transaction->save();
}
}
return true;
}
}

View File

@@ -37,6 +37,30 @@ interface AccountCrudInterface
*/
public function find(int $accountId): Account;
/**
* @param string $number
* @param array $types
*
* @return Account
*/
public function findByAccountNumber(string $number, array $types): Account;
/**
* @param string $iban
* @param array $types
*
* @return Account
*/
public function findByIban(string $iban, array $types): Account;
/**
* @param string $name
* @param array $types
*
* @return Account
*/
public function findByName(string $name, array $types): Account;
/**
* @param array $accountIds
*
@@ -67,7 +91,6 @@ interface AccountCrudInterface
*/
public function storeMeta(Account $account, string $name, $value): AccountMeta;
/**
* @param Account $account
* @param array $data
@@ -75,4 +98,12 @@ interface AccountCrudInterface
* @return Account
*/
public function update(Account $account, array $data): Account;
}
/**
* @param Account $account
* @param string $type
*
* @return Account
*/
public function updateAccountType(Account $account, string $type): Account;
}

View File

@@ -105,9 +105,6 @@ class Journal implements JournalInterface
*/
public function updateJournal(TransactionJournal $journal, array $data): TransactionJournal
{
echo '<pre>';
print_r($data);
$journal->description = $data['journal_description'];
$journal->transaction_currency_id = $data['journal_currency_id'];
$journal->date = $data['date'];
@@ -167,7 +164,8 @@ class Journal implements JournalInterface
{
$destinationAccount = Account::where('user_id', $this->user->id)->where('id', $data['destination_account_id'])->first(['accounts.*']);
if (strlen($data['source_account_name']) > 0) {
if (isset($data['source_account_name']) && strlen($data['source_account_name']) > 0) {
$sourceType = AccountType::where('type', 'Revenue account')->first();
$sourceAccount = Account::firstOrCreateEncrypted(
['user_id' => $this->user->id, 'account_type_id' => $sourceType->id, 'name' => $data['source_account_name'], 'active' => 1]
@@ -215,4 +213,4 @@ class Journal implements JournalInterface
}
}
}

View File

@@ -44,4 +44,4 @@ interface JournalInterface
* @return TransactionJournal
*/
public function updateJournal(TransactionJournal $journal, array $data): TransactionJournal;
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* UserIsConfirmed.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Events;
use FireflyIII\User;
use Illuminate\Queue\SerializesModels;
/**
* Class UserIsConfirmed
*
* @package FireflyIII\Events
*/
class UserIsConfirmed extends Event
{
use SerializesModels;
public $ipAddress;
public $user;
/**
* Create a new event instance.
*
* @param User $user
* @param string $ipAddress
*/
public function __construct(User $user, string $ipAddress)
{
$this->user = $user;
$this->ipAddress = $ipAddress;
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* UserIsDeleted.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Events;
use FireflyIII\User;
use Illuminate\Queue\SerializesModels;
/**
* Class UserIsDeleted
*
* @package FireflyIII\Events
*/
class UserIsDeleted extends Event
{
use SerializesModels;
public $ipAddress;
public $user;
/**
* Create a new event instance.
*
* @param User $user
* @param string $ipAddress
*/
public function __construct(User $user, string $ipAddress)
{
$this->user = $user;
$this->ipAddress = $ipAddress;
}
}

33
app/Exceptions/Handler.php Normal file → Executable file
View File

@@ -10,14 +10,15 @@
declare(strict_types = 1);
namespace FireflyIII\Exceptions;
use Auth;
use ErrorException;
use Exception;
use FireflyIII\Jobs\MailError;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Request;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Validation\ValidationException as ValException;
use Symfony\Component\HttpKernel\Exception\HttpException;
/**
@@ -34,9 +35,12 @@ class Handler extends ExceptionHandler
*/
protected $dontReport
= [
AuthenticationException::class,
AuthorizationException::class,
HttpException::class,
ModelNotFoundException::class,
TokenMismatchException::class,
ValException::class,
];
/**
@@ -71,15 +75,14 @@ class Handler extends ExceptionHandler
*/
public function report(Exception $exception)
{
if ($exception instanceof FireflyException || $exception instanceof ErrorException) {
$userData = [
'id' => 0,
'email' => 'unknown@example.com',
];
if (Auth::check()) {
$userData['id'] = Auth::user()->id;
$userData['email'] = Auth::user()->email;
if (auth()->check()) {
$userData['id'] = auth()->user()->id;
$userData['email'] = auth()->user()->email;
}
$data = [
'class' => get_class($exception),
@@ -92,10 +95,26 @@ class Handler extends ExceptionHandler
];
// create job that will mail.
$job = new MailError($userData, env('SITE_OWNER'), Request::ip(), $data);
$ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
$job = new MailError($userData, env('SITE_OWNER', ''), $ip, $data);
dispatch($job);
}
parent::report($exception);
}
/**
* Convert an authentication exception into an unauthenticated response.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
protected function unauthenticated($request)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
return redirect()->guest('login');
}
}

View File

@@ -83,15 +83,16 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
/** @var TransactionJournal $journal */
$journal = $attachment->attachable;
$args = [
'attachment_name' => $attachment->filename,
'attachment_name' => e($attachment->filename),
'attachment_id' => $attachment->id,
'type' => strtolower($journal->transactionType->type),
'description' => $journal->description,
'description' => e($journal->description),
'journal_id' => $journal->id,
'date' => $journal->date->formatLocalized(strval(trans('config.month_and_day'))),
'amount' => Amount::formatJournal($journal, false),
];
$string = trans('firefly.attachment_explanation', $args) . "\n";
Log::debug('Appended explanation string', ['string' => $string]);
$this->explanationString .= $string;
}

View File

@@ -11,7 +11,6 @@ declare(strict_types = 1);
namespace FireflyIII\Export\Collector;
use Auth;
use Crypt;
use FireflyIII\Models\ExportJob;
use Illuminate\Contracts\Encryption\DecryptException;
@@ -29,6 +28,7 @@ class UploadCollector extends BasicCollector implements CollectorInterface
private $expected;
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
private $exportDisk;
private $importKeys = [];
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
private $uploadDisk;
@@ -42,12 +42,17 @@ class UploadCollector extends BasicCollector implements CollectorInterface
{
parent::__construct($job);
Log::debug('Going to collect attachments', ['key' => $job->key]);
// make storage:
$this->uploadDisk = Storage::disk('upload');
$this->exportDisk = Storage::disk('export');
// todo needs work for new importer (potentially collect other types as well)
$this->expected = 'csv-upload-' . Auth::user()->id . '-';
// file names associated with the old import routine.
$this->expected = 'csv-upload-' . auth()->user()->id . '-';
// for the new import routine:
$this->getImportKeys();
}
/**
@@ -59,12 +64,26 @@ class UploadCollector extends BasicCollector implements CollectorInterface
$files = $this->uploadDisk->files();
foreach ($files as $entry) {
$this->processOldUpload($entry);
$this->processUpload($entry);
}
return true;
}
/**
*
*/
private function getImportKeys()
{
$set = auth()->user()->importJobs()->where('status', 'import_complete')->get(['import_jobs.*']);
if ($set->count() > 0) {
$keys = $set->pluck('key')->toArray();
$this->importKeys = $keys;
}
Log::debug('Valid import keys are ', $this->importKeys);
}
/**
* @param string $entry
*
@@ -85,9 +104,28 @@ class UploadCollector extends BasicCollector implements CollectorInterface
*
* @return bool
*/
private function isValidFile(string $entry): bool
private function isImportFile(string $entry): bool
{
$name = str_replace('.upload', '', $entry);
if (in_array($name, $this->importKeys)) {
Log::debug(sprintf('Import file "%s" is in array', $name), $this->importKeys);
return true;
}
Log::debug(sprintf('Import file "%s" is NOT in array', $name), $this->importKeys);
return false;
}
/**
* @param string $entry
*
* @return bool
*/
private function isOldImport(string $entry): bool
{
$len = strlen($this->expected);
// file is part of the old import routine:
if (substr($entry, 0, $len) === $this->expected) {
return true;
@@ -99,23 +137,63 @@ class UploadCollector extends BasicCollector implements CollectorInterface
/**
* @param $entry
*/
private function processOldUpload(string $entry)
private function processUpload(string $entry)
{
$content = '';
if ($this->isValidFile($entry)) {
try {
$content = Crypt::decrypt($this->uploadDisk->get($entry));
} catch (DecryptException $e) {
Log::error('Could not decrypt old CSV import file ' . $entry . '. Skipped because ' . $e->getMessage());
}
// file is old import:
if ($this->isOldImport($entry)) {
$this->saveOldImportFile($entry);
}
if (strlen($content) > 0) {
// continue with file:
$date = $this->getOriginalUploadDate($entry);
$file = $this->job->key . '-Old CSV import dated ' . $date . '.csv';
// file is current import.
if ($this->isImportFile($entry)) {
$this->saveImportFile($entry);
}
}
/**
* @param string $entry
*/
private function saveImportFile(string $entry)
{
// find job associated with import file:
$name = str_replace('.upload', '', $entry);
$job = auth()->user()->importJobs()->where('key', $name)->first();
$content = '';
try {
$content = Crypt::decrypt($this->uploadDisk->get($entry));
} catch (DecryptException $e) {
Log::error('Could not decrypt old import file ' . $entry . '. Skipped because ' . $e->getMessage());
}
if (!is_null($job) && strlen($content) > 0) {
// add to export disk.
$date = $job->created_at->format('Y-m-d');
$file = sprintf('%s-Old %s import dated %s.%s', $this->job->key, strtoupper($job->file_type), $date, $job->file_type);
$this->exportDisk->put($file, $content);
$this->getFiles()->push($file);
}
}
/**
* @param string $entry
*/
private function saveOldImportFile(string $entry)
{
$content = '';
try {
$content = Crypt::decrypt($this->uploadDisk->get($entry));
} catch (DecryptException $e) {
Log::error('Could not decrypt old CSV import file ' . $entry . '. Skipped because ' . $e->getMessage());
}
if (strlen($content) > 0) {
// add to export disk.
$date = $this->getOriginalUploadDate($entry);
$file = $this->job->key . '-Old import dated ' . $date . '.csv';
$this->exportDisk->put($file, $content);
$this->getFiles()->push($file);
}
}
}

View File

@@ -44,4 +44,4 @@ class EntryAccount
$this->type = $account->accountType->type;
$this->number = $account->getMeta('accountNumber');
}
}
}

View File

@@ -38,4 +38,4 @@ class EntryBill
}
}
}
}

View File

@@ -38,4 +38,4 @@ class EntryBudget
}
}
}
}

View File

@@ -37,4 +37,4 @@ class EntryCategory
$this->name = $category->name;
}
}
}
}

View File

@@ -104,4 +104,4 @@ class BudgetLimitEventHandler
}
}
}
}

View File

@@ -11,7 +11,6 @@ declare(strict_types = 1);
namespace FireflyIII\Handlers\Events;
use Auth;
use FireflyIII\Events\TransactionJournalStored;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
@@ -39,7 +38,7 @@ class ConnectJournalToPiggyBank
$piggyBankId = $event->piggyBankId;
/** @var PiggyBank $piggyBank */
$piggyBank = Auth::user()->piggybanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']);
$piggyBank = auth()->user()->piggyBanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']);
if (is_null($piggyBank)) {
return true;

View File

@@ -37,7 +37,7 @@ class ConnectTransactionToPiggyBank
$repository = app(PiggyBankRepositoryInterface::class);
$transaction = $event->transaction;
$piggyBank = $repository->find($transaction['piggy_bank_id']);
$piggyBank = $repository->find($transaction['piggy_bank_id']);
// valid piggy:
if (is_null($piggyBank->id)) {

View File

@@ -17,7 +17,6 @@ use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Rules\Processor;
use FireflyIII\User;
use Illuminate\Support\Facades\Auth;
/**
* Class FireRulesForStore
@@ -38,7 +37,7 @@ class FireRulesForStore
{
// get all the user's rule groups, with the rules, order by 'order'.
/** @var User $user */
$user = Auth::user();
$user = auth()->user();
$groups = $user->ruleGroups()->where('rule_groups.active', 1)->orderBy('order', 'ASC')->get();
//
/** @var RuleGroup $group */

View File

@@ -11,7 +11,6 @@ declare(strict_types = 1);
namespace FireflyIII\Handlers\Events;
use Auth;
use FireflyIII\Events\TransactionJournalUpdated;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup;
@@ -36,7 +35,7 @@ class FireRulesForUpdate
{
// get all the user's rule groups, with the rules, order by 'order'.
/** @var User $user */
$user = Auth::user();
$user = auth()->user();
$groups = $user->ruleGroups()->where('rule_groups.active', 1)->orderBy('order', 'ASC')->get();
//
/** @var RuleGroup $group */

View File

@@ -27,6 +27,7 @@ class UpdateJournalConnection
* Handle the event.
*
* @param TransactionJournalUpdated $event
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly 5.
*
* @return bool
*/
@@ -46,7 +47,7 @@ class UpdateJournalConnection
}
$piggyBank = $event->piggyBank()->first();
$repetition = null;
if ($piggyBank) {
if (!is_null($piggyBank)) {
/** @var PiggyBankRepetition $repetition */
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* UserSaveIpAddress.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\UserIsConfirmed;
use FireflyIII\Events\UserRegistration;
use Preferences;
/**
* Class UserSaveIpAddress
*
* @package FireflyIII\Handlers\Events
*/
class UserSaveIpAddress
{
/**
* Create the event listener.
*
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param UserIsConfirmed $event
*
* @return bool
*/
public function saveFromConfirmation(UserIsConfirmed $event): bool
{
Preferences::setForUser($event->user, 'confirmation_ip_address', $event->ipAddress);
return true;
}
/**
* Handle the event.
*
* @param UserRegistration $event
*
* @return bool
*/
public function saveFromRegistration(UserRegistration $event): bool
{
Preferences::setForUser($event->user, 'registration_ip_address', $event->ipAddress);
return true;
}
}

View File

@@ -10,7 +10,6 @@
declare(strict_types = 1);
namespace FireflyIII\Helpers\Attachments;
use Auth;
use Crypt;
use FireflyIII\Models\Attachment;
use Illuminate\Database\Eloquent\Model;
@@ -60,7 +59,7 @@ class AttachmentHelper implements AttachmentHelperInterface
*/
public function getAttachmentLocation(Attachment $attachment): string
{
$path = storage_path('upload') . DIRECTORY_SEPARATOR . 'at-' . $attachment->id . '.data';
$path = sprintf('%s%sat-%d.data', storage_path('upload'), DIRECTORY_SEPARATOR, intval($attachment->id));
return $path;
}
@@ -112,7 +111,7 @@ class AttachmentHelper implements AttachmentHelperInterface
$md5 = md5_file($file->getRealPath());
$name = $file->getClientOriginalName();
$class = get_class($model);
$count = Auth::user()->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
$count = auth()->user()->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
if ($count > 0) {
$msg = (string)trans('validation.file_already_attached', ['name' => $name]);
@@ -139,7 +138,7 @@ class AttachmentHelper implements AttachmentHelperInterface
}
$attachment = new Attachment; // create Attachment object.
$attachment->user()->associate(Auth::user());
$attachment->user()->associate(auth()->user());
$attachment->attachable()->associate($model);
$attachment->md5 = md5_file($file->getRealPath());
$attachment->filename = $file->getClientOriginalName();
@@ -250,6 +249,8 @@ class AttachmentHelper implements AttachmentHelperInterface
/**
* @param array $files
*
* @param Model $model
*
* @return bool
*/
private function processFiles(array $files, Model $model): bool

View File

@@ -32,14 +32,12 @@ class BalanceLine
/** @var BudgetModel */
protected $budget;
/** @var Carbon */
protected $startDate;
/** @var Carbon */
protected $endDate;
/** @var int */
protected $role = self::ROLE_DEFAULTROLE;
/** @var Carbon */
protected $startDate;
/**
*
@@ -90,6 +88,22 @@ class BalanceLine
$this->budget = $budget;
}
/**
* @return Carbon
*/
public function getEndDate()
{
return $this->endDate;
}
/**
* @param Carbon $endDate
*/
public function setEndDate($endDate)
{
$this->endDate = $endDate;
}
/**
* @return int
*/
@@ -106,6 +120,22 @@ class BalanceLine
$this->role = $role;
}
/**
* @return Carbon
*/
public function getStartDate()
{
return $this->startDate;
}
/**
* @param Carbon $startDate
*/
public function setStartDate($startDate)
{
$this->startDate = $startDate;
}
/**
* @return string
*/
@@ -127,39 +157,6 @@ class BalanceLine
return '';
}
/**
* @return Carbon
*/
public function getStartDate()
{
return $this->startDate;
}
/**
* @param Carbon $startDate
*/
public function setStartDate($startDate)
{
$this->startDate = $startDate;
}
/**
* @return Carbon
*/
public function getEndDate()
{
return $this->endDate;
}
/**
* @param Carbon $endDate
*/
public function setEndDate($endDate)
{
$this->endDate = $endDate;
}
/**
* If a BalanceLine has a budget/repetition, each BalanceEntry in this BalanceLine
* should have a "spent" value, which is the amount of money that has been spent

View File

@@ -41,46 +41,66 @@ class Budget
/**
* @param BudgetLine $budgetLine
*
* @return Budget
*/
public function addBudgetLine(BudgetLine $budgetLine)
public function addBudgetLine(BudgetLine $budgetLine): Budget
{
$this->budgetLines->push($budgetLine);
return $this;
}
/**
* @param string $add
*
* @return Budget
*/
public function addBudgeted(string $add)
public function addBudgeted(string $add): Budget
{
$add = strval(round($add, 2));
$this->budgeted = bcadd($this->budgeted, $add);
return $this;
}
/**
* @param string $add
*
* @return Budget
*/
public function addLeft(string $add)
public function addLeft(string $add): Budget
{
$add = strval(round($add, 2));
$this->left = bcadd($this->left, $add);
return $this;
}
/**
* @param string $add
*
* @return Budget
*/
public function addOverspent(string $add)
public function addOverspent(string $add): Budget
{
$add = strval(round($add, 2));
$this->overspent = bcadd($this->overspent, $add);
return $this;
}
/**
* @param string $add
*
* @return Budget
*/
public function addSpent(string $add)
public function addSpent(string $add): Budget
{
$add = strval(round($add, 2));
$this->spent = bcadd($this->spent, $add);
return $this;
}
/**
@@ -101,10 +121,14 @@ class Budget
/**
* @param string $budgeted
*
* @return Budget
*/
public function setBudgeted(string $budgeted)
public function setBudgeted(string $budgeted): Budget
{
$this->budgeted = $budgeted;
return $this;
}
/**
@@ -117,10 +141,14 @@ class Budget
/**
* @param string $left
*
* @return Budget
*/
public function setLeft(string $left)
public function setLeft(string $left): Budget
{
$this->left = $left;
return $this;
}
/**
@@ -133,10 +161,14 @@ class Budget
/**
* @param string $overspent
*
* @return Budget
*/
public function setOverspent(string $overspent)
public function setOverspent(string $overspent): Budget
{
$this->overspent = strval(round($overspent, 2));
return $this;
}
/**
@@ -149,10 +181,14 @@ class Budget
/**
* @param string $spent
*
* @return Budget
*/
public function setSpent(string $spent)
public function setSpent(string $spent): Budget
{
$this->spent = strval(round($spent, 2));
return $this;
}

View File

@@ -45,10 +45,14 @@ class BudgetLine
/**
* @param BudgetModel $budget
*
* @return BudgetLine
*/
public function setBudget(BudgetModel $budget)
public function setBudget(BudgetModel $budget): BudgetLine
{
$this->budget = $budget;
return $this;
}
/**
@@ -61,10 +65,14 @@ class BudgetLine
/**
* @param string $budgeted
*
* @return BudgetLine
*/
public function setBudgeted(string $budgeted)
public function setBudgeted(string $budgeted): BudgetLine
{
$this->budgeted = $budgeted;
return $this;
}
/**
@@ -77,10 +85,14 @@ class BudgetLine
/**
* @param string $left
*
* @return BudgetLine
*/
public function setLeft(string $left)
public function setLeft(string $left): BudgetLine
{
$this->left = $left;
return $this;
}
/**
@@ -93,10 +105,14 @@ class BudgetLine
/**
* @param string $overspent
*
* @return BudgetLine
*/
public function setOverspent(string $overspent)
public function setOverspent(string $overspent): BudgetLine
{
$this->overspent = $overspent;
return $this;
}
/**
@@ -109,10 +125,14 @@ class BudgetLine
/**
* @param LimitRepetition $repetition
*
* @return BudgetLine
*/
public function setRepetition(LimitRepetition $repetition)
public function setRepetition(LimitRepetition $repetition): BudgetLine
{
$this->repetition = $repetition;
return $this;
}
/**
@@ -125,10 +145,14 @@ class BudgetLine
/**
* @param string $spent
*
* @return BudgetLine
*/
public function setSpent(string $spent)
public function setSpent(string $spent): BudgetLine
{
$this->spent = $spent;
return $this;
}

View File

@@ -1,35 +0,0 @@
<?php
/**
* AccountId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Account;
/**
* Class AccountId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AccountId extends BasicConverter implements ConverterInterface
{
/**
* @return Account
*/
public function convert(): Account
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
$var = isset($this->mapped[$this->index][$this->value]) ? $this->mapped[$this->index][$this->value] : $this->value;
$account = $crud->find($var);
return $account;
}
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* Amount.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
/**
* Class Amount
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class Amount extends BasicConverter implements ConverterInterface
{
/**
* @return string
*/
public function convert(): string
{
if (is_numeric($this->value)) {
return strval($this->value);
}
return '0';
}
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* AmountComma.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
/**
* Class AmountComma
*
* Parses the input as the amount with a comma as decimal separator
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AmountComma extends BasicConverter implements ConverterInterface
{
/**
* @return float|int
*/
public function convert(): string
{
$value = str_replace(',', '.', strval($this->value));
if (is_numeric($value)) {
return strval($value);
}
return '0';
}
}

View File

@@ -1,89 +0,0 @@
<?php
/**
* AssetAccountIban.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use Carbon\Carbon;
use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
/**
* Class AssetAccountIban
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AssetAccountIban extends BasicConverter implements ConverterInterface
{
/**
* @return Account
*/
public function convert(): Account
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$account = $crud->find(intval($this->mapped[$this->index][$this->value]));
return $account;
}
if (strlen($this->value) > 0) {
$account = $this->searchOrCreate($crud);
return $account;
}
return new Account;
}
/**
* @param AccountCrudInterface $crud
*
* @return Account
*/
private function searchOrCreate(AccountCrudInterface $crud)
{
// find or create new account:
$set = $crud->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
/** @var Account $entry */
foreach ($set as $entry) {
if ($entry->iban == $this->value) {
return $entry;
}
}
// create it if doesn't exist.
$accountData = [
'name' => $this->value,
'accountType' => 'asset',
'virtualBalance' => 0,
'virtualBalanceCurrency' => 1, // hard coded.
'active' => true,
'user' => Auth::user()->id,
'iban' => $this->value,
'accountNumber' => $this->value,
'accountRole' => null,
'openingBalance' => 0,
'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => 1, // hard coded.
];
$account = $crud->store($accountData);
return $account;
}
}

View File

@@ -1,65 +0,0 @@
<?php
/**
* AssetAccountName.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
/**
* Class AssetAccountName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AssetAccountName extends BasicConverter implements ConverterInterface
{
/**
* @return Account|null
*/
public function convert(): Account
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
if (isset($this->mapped[$this->index][$this->value])) {
$account = $crud->find(intval($this->mapped[$this->index][$this->value]));
return $account;
}
$set = $crud->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
/** @var Account $entry */
foreach ($set as $entry) {
if ($entry->name == $this->value) {
return $entry;
}
}
$accountData = [
'name' => $this->value,
'accountType' => 'asset',
'virtualBalance' => 0,
'virtualBalanceCurrency' => 1, // hard coded.
'active' => true,
'user' => Auth::user()->id,
'iban' => null,
'accountNumber' => $this->value,
'accountRole' => null,
'openingBalance' => 0,
'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => 1, // hard coded.
];
$account = $crud->store($accountData);
return $account;
}
}

View File

@@ -1,77 +0,0 @@
<?php
/**
* AssetAccountNumber.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
/**
* Class AssetAccountNumber
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AssetAccountNumber extends BasicConverter implements ConverterInterface
{
/**
* @return Account|null
*/
public function convert(): Account
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$account = $crud->find(intval($this->mapped[$this->index][$this->value]));
return $account;
}
// if not, search for it (or create it):
$value = $this->value ?? '';
if (strlen($value) > 0) {
// find or create new account:
$set = $crud->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
/** @var Account $entry */
foreach ($set as $entry) {
$accountNumber = $entry->getMeta('accountNumber');
if ($accountNumber == $this->value) {
return $entry;
}
}
$accountData = [
'name' => $this->value,
'accountType' => 'asset',
'virtualBalance' => 0,
'virtualBalanceCurrency' => 1, // hard coded.
'active' => true,
'user' => Auth::user()->id,
'iban' => null,
'accountNumber' => $this->value,
'accountRole' => null,
'openingBalance' => 0,
'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => 1, // hard coded.
];
$account = $crud->store($accountData);
return $account;
}
return null; // is this accepted?
}
}

View File

@@ -1,114 +0,0 @@
<?php
/**
* BasicConverter.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
/**
* Class BasicConverter
*
*
* @SuppressWarnings(PHPMD.NumberOfChildren)
* @package FireflyIII\Helpers\Csv\Converter
*/
class BasicConverter
{
/** @var array */
protected $data;
/** @var string */
protected $field;
/** @var int */
protected $index;
/** @var array */
protected $mapped;
/** @var string */
protected $value;
/**
* @return array
*/
public function getData(): array
{
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
/**
* @return string
*/
public function getField(): string
{
return $this->field;
}
/**
* @param string $field
*/
public function setField(string $field)
{
$this->field = $field;
}
/**
* @return int
*/
public function getIndex(): int
{
return $this->index;
}
/**
* @param int $index
*/
public function setIndex(int $index)
{
$this->index = $index;
}
/**
* @return array
*/
public function getMapped(): array
{
return $this->mapped;
}
/**
* @param array $mapped
*/
public function setMapped(array $mapped)
{
$this->mapped = $mapped;
}
/**
* @return string
*/
public function getValue(): string
{
return $this->value;
}
/**
* @param string $value
*/
public function setValue(string $value)
{
$this->value = $value;
}
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* BillId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
/**
* Class BillId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class BillId extends BasicConverter implements ConverterInterface
{
/**
* @return Bill
*/
public function convert(): Bill
{
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$value = isset($this->mapped[$this->index][$this->value]) ? $this->mapped[$this->index][$this->value] : $this->value;
$bill = $repository->find($value);
return $bill;
}
}

View File

@@ -1,47 +0,0 @@
<?php
/**
* BillName.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
/**
* Class BillName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class BillName extends BasicConverter implements ConverterInterface
{
/**
* @return Bill
*/
public function convert(): Bill
{
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
return $repository->find($this->mapped[$this->index][$this->value]);
}
$bills = $repository->getBills();
/** @var Bill $bill */
foreach ($bills as $bill) {
if ($bill->name == $this->value) {
return $bill;
}
}
return new Bill;
}
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* BudgetId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
/**
* Class BudgetId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class BudgetId extends BasicConverter implements ConverterInterface
{
/**
* @return Budget
*/
public function convert(): Budget
{
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
$value = isset($this->mapped[$this->index][$this->value]) ? $this->mapped[$this->index][$this->value] : $this->value;
$budget = $repository->find($value);
return $budget;
}
}

View File

@@ -1,44 +0,0 @@
<?php
/**
* BudgetName.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
/**
* Class BudgetName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class BudgetName extends BasicConverter implements ConverterInterface
{
/**
* @return Budget
*/
public function convert(): Budget
{
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$budget = $repository->find($this->mapped[$this->index][$this->value]);
return $budget;
}
$budget = $repository->store(['name' => $this->value, 'user' => Auth::user()->id]);
return $budget;
}
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* CategoryId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
/**
* Class CategoryId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class CategoryId extends BasicConverter implements ConverterInterface
{
/**
* @return Category
*/
public function convert(): Category
{
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
$value = isset($this->mapped[$this->index][$this->value]) ? $this->mapped[$this->index][$this->value] : $this->value;
$category = $repository->find($value);
return $category;
}
}

View File

@@ -1,49 +0,0 @@
<?php
/**
* CategoryName.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
/**
* Class CategoryName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class CategoryName extends BasicConverter implements ConverterInterface
{
/**
* @return Category
*/
public function convert(): Category
{
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$category = $repository->find($this->mapped[$this->index][$this->value]);
return $category;
}
$data = [
'name' => $this->value,
'user' => Auth::user()->id,
];
$category = $repository->store($data);
return $category;
}
}

View File

@@ -1,52 +0,0 @@
<?php
/**
* ConverterInterface.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
/**
* Interface ConverterInterface
*
* @package FireflyIII\Helpers\Csv\Converter
*/
interface ConverterInterface
{
/**
* @return mixed
*/
public function convert();
/**
* @param array $data
*/
public function setData(array $data);
/**
* @param string $field
*
*/
public function setField(string $field);
/**
* @param int $index
*/
public function setIndex(int $index);
/**
* @param array $mapped
*/
public function setMapped(array $mapped);
/**
* @param string $value
*/
public function setValue(string $value);
}

View File

@@ -1,43 +0,0 @@
<?php
/**
* CurrencyCode.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
/**
* Class CurrencyCode
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class CurrencyCode extends BasicConverter implements ConverterInterface
{
/**
* @return TransactionCurrency
*/
public function convert(): TransactionCurrency
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
if (isset($this->mapped[$this->index][$this->value])) {
$currency = $repository->find(intval($this->mapped[$this->index][$this->value]));
return $currency;
}
$currency = $repository->findByCode($this->value);
return $currency;
}
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* CurrencyId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
/**
* Class CurrencyId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class CurrencyId extends BasicConverter implements ConverterInterface
{
/**
* @return TransactionCurrency
*/
public function convert(): TransactionCurrency
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$value = isset($this->mapped[$this->index][$this->value]) ? $this->mapped[$this->index][$this->value] : $this->value;
$currency = $repository->find($value);
return $currency;
}
}

View File

@@ -1,42 +0,0 @@
<?php
/**
* CurrencyName.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
/**
* Class CurrencyName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class CurrencyName extends BasicConverter implements ConverterInterface
{
/**
* @return TransactionCurrency
*/
public function convert(): TransactionCurrency
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
if (isset($this->mapped[$this->index][$this->value])) {
$currency = $repository->find($this->mapped[$this->index][$this->value]);
return $currency;
}
$currency = $repository->findByName($this->value);
return $currency;
}
}

View File

@@ -1,43 +0,0 @@
<?php
/**
* CurrencySymbol.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
/**
* Class CurrencySymbol
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class CurrencySymbol extends BasicConverter implements ConverterInterface
{
/**
* @return TransactionCurrency
*/
public function convert(): TransactionCurrency
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
if (isset($this->mapped[$this->index][$this->value])) {
$currency = $repository->find($this->mapped[$this->index][$this->value]);
return $currency;
}
$currency = $repository->findBySymbol($this->value);
return $currency;
}
}

View File

@@ -1,46 +0,0 @@
<?php
/**
* Date.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use InvalidArgumentException;
use Log;
/**
* Class Date
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class Date extends BasicConverter implements ConverterInterface
{
/**
* @return Carbon
* @throws FireflyException
*/
public function convert(): Carbon
{
$format = session('csv-date-format');
try {
$date = Carbon::createFromFormat($format, $this->value);
} catch (InvalidArgumentException $e) {
Log::error('Date conversion error: ' . $e->getMessage() . '. Value was "' . $this->value . '", format was "' . $format . '".');
$message = trans('firefly.csv_date_parse_error', ['format' => $format, 'value' => $this->value]);
throw new FireflyException($message);
}
return $date;
}
}

View File

@@ -1,64 +0,0 @@
<?php
/**
* OpposingAccountIban.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Models\Account;
/**
* Class OpposingAccountIban
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class OpposingAccountIban extends BasicConverter implements ConverterInterface
{
/**
* If mapped, return account. Otherwise, only return the name itself.
*
* @return Account|string
*/
public function convert()
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
if (isset($this->mapped[$this->index][$this->value])) {
$account = $crud->find($this->mapped[$this->index][$this->value]);
return $account;
}
return $this->findAccount($crud);
}
/**
* @param AccountCrudInterface $crud
*
* @return Account|string
*/
private function findAccount(AccountCrudInterface $crud)
{
if (strlen($this->value) > 0) {
$set = $crud->getAccountsByType([]);
/** @var Account $account */
foreach ($set as $account) {
if ($account->iban == $this->value) {
return $account;
}
}
}
return $this->value;
}
}

View File

@@ -1,35 +0,0 @@
<?php
/**
* OpposingAccountId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Account;
/**
* Class OpposingAccountId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class OpposingAccountId extends BasicConverter implements ConverterInterface
{
/**
* @return Account
*/
public function convert(): Account
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
$value = isset($this->mapped[$this->index][$this->value]) ? $this->mapped[$this->index][$this->value] : $this->value;
$account = $crud->find($value);
return $account;
}
}

View File

@@ -1,41 +0,0 @@
<?php
/**
* OpposingAccountName.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Account;
/**
* Class OpposingAccountName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class OpposingAccountName extends BasicConverter implements ConverterInterface
{
/**
* If mapped, return account. Otherwise, only return the name itself.
*
* @return Account|string
*/
public function convert()
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
if (isset($this->mapped[$this->index][$this->value])) {
$account = $crud->find($this->mapped[$this->index][$this->value]);
return $account;
}
return $this->value;
}
}

View File

@@ -1,53 +0,0 @@
<?php
/**
* TagsComma.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use Illuminate\Support\Collection;
/**
* Class TagsComma
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class TagsComma extends BasicConverter implements ConverterInterface
{
/**
* @return Collection
*/
public function convert(): Collection
{
/** @var TagRepositoryInterface $repository */
$repository = app(TagRepositoryInterface::class);
$tags = new Collection;
$strings = explode(',', $this->value);
foreach ($strings as $string) {
$data = [
'tag' => $string,
'date' => null,
'description' => null,
'latitude' => null,
'longitude' => null,
'zoomLevel' => null,
'tagMode' => 'nothing',
];
if (strlen($string) > 0) {
$tag = $repository->store($data); // should validate first?
$tags->push($tag);
}
}
$tags = $tags->merge($this->data['tags']);
return $tags;
}
}

View File

@@ -1,54 +0,0 @@
<?php
/**
* TagsSpace.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use Illuminate\Support\Collection;
/**
* Class TagsSpace
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class TagsSpace extends BasicConverter implements ConverterInterface
{
/**
* @return Collection
*/
public function convert(): Collection
{
/** @var TagRepositoryInterface $repository */
$repository = app(TagRepositoryInterface::class);
$tags = new Collection;
$strings = explode(' ', $this->value);
foreach ($strings as $string) {
$data = [
'tag' => $string,
'date' => null,
'description' => null,
'latitude' => null,
'longitude' => null,
'zoomLevel' => null,
'tagMode' => 'nothing',
];
if (strlen($string) > 0) {
$tag = $repository->store($data); // should validate first?
$tags->push($tag);
}
}
$tags = $tags->merge($this->data['tags']);
return $tags;
}
}

View File

@@ -1,336 +0,0 @@
<?php
/**
* Data.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv;
use Crypt;
use League\Csv\Reader;
use Session;
use Storage;
/**
* Class Data
*
* @package FireflyIII\Helpers\Csv
*/
class Data
{
/** @var string */
protected $csvFileContent = '';
/** @var string */
protected $csvFileLocation = '';
/** @var string */
protected $dateFormat = '';
/** @var string */
protected $delimiter = '';
/** @var bool */
protected $hasHeaders;
/** @var int */
protected $importAccount = 0;
/** @var array */
protected $map = [];
/** @var array */
protected $mapped = [];
/** @var Reader */
protected $reader;
/** @var array */
protected $roles = [];
/** @var array */
protected $specifix = [];
/**
*/
public function __construct()
{
$this->sessionHasHeaders();
$this->sessionDateFormat();
$this->sessionCsvFileLocation();
$this->sessionMap();
$this->sessionRoles();
$this->sessionMapped();
$this->sessionSpecifix();
$this->sessionImportAccount();
$this->sessionDelimiter();
}
/**
*
* @return string
*/
public function getCsvFileContent(): string
{
return $this->csvFileContent ?? '';
}
/**
*
* @param string $csvFileContent
*/
public function setCsvFileContent(string $csvFileContent)
{
$this->csvFileContent = $csvFileContent;
}
/**
* FIXxME may return null
*
* @return string
*/
public function getCsvFileLocation(): string
{
return $this->csvFileLocation;
}
/**
*
* @param string $csvFileLocation
*/
public function setCsvFileLocation(string $csvFileLocation)
{
Session::put('csv-file', $csvFileLocation);
$this->csvFileLocation = $csvFileLocation;
}
/**
* FIXxME may return null
*
* @return string
*/
public function getDateFormat(): string
{
return $this->dateFormat;
}
/**
*
* @param string $dateFormat
*/
public function setDateFormat(string $dateFormat)
{
Session::put('csv-date-format', $dateFormat);
$this->dateFormat = $dateFormat;
}
/**
* FIXxME may return null
*
* @return string
*/
public function getDelimiter(): string
{
return $this->delimiter;
}
/**
*
* @param string $delimiter
*/
public function setDelimiter(string $delimiter)
{
Session::put('csv-delimiter', $delimiter);
$this->delimiter = $delimiter;
}
/**
*
* @return array
*/
public function getMap(): array
{
return $this->map;
}
/**
*
* @param array $map
*/
public function setMap(array $map)
{
Session::put('csv-map', $map);
$this->map = $map;
}
/**
*
* @return array
*/
public function getMapped(): array
{
return $this->mapped;
}
/**
*
* @param array $mapped
*/
public function setMapped(array $mapped)
{
Session::put('csv-mapped', $mapped);
$this->mapped = $mapped;
}
/**
*
* @return Reader
*/
public function getReader(): Reader
{
if (!is_null($this->csvFileContent) && strlen($this->csvFileContent) === 0) {
$this->loadCsvFile();
}
if (is_null($this->reader)) {
$this->reader = Reader::createFromString($this->getCsvFileContent());
$this->reader->setDelimiter($this->delimiter);
}
return $this->reader;
}
/**
*
* @return array
*/
public function getRoles(): array
{
return $this->roles;
}
/**
*
* @param array $roles
*/
public function setRoles(array $roles)
{
Session::put('csv-roles', $roles);
$this->roles = $roles;
}
/**
*
* @return array
*/
public function getSpecifix(): array
{
return is_array($this->specifix) ? $this->specifix : [];
}
/**
*
* @param array $specifix
*/
public function setSpecifix(array $specifix)
{
Session::put('csv-specifix', $specifix);
$this->specifix = $specifix;
}
/**
*
* @return bool
*/
public function hasHeaders(): bool
{
return $this->hasHeaders;
}
/**
*
* @param bool $hasHeaders
*/
public function setHasHeaders(bool $hasHeaders)
{
Session::put('csv-has-headers', $hasHeaders);
$this->hasHeaders = $hasHeaders;
}
/**
*
* @param int $importAccount
*/
public function setImportAccount(int $importAccount)
{
Session::put('csv-import-account', $importAccount);
$this->importAccount = $importAccount;
}
protected function loadCsvFile()
{
$file = $this->getCsvFileLocation();
$disk = Storage::disk('upload');
$content = $disk->get($file);
$contentDecrypted = Crypt::decrypt($content);
$this->setCsvFileContent($contentDecrypted);
}
protected function sessionCsvFileLocation()
{
if (Session::has('csv-file')) {
$this->csvFileLocation = (string)session('csv-file');
}
}
protected function sessionDateFormat()
{
if (Session::has('csv-date-format')) {
$this->dateFormat = (string)session('csv-date-format');
}
}
protected function sessionDelimiter()
{
if (Session::has('csv-delimiter')) {
$this->delimiter = session('csv-delimiter');
}
}
protected function sessionHasHeaders()
{
if (Session::has('csv-has-headers')) {
$this->hasHeaders = (bool)session('csv-has-headers');
}
}
protected function sessionImportAccount()
{
if (Session::has('csv-import-account')) {
$this->importAccount = intval(session('csv-import-account'));
}
}
protected function sessionMap()
{
if (Session::has('csv-map')) {
$this->map = (array)session('csv-map');
}
}
protected function sessionMapped()
{
if (Session::has('csv-mapped')) {
$this->mapped = (array)session('csv-mapped');
}
}
protected function sessionRoles()
{
if (Session::has('csv-roles')) {
$this->roles = (array)session('csv-roles');
}
}
protected function sessionSpecifix()
{
if (Session::has('csv-specifix')) {
$this->specifix = (array)session('csv-specifix');
}
}
}

View File

@@ -1,384 +0,0 @@
<?php
/**
* Importer.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv;
use Auth;
use FireflyIII\Events\TransactionJournalStored;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Csv\Converter\ConverterInterface;
use FireflyIII\Helpers\Csv\PostProcessing\PostProcessorInterface;
use FireflyIII\Helpers\Csv\Specifix\SpecifixInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
use Log;
/**
* Class Importer
*
* @package FireflyIII\Helpers\Csv
*/
class Importer
{
/** @var Data */
protected $data;
/** @var array */
protected $errors = [];
/** @var array */
protected $importData;
/** @var array */
protected $importRow;
/** @var int */
protected $imported = 0;
/** @var Collection */
protected $journals;
/** @var array */
protected $map;
/** @var array */
protected $mapped;
/** @var array */
protected $roles;
/** @var int */
protected $rows = 0;
/** @var array */
protected $specifix = [];
/**
* Used by CsvController.
*
* @return array
*/
public function getErrors(): array
{
return $this->errors;
}
/**
* Used by CsvController
*
* @return int
*/
public function getImported(): int
{
return $this->imported;
}
/**
* @return Collection
*/
public function getJournals(): Collection
{
return $this->journals;
}
/**
* Used by CsvController
*
* @return int
*/
public function getRows(): int
{
return $this->rows;
}
/**
* @return array
*/
public function getSpecifix(): array
{
return is_array($this->specifix) ? $this->specifix : [];
}
/**
* @throws FireflyException
*/
public function run()
{
set_time_limit(0);
$this->journals = new Collection;
$this->map = $this->data->getMap();
$this->roles = $this->data->getRoles();
$this->mapped = $this->data->getMapped();
$this->specifix = $this->data->getSpecifix();
foreach ($this->data->getReader() as $index => $row) {
if ($this->parseRow($index)) {
$this->rows++;
$result = $this->importRow($row);
if (!($result instanceof TransactionJournal)) {
Log::error('Caught error at row #' . $index . ': ' . $result);
$this->errors[$index] = $result;
} else {
$this->imported++;
$this->journals->push($result);
event(new TransactionJournalStored($result, 0));
}
}
}
}
/**
* @param Data $data
*/
public function setData(Data $data)
{
$this->data = $data;
}
/**
* @return TransactionJournal|string
*/
protected function createTransactionJournal()
{
$date = $this->importData['date'];
if (is_null($this->importData['date'])) {
$date = $this->importData['date-rent'];
}
$transactionType = $this->getTransactionType(); // defaults to deposit
$errors = new MessageBag;
$journal = TransactionJournal::create(
[
'user_id' => Auth::user()->id,
'transaction_type_id' => $transactionType->id,
'transaction_currency_id' => $this->importData['currency']->id,
'description' => $this->importData['description'],
'completed' => 0,
'date' => $date,
'bill_id' => $this->importData['bill-id'],
]
);
if ($journal->getErrors()->count() == 0) {
// first transaction
$accountId = $this->importData['asset-account-object']->id; // create first transaction:
$amount = $this->importData['amount'];
$transaction = Transaction::create(['transaction_journal_id' => $journal->id, 'account_id' => $accountId, 'amount' => $amount]);
$errors = $transaction->getErrors();
// second transaction
$accountId = $this->importData['opposing-account-object']->id; // create second transaction:
$amount = bcmul($this->importData['amount'], '-1');
$transaction = Transaction::create(['transaction_journal_id' => $journal->id, 'account_id' => $accountId, 'amount' => $amount]);
$errors = $transaction->getErrors()->merge($errors);
}
if ($errors->count() == 0) {
$journal->completed = 1;
$journal->save();
} else {
$text = join(',', $errors->all());
return $text;
}
$this->saveBudget($journal);
$this->saveCategory($journal);
$this->saveTags($journal);
// some debug info:
$journalId = $journal->id;
$type = $journal->transaction_type_type ?? $journal->transactionType->type;
/** @var Account $asset */
$asset = $this->importData['asset-account-object'];
/** @var Account $opposing */
$opposing = $this->importData['opposing-account-object'];
Log::info('Created journal #' . $journalId . ' of type ' . $type . '!');
Log::info('Asset account #' . $asset->id . ' lost/gained: ' . $this->importData['amount']);
Log::info($opposing->accountType->type . ' #' . $opposing->id . ' lost/gained: ' . bcmul($this->importData['amount'], '-1'));
return $journal;
}
/**
* @return TransactionType
*/
protected function getTransactionType()
{
$transactionType = TransactionType::where('type', TransactionType::DEPOSIT)->first();
if ($this->importData['amount'] < 0) {
$transactionType = TransactionType::where('type', TransactionType::WITHDRAWAL)->first();
}
if (in_array($this->importData['opposing-account-object']->accountType->type, ['Asset account', 'Default account'])) {
$transactionType = TransactionType::where('type', TransactionType::TRANSFER)->first();
}
return $transactionType;
}
/**
* @param array $row
*
* @throws FireflyException
* @return string|bool
*/
protected function importRow(array $row)
{
$data = $this->getFiller(); // These fields are necessary to create a new transaction journal. Some are optional
foreach ($row as $index => $value) {
$role = $this->roles[$index] ?? '_ignore';
$class = config('csv.roles.' . $role . '.converter');
$field = config('csv.roles.' . $role . '.field');
// here would be the place where preprocessors would fire.
/** @var ConverterInterface $converter */
$converter = app('FireflyIII\Helpers\Csv\Converter\\' . $class);
$converter->setData($data); // the complete array so far.
$converter->setField($field);
$converter->setIndex($index);
$converter->setMapped($this->mapped);
$converter->setValue($value);
$data[$field] = $converter->convert();
}
// move to class vars.
$this->importData = $data;
$this->importRow = $row;
unset($data, $row);
// post processing and validating.
$this->postProcess();
$result = $this->validateData();
if (!($result === true)) {
return $result; // return error.
}
$journal = $this->createTransactionJournal();
return $journal;
}
/**
* @param int $index
*
* @return bool
*/
protected function parseRow(int $index)
{
return (($this->data->hasHeaders() && $index >= 1) || !$this->data->hasHeaders());
}
/**
* Row denotes the original data.
*
* @return void
*/
protected function postProcess()
{
// do bank specific fixes (must be enabled but now all of them.
foreach ($this->getSpecifix() as $className) {
/** @var SpecifixInterface $specifix */
$specifix = app('FireflyIII\Helpers\Csv\Specifix\\' . $className);
if ($specifix->getProcessorType() == SpecifixInterface::POST_PROCESSOR) {
$specifix->setData($this->importData);
$specifix->setRow($this->importRow);
$this->importData = $specifix->fix();
}
}
$set = config('csv.post_processors');
foreach ($set as $className) {
/** @var PostProcessorInterface $postProcessor */
$postProcessor = app('FireflyIII\Helpers\Csv\PostProcessing\\' . $className);
$array = $this->importData ?? [];
$postProcessor->setData($array);
$this->importData = $postProcessor->process();
}
}
/**
* @param TransactionJournal $journal
*/
protected function saveBudget(TransactionJournal $journal)
{
// add budget:
if (!is_null($this->importData['budget'])) {
$journal->budgets()->save($this->importData['budget']);
}
}
/**
* @param TransactionJournal $journal
*/
protected function saveCategory(TransactionJournal $journal)
{
// add category:
if (!is_null($this->importData['category'])) {
$journal->categories()->save($this->importData['category']);
}
}
/**
* @param TransactionJournal $journal
*/
protected function saveTags(TransactionJournal $journal)
{
if (!is_null($this->importData['tags'])) {
foreach ($this->importData['tags'] as $tag) {
$journal->tags()->save($tag);
}
}
}
/**
*
* @return bool|string
*/
protected function validateData()
{
$date = $this->importData['date'] ?? null;
$rentDate = $this->importData['date-rent'] ?? null;
if (is_null($date) && is_null($rentDate)) {
return 'No date value for this row.';
}
if (is_null($this->importData['opposing-account-object'])) {
return 'Opposing account is null';
}
if (!($this->importData['asset-account-object'] instanceof Account)) {
return 'No asset account to import into.';
}
return true;
}
/**
* @return array
*/
private function getFiller()
{
$filler = [];
foreach (config('csv.roles') as $role) {
if (isset($role['field'])) {
$fieldName = $role['field'];
$filler[$fieldName] = null;
}
}
// some extra's:
$filler['bill-id'] = null;
$filler['opposing-account-object'] = null;
$filler['asset-account-object'] = null;
$filler['amount-modifier'] = '1';
return $filler;
}
}

View File

@@ -1,42 +0,0 @@
<?php
/**
* AnyAccount.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Mapper;
use Auth;
use FireflyIII\Models\Account;
/**
* Class AnyAccount
*
* @package FireflyIII\Helpers\Csv\Mapper
*/
class AnyAccount implements MapperInterface
{
/**
* @return array
*/
public function getMap(): array
{
$result = Auth::user()->accounts()->with('accountType')->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
$list = [];
/** @var Account $account */
foreach ($result as $account) {
$list[$account->id] = $account->name . ' (' . $account->accountType->type . ')';
}
asort($list);
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}

View File

@@ -1,42 +0,0 @@
<?php
/**
* Bill.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Mapper;
use Auth;
use FireflyIII\Models\Bill as BillModel;
/**
* Class Bill
*
* @package FireflyIII\Helpers\Csv\Mapper
*/
class Bill implements MapperInterface
{
/**
* @return array
*/
public function getMap(): array
{
$result = Auth::user()->bills()->get(['bills.*']);
$list = [];
/** @var BillModel $bill */
foreach ($result as $bill) {
$list[$bill->id] = $bill->name . ' [' . $bill->match . ']';
}
asort($list);
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}

View File

@@ -1,42 +0,0 @@
<?php
/**
* Budget.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Mapper;
use Auth;
use FireflyIII\Models\Budget as BudgetModel;
/**
* Class Budget
*
* @package FireflyIII\Helpers\Csv\Mapper
*/
class Budget implements MapperInterface
{
/**
* @return array
*/
public function getMap(): array
{
$result = Auth::user()->budgets()->get(['budgets.*']);
$list = [];
/** @var BudgetModel $budget */
foreach ($result as $budget) {
$list[$budget->id] = $budget->name;
}
asort($list);
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}

View File

@@ -1,42 +0,0 @@
<?php
/**
* Category.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Mapper;
use Auth;
use FireflyIII\Models\Category as CategoryModel;
/**
* Class Category
*
* @package FireflyIII\Helpers\Csv\Mapper
*/
class Category implements MapperInterface
{
/**
* @return array
*/
public function getMap(): array
{
$result = Auth::user()->categories()->get(['categories.*']);
$list = [];
/** @var CategoryModel $category */
foreach ($result as $category) {
$list[$category->id] = $category->name;
}
asort($list);
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}

View File

@@ -1,42 +0,0 @@
<?php
/**
* Tag.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Mapper;
use Auth;
use FireflyIII\Models\Tag as TagModel;
/**
* Class Tag
*
* @package FireflyIII\Helpers\Csv\Mapper
*/
class Tag implements MapperInterface
{
/**
* @return array
*/
public function getMap(): array
{
$result = Auth::user()->budgets()->get(['tags.*']);
$list = [];
/** @var TagModel $tag */
foreach ($result as $tag) {
$list[$tag->id] = $tag->tag;
}
asort($list);
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}

View File

@@ -1,44 +0,0 @@
<?php
/**
* Amount.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
/**
* Class Amount
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class Amount implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process(): array
{
$amount = $this->data['amount'] ?? '0';
$modifier = strval($this->data['amount-modifier']);
$this->data['amount'] = bcmul($amount, $modifier);
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
}

View File

@@ -1,274 +0,0 @@
<?php
/**
* AssetAccount.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
use Auth;
use Carbon\Carbon;
use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use Validator;
/**
* Class AssetAccount
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class AssetAccount implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process(): array
{
$result = $this->checkIdNameObject(); // has object in ID or Name?
if (!is_null($result)) {
return $result;
}
// no object? maybe asset-account-iban is a string and we can find the matching account.
$result = $this->checkIbanString();
if (!is_null($result)) {
return $result;
}
// no object still? maybe we can find the account by name.
$result = $this->checkNameString();
if (!is_null($result)) {
return $result;
}
// still nothing? Perhaps the account number can lead us to an account:
$result = $this->checkAccountNumberString();
if (!is_null($result)) {
return $result;
}
return null;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
/**
* @return array|null
*/
protected function checkAccountNumberString()
{
$accountNumber = $this->data['asset-account-number'] ?? null;
if ($accountNumber instanceof Account) { // fourth: try to find account based on name, if any.
$this->data['asset-account-object'] = $accountNumber;
return $this->data;
}
if (is_string($accountNumber)) { // it's an actual account number
$this->data['asset-account-object'] = $this->parseAccountNumberString();
return $this->data;
}
return null;
}
/**
* @return array|null
*/
protected function checkIbanString()
{
$iban = $this->data['asset-account-iban'] ?? '';
$rules = ['iban' => 'iban'];
$check = ['iban' => $iban];
$validator = Validator::make($check, $rules);
if (!$validator->fails()) {
$this->data['asset-account-object'] = $this->parseIbanString();
return $this->data;
}
return null;
}
/**
* @return array
*/
protected function checkIdNameObject()
{
$accountId = $this->data['asset-account-id'] ?? null;
$accountIban = $this->data['asset-account-iban'] ?? null;
$accountNumber = $this->data['asset-account-number'] ?? null;
if ($accountId instanceof Account) { // first priority. try to find the account based on ID, if any
$this->data['asset-account-object'] = $accountId;
return $this->data;
}
if ($accountIban instanceof Account) { // second: try to find the account based on IBAN, if any.
$this->data['asset-account-object'] = $accountIban;
return $this->data;
}
if ($accountNumber instanceof Account) { // second: try to find the account based on account number, if any.
$this->data['asset-account-object'] = $accountNumber;
return $this->data;
}
return null;
}
/**
* @return array|null
*/
protected function checkNameString()
{
$accountName = $this->data['asset-account-name'] ?? null;
if ($accountName instanceof Account) { // third: try to find account based on name, if any.
$this->data['asset-account-object'] = $accountName;
return $this->data;
}
if (is_string($accountName)) {
$this->data['asset-account-object'] = $this->parseNameString();
return $this->data;
}
return null;
}
/**
* @return Account|null
*/
protected function createAccount()
{
$accountType = $this->getAccountType();
$name = $this->data['asset-account-name'] ?? '';
$iban = $this->data['asset-account-iban'] ?? '';
// create if not exists: // See issue #180
$name = strlen($name) > 0 ? $name : $iban;
$account = Account::firstOrCreateEncrypted(
[
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'name' => $name,
'iban' => $iban,
'active' => true,
]
);
return $account;
}
/**
*
* @return AccountType
*/
protected function getAccountType()
{
return AccountType::where('type', 'Asset account')->first();
}
/**
* @return Account|null
*/
protected function parseIbanString()
{
// create by name and/or iban.
$iban = $this->data['asset-account-iban'] ?? '';
$accounts = Auth::user()->accounts()->get();
foreach ($accounts as $entry) {
if ($iban !== '' && $entry->iban === $iban) {
return $entry;
}
}
$account = $this->createAccount();
return $account;
}
/**
* @return Account|null
*/
protected function parseNameString()
{
$accountType = $this->getAccountType();
$accounts = Auth::user()->accounts()->where('account_type_id', $accountType->id)->get();
foreach ($accounts as $entry) {
if ($entry->name == $this->data['asset-account-name']) {
return $entry;
}
}
// create if not exists:
// See issue #180
$account = Account::firstOrCreateEncrypted(
[
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'name' => $this->data['asset-account-name'],
'iban' => '',
'active' => true,
]
);
return $account;
}
/**
* @return Account|null
*/
private function parseAccountNumberString()
{
/** @var AccountCrudInterface $crud */
$crud = app(AccountCrudInterface::class);
$accountNumber = $this->data['asset-account-number'] ?? '';
$accountType = $this->getAccountType();
$accounts = Auth::user()->accounts()->with(['accountmeta'])->where('account_type_id', $accountType->id)->get();
/** @var Account $entry */
foreach ($accounts as $entry) {
$metaFieldValue = $entry->getMeta('accountNumber');
if ($metaFieldValue === $accountNumber && $metaFieldValue !== '') {
return $entry;
}
}
// create new if not exists and return that one:
$accountData = [
'name' => $accountNumber,
'accountType' => 'asset',
'virtualBalance' => 0,
'virtualBalanceCurrency' => 1, // hard coded.
'active' => true,
'user' => Auth::user()->id,
'iban' => null,
'accountNumber' => $accountNumber,
'accountRole' => null,
'openingBalance' => 0,
'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => 1, // hard coded.
];
$account = $crud->store($accountData);
return $account;
}
}

View File

@@ -1,45 +0,0 @@
<?php
/**
* Bill.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
/**
* Class Bill
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class Bill implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process(): array
{
// get bill id.
if (!is_null($this->data['bill']) && !is_null($this->data['bill']->id)) {
$this->data['bill-id'] = $this->data['bill']->id;
}
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
}

View File

@@ -1,49 +0,0 @@
<?php
/**
* Currency.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
use FireflyIII\Models\TransactionCurrency;
use Preferences;
/**
* Class Currency
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class Currency implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process(): array
{
// fix currency
if (is_null($this->data['currency'])) {
$currencyPreference = Preferences::get('currencyPreference', env('DEFAULT_CURRENCY', 'EUR'));
$this->data['currency'] = TransactionCurrency::whereCode($currencyPreference->data)->first();
}
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
}

View File

@@ -1,47 +0,0 @@
<?php
/**
* Description.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
/**
* Class Description
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class Description implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process(): array
{
$description = $this->data['description'] ?? '';
$this->data['description'] = trim($description);
if (strlen($this->data['description']) == 0) {
$this->data['description'] = trans('firefly.csv_empty_description');
}
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
}

View File

@@ -1,210 +0,0 @@
<?php
/**
* OpposingAccount.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
use Auth;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use Validator;
/**
* Class OpposingAccount
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class OpposingAccount implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process(): array
{
// three values:
// opposing-account-id, opposing-account-iban, opposing-account-name
$result = $this->checkIdNameObject();
if (!is_null($result)) {
return $result;
}
$result = $this->checkIbanString();
if (!is_null($result)) {
return $result;
}
$result = $this->checkNameString();
if (!is_null($result)) {
return $result;
}
return null;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
/**
* @return array|null
*/
protected function checkIbanString()
{
$rules = ['iban' => 'iban'];
$iban = $this->data['opposing-account-iban'];
$check = ['iban' => $iban];
$validator = Validator::make($check, $rules);
if (is_string($iban) && strlen($iban) > 0 && !$validator->fails()) {
$this->data['opposing-account-object'] = $this->parseIbanString();
return $this->data;
}
return null;
}
/**
* @return array
*/
protected function checkIdNameObject()
{
if ($this->data['opposing-account-id'] instanceof Account) { // first priority. try to find the account based on ID, if any
$this->data['opposing-account-object'] = $this->data['opposing-account-id'];
return $this->data;
}
if ($this->data['opposing-account-iban'] instanceof Account) { // second: try to find the account based on IBAN, if any.
$this->data['opposing-account-object'] = $this->data['opposing-account-iban'];
return $this->data;
}
return null;
}
/**
* @return array|null
*/
protected function checkNameString()
{
if ($this->data['opposing-account-name'] instanceof Account) { // third: try to find account based on name, if any.
$this->data['opposing-account-object'] = $this->data['opposing-account-name'];
return $this->data;
}
if (is_string($this->data['opposing-account-name'])) {
$this->data['opposing-account-object'] = $this->parseNameString();
return $this->data;
}
return null;
}
/**
* @return Account|null
*/
protected function createAccount()
{
$accountType = $this->getAccountType();
// create if not exists:
$name = is_string($this->data['opposing-account-name']) && strlen($this->data['opposing-account-name']) > 0 ? $this->data['opposing-account-name']
: $this->data['opposing-account-iban'];
$account = Account::firstOrCreateEncrypted( // See issue #180
[
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'name' => $name,
'iban' => $this->data['opposing-account-iban'],
'active' => true,
]
);
return $account;
}
/**
*
* @return AccountType
*/
protected function getAccountType()
{
// opposing account type:
if ($this->data['amount'] < 0) {
// create expense account:
return AccountType::where('type', 'Expense account')->first();
}
// create revenue account:
return AccountType::where('type', 'Revenue account')->first();
}
/**
* @return Account|null
*/
protected function parseIbanString()
{
// create by name and/or iban.
$accounts = Auth::user()->accounts()->get();
foreach ($accounts as $entry) {
if ($entry->iban == $this->data['opposing-account-iban']) {
return $entry;
}
}
$account = $this->createAccount();
return $account;
}
/**
* @return Account|null
*/
protected function parseNameString()
{
$accountType = $this->getAccountType();
$accounts = Auth::user()->accounts()->where('account_type_id', $accountType->id)->get();
foreach ($accounts as $entry) {
if ($entry->name == $this->data['opposing-account-name']) {
return $entry;
}
}
// create if not exists:
$account = Account::firstOrCreateEncrypted( // See issue #180
[
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'name' => $this->data['opposing-account-name'],
'iban' => '',
'active' => true,
]
);
return $account;
}
}

View File

@@ -1,31 +0,0 @@
<?php
/**
* PostProcessorInterface.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
/**
* Interface PostProcessorInterface
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
interface PostProcessorInterface
{
/**
* @return array
*/
public function process(): array;
/**
* @param array $data
*/
public function setData(array $data);
}

View File

@@ -1,60 +0,0 @@
<?php
/**
* Dummy.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Specifix;
/**
* Class Dummy
*
* @package FireflyIII\Helpers\Csv\Specifix
*/
class Dummy extends Specifix implements SpecifixInterface
{
/** @var array */
protected $data;
/** @var array */
protected $row;
/**
* Dummy constructor.
*/
public function __construct()
{
$this->setProcessorType(self::POST_PROCESSOR);
}
/**
* @return array
*/
public function fix(): array
{
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
/**
* @param array $row
*/
public function setRow(array $row)
{
$this->row = $row;
}
}

View File

@@ -1,76 +0,0 @@
<?php
/**
* RabobankDescription.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Specifix;
/**
* Class RabobankDescription
*
* @package FireflyIII\Helpers\Csv\Specifix
*/
class RabobankDescription extends Specifix implements SpecifixInterface
{
/** @var array */
protected $data;
/** @var array */
protected $row;
/**
* RabobankDescription constructor.
*/
public function __construct()
{
$this->setProcessorType(self::POST_PROCESSOR);
}
/**
* @return array
*/
public function fix(): array
{
$this->rabobankFixEmptyOpposing();
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
/**
* @param array $row
*/
public function setRow(array $row)
{
$this->row = $row;
}
/**
* Fixes Rabobank specific thing.
*/
protected function rabobankFixEmptyOpposing()
{
if (is_string($this->data['opposing-account-name']) && strlen($this->data['opposing-account-name']) == 0) {
$this->data['opposing-account-name'] = $this->row[10];
$this->data['description'] = trim(str_replace($this->row[10], '', $this->data['description']));
}
}
}

View File

@@ -1,46 +0,0 @@
<?php
/**
* Specifix.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Specifix;
/**
* Class Specifix
*
* @package FireflyIII\Helpers\Csv\Specifix
*/
class Specifix
{
/** @var int */
protected $processorType;
/**
* @return int
*/
public function getProcessorType(): int
{
return $this->processorType;
}
/**
* @param int $processorType
*
* @return $this
*/
public function setProcessorType(int $processorType)
{
$this->processorType = $processorType;
return $this;
}
}

View File

@@ -1,49 +0,0 @@
<?php
/**
* SpecifixInterface.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Specifix;
/**
* Interface SpecifixInterface
*
* @package FireflyIII\Helpers\Csv\Specifix
*/
interface SpecifixInterface
{
const PRE_PROCESSOR = 1;
const POST_PROCESSOR = 2;
/**
* Implement bank and locale related fixes.
*/
public function fix();
/**
* @return int
*/
public function getProcessorType(): int;
/**
* @param array $data
*/
public function setData(array $data);
/**
* @param int $processorType
*
* @return $this
*/
public function setProcessorType(int $processorType);
/**
* @param array $row
*/
public function setRow(array $row);
}

View File

@@ -1,202 +0,0 @@
<?php
/**
* Wizard.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv;
use Auth;
use Crypt;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Csv\Mapper\MapperInterface;
use League\Csv\Reader;
use Log;
use ReflectionException;
use Session;
use SplFileObject;
use Storage;
/**
* Class Wizard
*
* @package FireflyIII\Helpers\Csv
*/
class Wizard implements WizardInterface
{
/**
* @param Reader $reader
* @param array $map
* @param bool $hasHeaders
*
* @return array
*/
public function getMappableValues(Reader $reader, array $map, bool $hasHeaders): array
{
$values = [];
/*
* Loop over the CSV and collect mappable data:
*/
$keys = array_keys($map);
foreach ($reader as $index => $row) {
if ($this->useRow($hasHeaders, $index)) {
// collect all map values
foreach ($keys as $column) {
$values[$column][] = $row[$column];
}
}
}
/*
* Make each one unique.
*/
$values = $this->uniqueRecursive($values);
return $values;
}
/**
* @param array $roles
* @param array $map
*
* @return array
*/
public function processSelectedMapping(array $roles, array $map): array
{
$configRoles = config('csv.roles');
$maps = [];
$keys = array_keys($map);
foreach ($keys as $index) {
if (isset($roles[$index])) {
$name = $roles[$index];
if ($configRoles[$name]['mappable']) {
$maps[$index] = $name;
}
}
}
return $maps;
}
/**
* @param array $input
*
* @return array
*/
public function processSelectedRoles(array $input): array
{
$roles = [];
/*
* Store all rows for each column:
*/
if (is_array($input)) {
foreach ($input as $index => $role) {
if ($role != '_ignore') {
$roles[$index] = $role;
}
}
}
return $roles;
}
/**
* @param array $fields
*
* @return bool
*/
public function sessionHasValues(array $fields): bool
{
foreach ($fields as $field) {
if (!Session::has($field)) {
Log::error('Session is missing field: ' . $field);
return false;
}
}
return true;
}
/**
* @param array $map
*
* @return array
* @throws FireflyException
*/
public function showOptions(array $map): array
{
$options = [];
foreach ($map as $index => $columnRole) {
$mapper = config('csv.roles.' . $columnRole . '.mapper');
if (is_null($mapper)) {
throw new FireflyException('Cannot map field of type "' . $columnRole . '".');
}
$class = 'FireflyIII\Helpers\Csv\Mapper\\' . $mapper;
try {
/** @var MapperInterface $mapObject */
$mapObject = app($class);
} catch (ReflectionException $e) {
throw new FireflyException('Column "' . $columnRole . '" cannot be mapped because mapper class ' . $mapper . ' does not exist.');
}
$set = $mapObject->getMap();
$options[$index] = $set;
}
return $options;
}
/**
* @param string $path
*
* @return string
*/
public function storeCsvFile(string $path): string
{
$time = str_replace(' ', '-', microtime());
$fileName = 'csv-upload-' . Auth::user()->id . '-' . $time . '.csv.encrypted';
$disk = Storage::disk('upload');
$file = new SplFileObject($path, 'r');
$content = $file->fread($file->getSize());
$contentEncrypted = Crypt::encrypt($content);
$disk->put($fileName, $contentEncrypted);
return $fileName;
}
/**
* @param array $array
*
* @return array
*/
protected function uniqueRecursive(array $array)
{
foreach ($array as $column => $found) {
$array[$column] = array_unique($found);
}
return $array;
}
/**
* @param bool $hasHeaders
* @param int $index
*
* @return bool
*/
protected function useRow(bool $hasHeaders, int $index)
{
return ($hasHeaders && $index > 1) || !$hasHeaders;
}
}

View File

@@ -1,68 +0,0 @@
<?php
/**
* WizardInterface.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv;
use League\Csv\Reader;
/**
* Interface WizardInterface
*
* @package FireflyIII\Helpers\Csv
*/
interface WizardInterface
{
/**
* @param Reader $reader
* @param array $map
* @param bool $hasHeaders
*
* @return array
*/
public function getMappableValues(Reader $reader, array $map, bool $hasHeaders): array;
/**
* @param array $roles
* @param array $map
*
* @return array
*/
public function processSelectedMapping(array $roles, array $map): array;
/**
* @param array $input
*
* @return array
*/
public function processSelectedRoles(array $input): array;
/**
* @param array $fields
*
* @return bool
*/
public function sessionHasValues(array $fields): bool;
/**
* @param array $map
*
* @return array
*/
public function showOptions(array $map): array;
/**
* @param string $path
*
* @return string
*/
public function storeCsvFile(string $path): string;
}

View File

@@ -11,7 +11,6 @@ declare(strict_types = 1);
namespace FireflyIII\Helpers\Report;
use Auth;
use Carbon\Carbon;
use DB;
use FireflyIII\Helpers\Collection\Balance;
@@ -58,8 +57,7 @@ class BalanceReportHelper implements BalanceReportHelperInterface
*/
public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts): Balance
{
$balance = new Balance;
// build a balance header:
$balance = new Balance;
$header = new BalanceHeader;
$limitRepetitions = $this->budgetRepository->getAllBudgetLimitRepetitions($start, $end);
foreach ($accounts as $account) {
@@ -103,34 +101,34 @@ class BalanceReportHelper implements BalanceReportHelperInterface
private function allCoveredByBalancingActs(Collection $accounts, Carbon $start, Carbon $end): Collection
{
$ids = $accounts->pluck('id')->toArray();
$set = Auth::user()->tags()
->leftJoin('tag_transaction_journal', 'tag_transaction_journal.tag_id', '=', 'tags.id')
->leftJoin('transaction_journals', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->leftJoin(
'transactions AS t_source', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 't_source.transaction_journal_id')->where('t_source.amount', '<', 0);
}
)
->leftJoin(
'transactions AS t_destination', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 't_destination.transaction_journal_id')->where('t_destination.amount', '>', 0);
}
)
->where('tags.tagMode', 'balancingAct')
->where('transaction_types.type', TransactionType::TRANSFER)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->whereNull('transaction_journals.deleted_at')
->whereIn('t_source.account_id', $ids)
->whereIn('t_destination.account_id', $ids)
->groupBy('t_destination.account_id')
->get(
[
't_destination.account_id',
DB::raw('SUM(`t_destination`.`amount`) as `sum`'),
]
);
$set = auth()->user()->tags()
->leftJoin('tag_transaction_journal', 'tag_transaction_journal.tag_id', '=', 'tags.id')
->leftJoin('transaction_journals', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->leftJoin(
'transactions AS t_source', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 't_source.transaction_journal_id')->where('t_source.amount', '<', 0);
}
)
->leftJoin(
'transactions AS t_destination', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 't_destination.transaction_journal_id')->where('t_destination.amount', '>', 0);
}
)
->where('tags.tagMode', 'balancingAct')
->where('transaction_types.type', TransactionType::TRANSFER)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->whereNull('transaction_journals.deleted_at')
->whereIn('t_source.account_id', $ids)
->whereIn('t_destination.account_id', $ids)
->groupBy('t_destination.account_id')
->get(
[
't_destination.account_id',
DB::raw('SUM(`t_destination`.`amount`) as `sum`'),
]
);
return $set;
}
@@ -262,6 +260,7 @@ class BalanceReportHelper implements BalanceReportHelperInterface
/**
* @param Balance $balance
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly 5.
*
* @return Balance
*/

View File

@@ -18,6 +18,7 @@ use FireflyIII\Helpers\Collection\BudgetLine;
use FireflyIII\Models\Budget;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;
/**
@@ -40,6 +41,60 @@ class BudgetReportHelper implements BudgetReportHelperInterface
$this->repository = $repository;
}
/**
* @SuppressWarnings(PHPMD.ExcessiveMethodLength) // at 43, its ok.
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly 5.
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Collection
*/
public function budgetYearOverview(Carbon $start, Carbon $end, Collection $accounts): Collection
{
// chart properties for cache:
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('budget-year');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
return $cache->get();
}
$current = clone $start;
$return = new Collection;
$set = $this->repository->getBudgets();
$budgets = [];
$spent = [];
$headers = $this->createYearHeaders($current, $end);
/** @var Budget $budget */
foreach ($set as $budget) {
$id = $budget->id;
$budgets[$id] = $budget->name;
$current = clone $start;
$budgetData = $this->getBudgetSpentData($current, $end, $budget, $accounts);
$sum = $budgetData['sum'];
$spent[$id] = $budgetData['spent'];
if (bccomp('0', $sum) === 0) {
// not spent anything.
unset($spent[$id]);
unset($budgets[$id]);
}
}
$return->put('headers', $headers);
$return->put('budgets', $budgets);
$return->put('spent', $spent);
$cache->store($return);
return $return;
}
/**
* @param Carbon $start
* @param Carbon $end
@@ -63,10 +118,8 @@ class BudgetReportHelper implements BudgetReportHelperInterface
if ($spent > 0) {
$budgetLine = new BudgetLine;
$budgetLine->setBudget($budget);
$budgetLine->setOverspent($spent);
$object->addOverspent($spent);
$object->addBudgetLine($budgetLine);
$budgetLine->setBudget($budget)->setOverspent($spent);
$object->addOverspent($spent)->addBudgetLine($budgetLine);
}
continue;
}
@@ -76,18 +129,12 @@ class BudgetReportHelper implements BudgetReportHelperInterface
$data = $this->calculateExpenses($budget, $repetition, $accounts);
$budgetLine = new BudgetLine;
$budgetLine->setBudget($budget);
$budgetLine->setRepetition($repetition);
$budgetLine->setLeft($data['left']);
$budgetLine->setSpent($data['expenses']);
$budgetLine->setOverspent($data['overspent']);
$budgetLine->setBudgeted($repetition->amount);
$budgetLine->setBudget($budget)->setRepetition($repetition)
->setLeft($data['left'])->setSpent($data['expenses'])->setOverspent($data['overspent'])
->setBudgeted(strval($repetition->amount));
$object->addBudgeted($repetition->amount);
$object->addSpent($data['spent']);
$object->addLeft($data['left']);
$object->addOverspent($data['overspent']);
$object->addBudgetLine($budgetLine);
$object->addBudgeted(strval($repetition->amount))->addSpent($data['spent'])
->addLeft($data['left'])->addOverspent($data['overspent'])->addBudgetLine($budgetLine);
}
@@ -97,10 +144,8 @@ class BudgetReportHelper implements BudgetReportHelperInterface
$noBudget = $this->repository->spentInPeriodWithoutBudget($accounts, $start, $end);
$budgetLine = new BudgetLine;
$budgetLine->setOverspent($noBudget);
$budgetLine->setSpent($noBudget);
$object->addOverspent($noBudget);
$object->addBudgetLine($budgetLine);
$budgetLine->setOverspent($noBudget)->setSpent($noBudget);
$object->addOverspent($noBudget)->addBudgetLine($budgetLine);
return $object;
}
@@ -181,4 +226,50 @@ class BudgetReportHelper implements BudgetReportHelperInterface
return $array;
}
/**
* @param Carbon $current
* @param Carbon $end
*
* @return array
*/
private function createYearHeaders(Carbon $current, Carbon $end): array
{
$headers = [];
while ($current < $end) {
$short = $current->format('m-Y');
$headers[$short] = $current->formatLocalized((string)trans('config.month'));
$current->addMonth();
}
return $headers;
}
/**
* @param Carbon $current
* @param Carbon $end
* @param Budget $budget
* @param Collection $accounts
*
* @return array
*/
private function getBudgetSpentData(Carbon $current, Carbon $end, Budget $budget, Collection $accounts): array
{
$sum = '0';
$spent = [];
while ($current < $end) {
$currentEnd = clone $current;
$currentEnd->endOfMonth();
$format = $current->format('m-Y');
$budgetSpent = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $current, $currentEnd);
$spent[$format] = $budgetSpent;
$sum = bcadd($sum, $budgetSpent);
$current->addMonth();
}
return [
'spent' => $spent,
'sum' => $sum,
];
}
}

View File

@@ -23,6 +23,15 @@ use Illuminate\Support\Collection;
*/
interface BudgetReportHelperInterface
{
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Collection
*/
public function budgetYearOverview(Carbon $start, Carbon $end, Collection $accounts): Collection;
/**
* @param Carbon $start
* @param Carbon $end

View File

@@ -82,8 +82,8 @@ class ReportHelper implements ReportHelperInterface
$billLine = new BillLine;
$billLine->setBill($bill);
$billLine->setActive(intval($bill->active) === 1);
$billLine->setMin($bill->amount_min);
$billLine->setMax($bill->amount_max);
$billLine->setMin(strval($bill->amount_min));
$billLine->setMax(strval($bill->amount_max));
$billLine->setHit(false);
// is hit in period?

View File

@@ -11,7 +11,6 @@ declare(strict_types = 1);
namespace FireflyIII\Http\Controllers;
use Auth;
use Carbon\Carbon;
use ExpandedForm;
use FireflyIII\Crud\Account\AccountCrudInterface;
@@ -50,7 +49,7 @@ class AccountController extends Controller
/**
* @param string $what
*
* @return \Illuminate\View\View
* @return View
*/
public function create(string $what = 'asset')
{
@@ -116,7 +115,7 @@ class AccountController extends Controller
* @param ARI $repository
* @param Account $account
*
* @return \Illuminate\View\View
* @return View
*/
public function edit(ARI $repository, Account $account)
{
@@ -172,8 +171,10 @@ class AccountController extends Controller
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
$types = config('firefly.accountTypesByIdentifier.' . $what);
$accounts = $crud->getAccountsByType($types);
$start = clone session('start', Carbon::now()->startOfMonth());
$end = clone session('end', Carbon::now()->endOfMonth());
/** @var Carbon $start */
$start = clone session('start', Carbon::now()->startOfMonth());
/** @var Carbon $end */
$end = clone session('end', Carbon::now()->endOfMonth());
$start->subDay();
$ids = $accounts->pluck('id')->toArray();
@@ -196,7 +197,7 @@ class AccountController extends Controller
* @param ARI $repository
* @param Account $account
*
* @return \Illuminate\View\View
* @return View
*/
public function show(ARI $repository, Account $account)
{
@@ -204,15 +205,17 @@ class AccountController extends Controller
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
$subTitle = $account->name;
$range = Preferences::get('viewRange', '1M')->data;
$start = session('start', Navigation::startOfPeriod(new Carbon, $range));
$end = session('end', Navigation::endOfPeriod(new Carbon, $range));
$page = intval(Input::get('page'));
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$offset = ($page - 1) * $pageSize;
$set = $repository->journalsInPeriod(new Collection([$account]), [], $start, $end);
$count = $set->count();
$subSet = $set->splice($offset, $pageSize);
$journals = new LengthAwarePaginator($subSet, $count, $pageSize, $page);
/** @var Carbon $start */
$start = session('start', Navigation::startOfPeriod(new Carbon, $range));
/** @var Carbon $end */
$end = session('end', Navigation::endOfPeriod(new Carbon, $range));
$page = intval(Input::get('page'));
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$offset = ($page - 1) * $pageSize;
$set = $repository->journalsInPeriod(new Collection([$account]), [], $start, $end);
$count = $set->count();
$subSet = $set->splice($offset, $pageSize);
$journals = new LengthAwarePaginator($subSet, $count, $pageSize, $page);
$journals->setPath('accounts/show/' . $account->id);
// grouped other months thing:
@@ -251,6 +254,7 @@ class AccountController extends Controller
$end = Navigation::subtractPeriod($end, $range, 1);
}
$cache->store($entries);
return view('accounts.show', compact('account', 'what', 'entries', 'subTitleIcon', 'journals', 'subTitle'));
}
@@ -270,6 +274,7 @@ class AccountController extends Controller
$end = Navigation::endOfPeriod($carbon, $range);
$subTitle = $account->name . ' (' . Navigation::periodShow($start, $range) . ')';
$page = intval(Input::get('page'));
$page = $page === 0 ? 1 : $page;
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$offset = ($page - 1) * $pageSize;
$set = $repository->journalsInPeriod(new Collection([$account]), [], $start, $end);
@@ -285,7 +290,7 @@ class AccountController extends Controller
* @param AccountFormRequest $request
* @param AccountCrudInterface $crud
*
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function store(AccountFormRequest $request, AccountCrudInterface $crud)
{
@@ -295,7 +300,7 @@ class AccountController extends Controller
'virtualBalance' => round($request->input('virtualBalance'), 2),
'virtualBalanceCurrency' => intval($request->input('amount_currency_id_virtualBalance')),
'active' => true,
'user' => Auth::user()->id,
'user' => auth()->user()->id,
'iban' => $request->input('iban'),
'accountNumber' => $request->input('accountNumber'),
'accountRole' => $request->input('accountRole'),
@@ -333,7 +338,7 @@ class AccountController extends Controller
* @param AccountCrudInterface $crud
* @param Account $account
*
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function update(AccountFormRequest $request, AccountCrudInterface $crud, Account $account)
{
@@ -341,7 +346,7 @@ class AccountController extends Controller
$accountData = [
'name' => $request->input('name'),
'active' => $request->input('active'),
'user' => Auth::user()->id,
'user' => auth()->user()->id,
'iban' => $request->input('iban'),
'accountNumber' => $request->input('accountNumber'),
'accountRole' => $request->input('accountRole'),

View File

@@ -0,0 +1,77 @@
<?php
/**
* ConfigurationController.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Http\Controllers\Admin;
use Config;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\ConfigurationRequest;
use FireflyIII\Support\Facades\FireflyConfig;
use Preferences;
use Redirect;
use Session;
use View;
/**
* Class ConfigurationController
*
* @package FireflyIII\Http\Controllers\Admin
*/
class ConfigurationController extends Controller
{
/**
* ConfigurationController constructor.
*/
public function __construct()
{
parent::__construct();
View::share('title', strval(trans('firefly.administration')));
View::share('mainTitleIcon', 'fa-hand-spock-o');
}
/**
* @return View
*/
public function index()
{
$subTitle = strval(trans('firefly.instance_configuration'));
$subTitleIcon = 'fa-wrench';
// all available configuration and their default value in case
// they don't exist yet.
$singleUserMode = FireflyConfig::get('single_user_mode', Config::get('firefly.configuration.single_user_mode'))->data;
return view('admin.configuration.index', compact('subTitle', 'subTitleIcon', 'singleUserMode'));
}
/**
* @param ConfigurationRequest $request
*/
public function store(ConfigurationRequest $request)
{
// get config values:
$singleUserMode = intval($request->get('single_user_mode')) === 1 ? true : false;
// store config values
FireflyConfig::set('single_user_mode', $singleUserMode);
// flash message
Session::flash('success', strval(trans('firefly.configuration_updated')));
Preferences::mark();
return Redirect::route('admin.configuration.index');
}
}

View File

@@ -0,0 +1,136 @@
<?php
/**
* DomainController.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Http\Controllers\Admin;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\User;
use Illuminate\Http\Request;
use Session;
/**
* Class DomainController
*
* @package FireflyIII\Http\Controllers\Admin
*/
class DomainController extends Controller
{
/**
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function domains()
{
$title = strval(trans('firefly.administration'));
$mainTitleIcon = 'fa-hand-spock-o';
$subTitle = strval(trans('firefly.blocked_domains'));
$subTitleIcon = 'fa-exclamation-circle';
$domains = FireflyConfig::get('blocked-domains', [])->data;
// known domains
$knownDomains = $this->getKnownDomains();
return view('admin.domains.index', compact('title', 'mainTitleIcon', 'knownDomains', 'subTitle', 'subTitleIcon', 'domains'));
}
/**
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function manual(Request $request)
{
if (strlen($request->get('domain')) === 0) {
Session::flash('error', trans('firefly.no_domain_filled_in'));
return redirect(route('admin.users.domains'));
}
$domain = strtolower($request->get('domain'));
$blocked = FireflyConfig::get('blocked-domains', [])->data;
if (in_array($domain, $blocked)) {
Session::flash('error', trans('firefly.domain_already_blocked', ['domain' => $domain]));
return redirect(route('admin.users.domains'));
}
$blocked[] = $domain;
FireflyConfig::set('blocked-domains', $blocked);
Session::flash('success', trans('firefly.domain_is_now_blocked', ['domain' => $domain]));
return redirect(route('admin.users.domains'));
}
/**
* @param string $domain
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function toggleDomain(string $domain)
{
$blocked = FireflyConfig::get('blocked-domains', [])->data;
if (in_array($domain, $blocked)) {
$key = array_search($domain, $blocked);
unset($blocked[$key]);
sort($blocked);
FireflyConfig::set('blocked-domains', $blocked);
Session::flash('message', trans('firefly.domain_now_unblocked', ['domain' => $domain]));
return redirect(route('admin.users.domains'));
}
$blocked[] = $domain;
FireflyConfig::set('blocked-domains', $blocked);
Session::flash('message', trans('firefly.domain_now_blocked', ['domain' => $domain]));
return redirect(route('admin.users.domains'));
}
/**
* @return array
*/
private function getKnownDomains(): array
{
$users = User::get();
$set = [];
$filtered = [];
/** @var User $user */
foreach ($users as $user) {
$email = $user->email;
$parts = explode('@', $email);
$domain = $parts[1];
$set[] = $domain;
}
$set = array_unique($set);
// filter for already banned domains:
$blocked = FireflyConfig::get('blocked-domains', [])->data;
foreach ($set as $domain) {
// in the block array? ignore it.
if (!in_array($domain, $blocked)) {
$filtered[] = $domain;
}
}
asort($filtered);
return $filtered;
}
}

View File

@@ -24,8 +24,23 @@ use Preferences;
*/
class UserController extends Controller
{
/**
* @param User $user
*
* @return int
*/
public function edit(User $user)
{
return $user->id;
}
/**
* @param UserRepositoryInterface $repository
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function index(UserRepositoryInterface $repository)
{
@@ -61,4 +76,5 @@ class UserController extends Controller
}
}

View File

@@ -18,6 +18,7 @@ use FireflyIII\Http\Requests\AttachmentFormRequest;
use FireflyIII\Models\Attachment;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use Input;
use Log;
use Preferences;
use Response;
use Session;
@@ -46,7 +47,7 @@ class AttachmentController extends Controller
/**
* @param Attachment $attachment
*
* @return \Illuminate\View\View
* @return View
*/
public function delete(Attachment $attachment)
{
@@ -92,10 +93,12 @@ class AttachmentController extends Controller
if ($disk->exists($file)) {
$quoted = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\'));
$quoted = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\'));
$content = Crypt::decrypt($disk->get($file));
Log::debug('Send file to user', ['file' => $quoted, 'size' => strlen($content)]);
return response(Crypt::decrypt($disk->get($file)), 200)
return response($content, 200)
->header('Content-Description', 'File Transfer')
->header('Content-Type', 'application/octet-stream')
->header('Content-Disposition', 'attachment; filename=' . $quoted)
@@ -104,7 +107,7 @@ class AttachmentController extends Controller
->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', $disk->size($file));
->header('Content-Length', strlen($content));
}
throw new FireflyException('Could not find the indicated attachment. The file is no longer there.');
@@ -113,7 +116,7 @@ class AttachmentController extends Controller
/**
* @param Attachment $attachment
*
* @return \Illuminate\View\View
* @return View
*/
public function edit(Attachment $attachment)
{

View File

@@ -11,20 +11,10 @@ declare(strict_types = 1);
namespace FireflyIII\Http\Controllers\Auth;
use Auth;
use FireflyIII\Events\UserRegistration;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\User;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Http\Request;
use Illuminate\Mail\Message;
use Illuminate\Support\Facades\Lang;
use Log;
use Mail;
use Session;
use Swift_TransportException;
use Validator;
@@ -54,106 +44,6 @@ class AuthController extends Controller
parent::__construct();
}
/**
* Handle a login request to the application.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
*/
public function login(Request $request)
{
$this->validate($request, [$this->loginUsername() => 'required', 'password' => 'required',]);
$throttles = $this->isUsingThrottlesLoginsTrait();
if ($throttles && $this->hasTooManyLoginAttempts($request)) {
return $this->sendLockoutResponse($request);
}
$credentials = $this->getCredentials($request);
$credentials['blocked'] = 0; // most not be blocked.
if (Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'))) {
return $this->handleUserWasAuthenticated($request, $throttles);
}
// check if user is blocked:
$errorMessage = '';
/** @var User $foundUser */
$foundUser = User::where('email', $credentials['email'])->where('blocked', 1)->first();
if (!is_null($foundUser)) {
// if it exists, show message:
$code = strlen(strval($foundUser->blocked_code)) > 0 ? $foundUser->blocked_code : 'general_blocked';
$errorMessage = strval(trans('firefly.' . $code . '_error', ['email' => $credentials['email']]));
$this->reportBlockedUserLoginAttempt($foundUser, $code, $request->ip());
}
if ($throttles) {
$this->incrementLoginAttempts($request);
}
return $this->sendFailedLoginResponse($request, $errorMessage);
}
/**
* Handle a registration request for the application.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
* @throws FireflyException
* @throws \Illuminate\Foundation\Validation\ValidationException
*/
public function register(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
$data = $request->all();
$data['password'] = bcrypt($data['password']);
// is user email domain blocked?
if ($this->isBlockedDomain($data['email'])) {
$validator->getMessageBag()->add('email', (string)trans('validation.invalid_domain'));
$this->reportBlockedDomainRegistrationAttempt($data['email'], $request->ip());
$this->throwValidationException(
$request, $validator
);
}
$user = $this->create($request->all());
// trigger user registration event:
event(new UserRegistration($user, $request->ip()));
Auth::login($user);
Session::flash('success', strval(trans('firefly.registered')));
Session::flash('gaEventCategory', 'user');
Session::flash('gaEventAction', 'new-registration');
return redirect($this->redirectPath());
}
/**
* Show the application registration form.
*
* @return \Illuminate\Http\Response
*/
public function showRegistrationForm()
{
$showDemoWarning = env('SHOW_DEMO_WARNING', false);
return view('auth.register', compact('showDemoWarning'));
}
/**
* Create a new user instance after a valid registration.
@@ -172,76 +62,6 @@ class AuthController extends Controller
);
}
/**
* @return array
*/
protected function getBlockedDomains()
{
$set = explode(',', env('BLOCKED_DOMAINS', ''));
$domains = [];
foreach ($set as $entry) {
$domain = trim($entry);
if (strlen($domain) > 0) {
$domains[] = $domain;
}
}
return $domains;
}
/**
* Get the failed login message.
*
* @param string $message
*
* @return string
*/
protected function getFailedLoginMessage(string $message)
{
if (strlen($message) > 0) {
return $message;
}
return Lang::has('auth.failed')
? Lang::get('auth.failed')
: 'These credentials do not match our records.';
}
/**
* @param string $email
*
* @return bool
*/
protected function isBlockedDomain(string $email)
{
$parts = explode('@', $email);
$blocked = $this->getBlockedDomains();
if (isset($parts[1]) && in_array($parts[1], $blocked)) {
return true;
}
return false;
}
/**
* Get the failed login response instance.
*
* @param \Illuminate\Http\Request $request
* @param string $message
*
* @return \Illuminate\Http\Response
*/
protected function sendFailedLoginResponse(Request $request, string $message)
{
return redirect()->back()
->withInput($request->only($this->loginUsername(), 'remember'))
->withErrors(
[
$this->loginUsername() => $this->getFailedLoginMessage($message),
]
);
}
/**
* Get a validator for an incoming registration request.
@@ -260,61 +80,5 @@ class AuthController extends Controller
);
}
/**
* Send a message home about a blocked domain and the address attempted to register.
*
* @param string $registrationMail
* @param string $ipAddress
*/
private function reportBlockedDomainRegistrationAttempt(string $registrationMail, string $ipAddress)
{
try {
$email = env('SITE_OWNER', false);
$parts = explode('@', $registrationMail);
$domain = $parts[1];
$fields = [
'email_address' => $registrationMail,
'blocked_domain' => $domain,
'ip' => $ipAddress,
];
Mail::send(
['emails.blocked-registration-html', 'emails.blocked-registration'], $fields, function (Message $message) use ($email, $domain) {
$message->to($email, $email)->subject('Blocked a registration attempt with domain ' . $domain . '.');
}
);
} catch (Swift_TransportException $e) {
Log::error($e->getMessage());
}
}
/**
* Send a message home about the blocked attempt to login.
* Perhaps in a later stage, simply log these messages.
*
* @param User $user
* @param string $code
* @param string $ipAddress
*/
private function reportBlockedUserLoginAttempt(User $user, string $code, string $ipAddress)
{
try {
$email = env('SITE_OWNER', false);
$fields = [
'user_id' => $user->id,
'user_address' => $user->email,
'code' => $code,
'ip' => $ipAddress,
];
Mail::send(
['emails.blocked-login-html', 'emails.blocked-login'], $fields, function (Message $message) use ($email, $user) {
$message->to($email, $email)->subject('Blocked a login attempt from ' . trim($user->email) . '.');
}
);
} catch (Swift_TransportException $e) {
Log::error($e->getMessage());
}
}
}

View File

@@ -11,8 +11,8 @@ declare(strict_types = 1);
namespace FireflyIII\Http\Controllers\Auth;
use Auth;
use FireflyIII\Events\ResendConfirmation;
use FireflyIII\Events\UserIsConfirmed;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use Illuminate\Http\Request;
@@ -36,12 +36,13 @@ class ConfirmationController extends Controller
}
/**
* @param string $code
* @param Request $request
* @param string $code
*
* @return mixed
* @throws FireflyException
*/
public function doConfirmation(string $code)
public function doConfirmation(Request $request, string $code)
{
// check user_confirmed_last_mail
@@ -51,8 +52,12 @@ class ConfirmationController extends Controller
$maxDiff = config('firefly.confirmation_age');
if ($database === $code && ($now - $time <= $maxDiff)) {
Preferences::setForUser(Auth::user(), 'user_confirmed', true);
Preferences::setForUser(Auth::user(), 'user_confirmed_confirmed', time());
// trigger user registration event:
event(new UserIsConfirmed(auth()->user(), $request->ip()));
Preferences::setForUser(auth()->user(), 'user_confirmed', true);
Preferences::setForUser(auth()->user(), 'user_confirmed_confirmed', time());
Session::flash('success', strval(trans('firefly.account_is_confirmed')));
return redirect(route('home'));
@@ -62,6 +67,8 @@ class ConfirmationController extends Controller
/**
* @param Request $request
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function resendConfirmation(Request $request)
{
@@ -71,7 +78,7 @@ class ConfirmationController extends Controller
$owner = env('SITE_OWNER', 'mail@example.com');
$view = 'auth.confirmation.no-resent';
if ($now - $time > $maxDiff) {
event(new ResendConfirmation(Auth::user(), $request->ip()));
event(new ResendConfirmation(auth()->user(), $request->ip()));
$view = 'auth.confirmation.resent';
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* ForgotPasswordController.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Http\Controllers\Auth;
use FireflyIII\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
/**
* Class ForgotPasswordController
*
* @package FireflyIII\Http\Controllers\Auth
*/
class ForgotPasswordController extends Controller
{
use SendsPasswordResetEmails;
/**
* Create a new controller instance.
*
*/
public function __construct()
{
parent::__construct();
$this->middleware('guest');
}
}

View File

@@ -0,0 +1,195 @@
<?php
/**
* LoginController.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Http\Controllers\Auth;
use Config;
use FireflyConfig;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\User;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Mail\Message;
use Lang;
use Log;
use Mail;
use Swift_TransportException;
/**
* Class LoginController
*
* @package FireflyIII\Http\Controllers\Auth
*/
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login / registration.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
*/
public function __construct()
{
parent::__construct();
$this->middleware('guest', ['except' => 'logout']);
}
/**
* Handle a login request to the application.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
*/
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($lockedOut = $this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$credentials = $this->credentials($request);
$credentials['blocked'] = 0; // most not be blocked.
if ($this->guard()->attempt($credentials, $request->has('remember'))) {
return $this->sendLoginResponse($request);
}
// check if user is blocked:
$errorMessage = '';
/** @var User $foundUser */
$foundUser = User::where('email', $credentials['email'])->where('blocked', 1)->first();
if (!is_null($foundUser)) {
// if it exists, show message:
$code = strlen(strval($foundUser->blocked_code)) > 0 ? $foundUser->blocked_code : 'general_blocked';
$errorMessage = strval(trans('firefly.' . $code . '_error', ['email' => $credentials['email']]));
$this->reportBlockedUserLoginAttempt($foundUser, $code, $request->ip());
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
if (!$lockedOut) {
$this->incrementLoginAttempts($request);
}
return $this->sendFailedLoginResponse($request, $errorMessage);
}
/**
* Show the application login form.
*
* @return \Illuminate\Http\Response
*/
public function showLoginForm(Request $request)
{
// is allowed to?
$singleUserMode = FireflyConfig::get('single_user_mode', Config::get('firefly.configuration.single_user_mode'))->data;
$userCount = User::count();
$allowRegistration = true;
if ($singleUserMode === true && $userCount > 0) {
$allowRegistration = false;
}
$email = $request->old('email');
$remember = $request->old('remember');
return view('auth.login', compact('allowRegistration', 'email', 'remember'));
}
/**
* Get the failed login message.
*
* @param string $message
*
* @return string
*/
protected function getFailedLoginMessage(string $message)
{
if (strlen($message) > 0) {
return $message;
}
return Lang::has('auth.failed') ? Lang::get('auth.failed') : 'These credentials do not match our records.';
}
/**
* Get the failed login response instance.
*
* @param \Illuminate\Http\Request $request
* @param string $message
*
* @return \Illuminate\Http\RedirectResponse
*/
protected function sendFailedLoginResponse(Request $request, string $message)
{
return redirect()->back()
->withInput($request->only($this->username(), 'remember'))
->withErrors(
[
$this->username() => $this->getFailedLoginMessage($message),
]
);
}
/**
* Send a message home about the blocked attempt to login.
* Perhaps in a later stage, simply log these messages.
*
* @param User $user
* @param string $code
* @param string $ipAddress
*/
private function reportBlockedUserLoginAttempt(User $user, string $code, string $ipAddress)
{
try {
$email = env('SITE_OWNER', false);
$fields = [
'user_id' => $user->id,
'user_address' => $user->email,
'code' => $code,
'ip' => $ipAddress,
];
Mail::send(
['emails.blocked-login-html', 'emails.blocked-login'], $fields, function (Message $message) use ($email, $user) {
$message->to($email, $email)->subject('Blocked a login attempt from ' . trim($user->email) . '.');
}
);
} catch (Swift_TransportException $e) {
Log::error($e->getMessage());
}
}
}

View File

@@ -23,6 +23,7 @@ use Illuminate\Support\Facades\Password;
* Class PasswordController
*
* @package FireflyIII\Http\Controllers\Auth
* @method getEmailSubject
*/
class PasswordController extends Controller
{
@@ -55,7 +56,7 @@ class PasswordController extends Controller
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
* @return \Symfony\Component\HttpFoundation\Response
*/
public function sendResetLinkEmail(Request $request)
{

View File

@@ -0,0 +1,224 @@
<?php
/**
* RegisterController.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Http\Controllers\Auth;
use Auth;
use Config;
use FireflyIII\Events\UserRegistration;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\Request;
use Illuminate\Mail\Message;
use Log;
use Mail;
use Session;
use Swift_TransportException;
use Validator;
/**
* Class RegisterController
*
* @package FireflyIII\Http\Controllers\Auth
*/
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after login / registration.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*/
public function __construct()
{
parent::__construct();
$this->middleware('guest');
}
/**
* @param Request $request
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
*/
public function register(Request $request)
{
// is allowed to?
$singleUserMode = FireflyConfig::get('single_user_mode', Config::get('firefly.configuration.single_user_mode'))->data;
$userCount = User::count();
if ($singleUserMode === true && $userCount > 0) {
$message = 'Registration is currently not available.';
return view('error', compact('message'));
}
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException($request, $validator);
}
$data = $request->all();
$data['password'] = bcrypt($data['password']);
// is user email domain blocked?
if ($this->isBlockedDomain($data['email'])) {
$validator->getMessageBag()->add('email', (string)trans('validation.invalid_domain'));
$this->reportBlockedDomainRegistrationAttempt($data['email'], $request->ip());
$this->throwValidationException($request, $validator);
}
$user = $this->create($request->all());
// trigger user registration event:
event(new UserRegistration($user, $request->ip()));
Auth::login($user);
Session::flash('success', strval(trans('firefly.registered')));
Session::flash('gaEventCategory', 'user');
Session::flash('gaEventAction', 'new-registration');
return redirect($this->redirectPath());
}
/**
* OLD
* Show the application registration form.
*
* @return \Illuminate\Http\Response
*/
public function showRegistrationForm(Request $request)
{
$showDemoWarning = config('firefly.show-demo-warning', false);
// is allowed to?
$singleUserMode = FireflyConfig::get('single_user_mode', Config::get('firefly.configuration.single_user_mode'))->data;
$userCount = User::count();
if ($singleUserMode === true && $userCount > 0) {
$message = 'Registration is currently not available.';
return view('error', compact('message'));
}
$email = $request->old('email');
return view('auth.register', compact('showDemoWarning', 'email'));
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
*
* @return User
*/
protected function create(array $data)
{
return User::create(
[
'email' => $data['email'],
'password' => bcrypt($data['password']),
]
);
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
*
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make(
$data, [
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
]
);
}
/**
* @return array
*/
private function getBlockedDomains()
{
return FireflyConfig::get('blocked-domains', [])->data;
}
/**
* @param string $email
*
* @return bool
*/
private function isBlockedDomain(string $email)
{
$parts = explode('@', $email);
$blocked = $this->getBlockedDomains();
if (isset($parts[1]) && in_array($parts[1], $blocked)) {
return true;
}
return false;
}
/**
* Send a message home about a blocked domain and the address attempted to register.
*
* @param string $registrationMail
* @param string $ipAddress
*/
private function reportBlockedDomainRegistrationAttempt(string $registrationMail, string $ipAddress)
{
try {
$email = env('SITE_OWNER', false);
$parts = explode('@', $registrationMail);
$domain = $parts[1];
$fields = [
'email_address' => $registrationMail,
'blocked_domain' => $domain,
'ip' => $ipAddress,
];
Mail::send(
['emails.blocked-registration-html', 'emails.blocked-registration'], $fields, function (Message $message) use ($email, $domain) {
$message->to($email, $email)->subject('Blocked a registration attempt with domain ' . $domain . '.');
}
);
} catch (Swift_TransportException $e) {
Log::error($e->getMessage());
}
}
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* ResetPasswordController.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Http\Controllers\Auth;
use FireflyIII\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
/**
* Class ResetPasswordController
*
* @package FireflyIII\Http\Controllers\Auth
*/
class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Create a new controller instance.
*
*/
public function __construct()
{
$this->middleware('guest');
}
}

Some files were not shown because too many files have changed in this diff Show More