Compare commits

...

338 Commits

Author SHA1 Message Date
James Cole
bc4ac303e2 Merge branch 'release/4.7.6.2' 2018-09-04 19:49:45 +02:00
James Cole
0e9fbecbe4 Forgot the credit card type [skip ci] 2018-09-04 19:32:50 +02:00
James Cole
226b3cfdd8 Update meta files and language files for new release. 2018-09-04 19:07:02 +02:00
James Cole
d43fa3790d Update tests so repositories are not called. Saves on DB calls, speeds up tests. 2018-09-04 16:47:01 +02:00
James Cole
ca04113aa7 Less logging for tests means less strain on travis et al. 2018-09-04 09:52:51 +02:00
James Cole
817c157db4 Disable languages that drop under 75% coverage. 2018-09-04 09:52:35 +02:00
James Cole
07edbe758a Update tests so repositories are not called. Saves on DB calls, speeds up tests. 2018-09-04 09:52:19 +02:00
James Cole
46ba0a5a5a Mock more repositories in tests. 2018-09-03 18:52:46 +02:00
James Cole
480b636c7e Fix Docker build 2018-09-03 14:51:15 +02:00
James Cole
20340dff7b Fix CSS of OAuth authorise view. 2018-09-03 14:50:57 +02:00
James Cole
cfbabb500f Merge tag '4.7.6.1' into develop
4.7.6.1
2018-09-03 10:26:38 +02:00
James Cole
a4cb2c1cb1 Merge branch 'release/4.7.6.1' 2018-09-03 10:26:36 +02:00
James Cole
bd31b7e943 Update language files [skip ci] 2018-09-03 10:20:51 +02:00
James Cole
b2e7c767df Update meta files to 4.7.6.1 [skip ci] 2018-09-03 10:10:58 +02:00
James Cole
bb9f763729 Repositories will now warn if used in test environment. 2018-09-03 08:41:03 +02:00
James Cole
fb61229bf3 Update the .env files and the Dockerfile. 2018-09-03 08:40:22 +02:00
James Cole
fc30d41ee5 Refer to correct issue [skip ci] 2018-09-03 07:59:32 +02:00
James Cole
7666147f3c Merge pull request #1649 from hamuz/patch-1
2FA QR doesn't show up due to CSP error
2018-09-03 07:57:19 +02:00
HamuZ HamuZ
52f8b24041 2FA QR doesn't show up due to CSP error
Relevant stackoverflow fix:
https://stackoverflow.com/questions/18447970/content-security-policy-data-not-working-for-base64-images-in-chrome-28
2018-09-03 08:19:38 +03:00
James Cole
eaf2667abb Fix test method names. 2018-09-02 20:27:26 +02:00
James Cole
de754ca4e0 Improve test coverage. 2018-09-02 20:13:25 +02:00
James Cole
96dd89fbeb Merge tag '4.7.6' into develop
4.7.6
2018-09-01 21:30:46 +02:00
James Cole
bae40e2cbc Merge branch 'release/4.7.6' 2018-09-01 21:30:44 +02:00
James Cole
6a647dab8b Remove newline from changelog. 2018-09-01 20:57:03 +02:00
James Cole
ebcf5b71d2 Update meta files for new release. 2018-09-01 20:51:22 +02:00
James Cole
02370fb65d Fix final tests 2018-09-01 20:45:05 +02:00
James Cole
1e4f4907e3 Update translations. 2018-09-01 20:44:50 +02:00
James Cole
13f72c73fb Expand test coverage. 2018-08-31 21:12:53 +02:00
James Cole
69b4632ef6 Fix #1642 2018-08-31 21:11:47 +02:00
James Cole
ede8c293fc Fix for #1643 2018-08-31 19:51:18 +02:00
James Cole
0cfe991482 Fix issue where the tester would not respect the strict yes/no setting. 2018-08-31 17:48:54 +02:00
James Cole
6377459e2f Smaller batch for bunq import. #1607 2018-08-31 17:11:48 +02:00
James Cole
33fe6dbfa3 First step in improving test coverage. 2018-08-30 20:58:07 +02:00
James Cole
e158b9b64e Also improve the "forward" routine so it won't go back again #1607 2018-08-30 19:27:27 +02:00
James Cole
dfa9e537b3 Improve the bunq routine so it will keep looping when faced with default PHP time out settings (30 seconds). 2018-08-30 19:12:52 +02:00
James Cole
6d28ece616 Download more, sleep less. #1607 2018-08-29 17:33:36 +02:00
James Cole
59f4ecdaa6 The net worth chart will respect net worth preferences. 2018-08-29 10:57:42 +02:00
James Cole
10d953f336 Update change log. [skip ci] 2018-08-29 08:01:30 +02:00
James Cole
5b771f7def Code for #1607 2018-08-28 21:48:10 +02:00
James Cole
4a8e3ee845 Merge pull request #1639 from hamuz/hamuz-patch-1
Trust Heroku load balancer
2018-08-28 19:43:19 +02:00
HamuZ HamuZ
9a1f559dd2 Merge branch 'develop' into hamuz-patch-1 2018-08-28 20:34:01 +03:00
James Cole
62321a03ca Fix missing combi for transaction types. 2018-08-28 14:23:51 +02:00
James Cole
40ca72c656 Reference to unknown chart. 2018-08-28 14:20:04 +02:00
HamuZ HamuZ
34fcff7a9d Trust Heroku load balancer
Fix insecure warning in browser when deploying to Heroku
2018-08-28 08:18:43 +03:00
James Cole
e1c829f4fa Make some charts multi-currency. 2018-08-28 05:21:23 +02:00
James Cole
46136d94e9 A fix for apparently unknown category names [skip ci] 2018-08-28 04:29:16 +02:00
James Cole
0e2e8d1be5 Fix new category chart tests. 2018-08-27 21:06:46 +02:00
James Cole
1d1aa5dd3a Fix tests for multi currency account charts. 2018-08-27 20:33:52 +02:00
James Cole
0d82589916 Make some charts currency aware for #740 2018-08-27 18:59:30 +02:00
James Cole
4fc13037d2 This makes the expense chart on the frontpage multi-currency. 2018-08-27 08:08:51 +02:00
James Cole
3764499714 Expand API to accept liability accounts. 2018-08-26 21:29:46 +02:00
James Cole
c4bbbc49b4 Update CSS font references 2018-08-26 21:29:30 +02:00
James Cole
503158ab97 New translations [skip ci] 2018-08-26 18:44:22 +02:00
James Cole
8c1d1d1db0 Improved implementation of liability accounts and the option to add or remove accounts from the net-worth calculations. 2018-08-26 18:40:38 +02:00
James Cole
7dc72a2894 Add the ability to make transactions to and from liability accounts. 2018-08-25 22:10:10 +02:00
James Cole
07cfba1b3a Add the ability to make transfers to and from liability accounts. 2018-08-25 21:33:22 +02:00
James Cole
c55b80f467 Update test coverage. 2018-08-25 20:45:42 +02:00
James Cole
2099da7142 Moved word "success out of hyperlink [skip ci] 2018-08-25 17:09:25 +02:00
James Cole
ea125936e7 Fix CSS. [skip ci] 2018-08-25 17:08:29 +02:00
James Cole
5de01628a6 Expand secure headers. 2018-08-25 10:49:52 +02:00
James Cole
2834aca597 Update header readability, add Google as an optional allowed source. 2018-08-25 10:36:27 +02:00
James Cole
88bab888d8 Update CSS and JS libs. 2018-08-25 07:56:10 +02:00
James Cole
dfdbace298 Add secure headers middleware. 2018-08-25 07:55:47 +02:00
James Cole
a9590d2bb6 Add secure headers middleware. 2018-08-25 07:55:32 +02:00
James Cole
29a81eb05e Fix test coverage. 2018-08-24 21:14:17 +02:00
James Cole
20490fcd80 Update JS 2018-08-24 21:14:04 +02:00
James Cole
e775927f60 Add htaccess files to prevent directory indexing. [skip ci] 2018-08-24 21:10:04 +02:00
James Cole
835a421909 Refactor rule processor so it's testable. 2018-08-24 17:57:34 +02:00
James Cole
850a0ae17e Improved code coverage for events and reports. 2018-08-24 16:07:33 +02:00
James Cole
2b54363dd7 Improve test coverage. 2018-08-24 07:18:33 +02:00
James Cole
b174a06b86 Rewrite text in env files. 2018-08-24 07:17:50 +02:00
James Cole
d4096103cb Improve test coverage and fix test code. 2018-08-23 18:33:39 +02:00
James Cole
3f493aceb2 Mark code as untestable or deprecated (or both). 2018-08-23 18:33:07 +02:00
James Cole
05309da76d Small fix for test script. 2018-08-23 18:32:17 +02:00
James Cole
179f720806 Some updated translations [skip ci] 2018-08-23 06:17:26 +02:00
James Cole
7c34144ccd Some basic code for liability accounts. 2018-08-22 21:18:15 +02:00
James Cole
cc234b594d Fix call to cron job, clear cache after running. 2018-08-21 18:20:01 +02:00
James Cole
024cf610a8 Merge pull request #1624 from david-me/clickable-transaction-notifier
Can have link in success message to the transaction it refers to
2018-08-21 15:52:52 +02:00
David Meiseles
a1896a6336 DRYed out 2018-08-20 13:45:30 -04:00
David Meiseles
d30da7bf5d Can have link in success message to the transaction it refers to 2018-08-20 11:36:13 -04:00
James Cole
f8e914416d Give file a newline [skip ci] 2018-08-20 17:31:39 +02:00
James Cole
433da921bb Simplify cronjob call. 2018-08-20 17:29:39 +02:00
James Cole
4876053018 Test a fix for #1620 2018-08-19 19:31:21 +02:00
James Cole
0c3a580b33 Fix issues with italian translation, add new translations [skip ci] 2018-08-18 22:11:31 +02:00
James Cole
7689b7b4b0 Forgot to push this part of the fix for #1615 2018-08-18 20:13:52 +02:00
James Cole
21bff39e31 Fix #1620 2018-08-18 20:13:26 +02:00
James Cole
ba09901228 fix #1615 2018-08-18 20:11:12 +02:00
James Cole
90bf2e58b2 Fixes #1620 2018-08-18 14:12:39 +02:00
James Cole
004807aa32 Update cron file, use supervisor. 2018-08-18 14:08:28 +02:00
James Cole
35bacf2ad0 Update docker file to match postgres. 2018-08-18 05:21:47 +02:00
James Cole
81d17409d4 Fix some things with the update checker. 2018-08-17 21:51:15 +02:00
James Cole
a8080f55f0 Fix docker and entry point. 2018-08-17 21:12:26 +02:00
James Cole
379c540bd8 Update config for logging in Docker. 2018-08-17 20:01:46 +02:00
James Cole
f319005357 Fix tests. 2018-08-17 06:45:57 +02:00
James Cole
df0e2dd2a2 Bump version and warn about PHP 7.2 2018-08-17 06:39:48 +02:00
James Cole
219a0cd612 Fix for #1617 2018-08-17 05:54:29 +02:00
James Cole
3ca3ce0726 Fix #1616 2018-08-16 20:43:11 +02:00
James Cole
566be8dc63 Fix #1564 2018-08-16 16:42:58 +02:00
James Cole
6bd4fa1c0a Remove bad slash from path. 2018-08-15 19:10:00 +02:00
James Cole
c767ee04f4 Merge pull request #1613 from ErikFontanel/develop
fixed missing ENV variables
2018-08-15 17:15:33 +02:00
Erik Gelderblom
a5f89e0967 fixed missing ENV variables 2018-08-15 14:43:49 +02:00
James Cole
7355d14159 Merge pull request #1610 from ErikFontanel/develop
Multi architecture Dockerfile
2018-08-15 06:18:54 +02:00
Erik Gelderblom
efd5ceb405 fixed installation for cURL and cron 2018-08-14 21:21:03 +02:00
James Cole
035dc8ceb4 Fix #1609 2018-08-14 20:08:07 +02:00
James Cole
11be33e942 Fix #1605 2018-08-14 06:40:21 +02:00
James Cole
e125254687 Fix bad method name. 2018-08-14 06:40:04 +02:00
James Cole
a2b997ba20 Fix #1608 2018-08-13 19:09:43 +02:00
James Cole
7327941c77 Alert if cron job isn't running. 2018-08-13 19:07:46 +02:00
James Cole
6c9eb1b699 Update composer lock file. 2018-08-13 19:07:22 +02:00
James Cole
60e262dece Fix bug in Spectre import. 2018-08-13 18:30:47 +02:00
James Cole
9c5463e515 Update to user and cron job. 2018-08-13 18:10:02 +02:00
James Cole
6941176519 Make chart red/green 2018-08-13 18:09:47 +02:00
James Cole
cb2c52cddb New cronjob code. 2018-08-12 14:26:11 +02:00
James Cole
dd95776144 Code for #833 2018-08-12 10:06:20 +02:00
James Cole
b95ca98be9 Add cron job to docker file. 2018-08-12 09:34:03 +02:00
James Cole
67b090b4d8 New translations. 2018-08-12 09:33:56 +02:00
James Cole
54b76a03ce Update views and translations. 2018-08-11 19:22:28 +02:00
James Cole
cd6c727730 Flags for help pages. 2018-08-11 19:22:10 +02:00
James Cole
a35c6e29b6 Rename various methods. 2018-08-11 19:21:58 +02:00
James Cole
95ce72fce7 Expand API options for available budgets and journal links 2018-08-11 18:27:45 +02:00
James Cole
a803dfc7fa Undo recurring job thing. 2018-08-11 18:20:29 +02:00
James Cole
c465d1c059 Example run of recurring thing outside of cron job. 2018-08-11 18:20:10 +02:00
James Cole
9914c0791e Rename journal collector to more fitting transaction collector. 2018-08-11 14:33:47 +02:00
James Cole
96baf5d3c7 Add new transaction collector (as opposed to journal collector). 2018-08-11 14:15:22 +02:00
James Cole
a205367b62 Various refactoring. 2018-08-11 14:15:07 +02:00
James Cole
6218fa90de Move get income / get expense methods to trait. 2018-08-11 14:06:49 +02:00
James Cole
51a770cfdc New experimental Dockerfile #1464 2018-08-11 07:22:17 +02:00
James Cole
16fba15b5c Refactor various methods away from controllers 2018-08-11 06:39:29 +02:00
James Cole
ec2463a3ba Remove view generation and put in trait. 2018-08-10 18:19:51 +02:00
James Cole
b605ede74e Move methods to traits. 2018-08-10 17:05:37 +02:00
James Cole
b1b13d3696 Can no longer set a budget to an expense. 2018-08-09 20:49:30 +02:00
James Cole
51b11e5188 Can no longer set a budget to an expense. 2018-08-09 20:46:47 +02:00
James Cole
eefa84a77b Remove method pointers from tests. 2018-08-09 20:17:15 +02:00
James Cole
5908b4b000 Route fixes and fix tests. 2018-08-09 19:44:36 +02:00
James Cole
2ed433c96d Refactor configuration methods into trait 2018-08-09 17:50:30 +02:00
James Cole
9865800e39 Refactor many request related methods into (complex) trait. 2018-08-09 17:46:14 +02:00
James Cole
4f697e77d5 Redirect user to original account refactor. 2018-08-09 17:34:11 +02:00
James Cole
c957aded98 Redirect user to original account refactor. 2018-08-09 17:32:28 +02:00
James Cole
aa0758cd2b Refactor basic methods to trait 2018-08-09 16:16:27 +02:00
James Cole
0c2093753d Refactor isSplitJournal() 2018-08-09 16:14:47 +02:00
James Cole
136f983353 Move isOpeningBalance() to trait 2018-08-09 16:13:13 +02:00
James Cole
7943164375 Change scope of methods, add some notes. Prep for refactoring. 2018-08-09 16:07:33 +02:00
James Cole
32e58d0a60 Replace "moment" with more accurate start/end dates. 2018-08-08 17:53:40 +02:00
James Cole
bc807965ab Improve navigation for tags and rename route. 2018-08-07 21:00:25 +02:00
James Cole
477788658b Recurring transactions support pagination. 2018-08-07 20:47:05 +02:00
James Cole
723abf44bd Shorten breadcrumbs [skip ci] 2018-08-07 20:38:19 +02:00
James Cole
fd1298d4d2 Refactor method that only counts. 2018-08-07 19:29:53 +02:00
James Cole
42f39536a1 Catch "throwable" 2018-08-07 19:29:40 +02:00
James Cole
6f0ac91bd2 Add missing string. 2018-08-07 19:29:25 +02:00
James Cole
6dea9156ab Fix edit for liabilities. 2018-08-07 19:29:19 +02:00
James Cole
c5051b3e46 Make method nullable. 2018-08-07 19:29:10 +02:00
James Cole
229d033e1a Fix category bread crumb 2018-08-07 19:28:54 +02:00
James Cole
f494ba7065 Rename field to "notes" 2018-08-07 19:28:46 +02:00
James Cole
201bc7db53 Update requests. 2018-08-07 19:24:07 +02:00
James Cole
cd2a251f22 Reinstate description for rule group. 2018-08-07 17:54:37 +02:00
James Cole
ff44ad4994 Fix #1597 2018-08-07 17:50:14 +02:00
James Cole
b496ca6a2c Some fixing up for #1598 2018-08-07 17:34:43 +02:00
James Cole
5908c0ce8c Code cleanup and realign. 2018-08-06 19:14:30 +02:00
James Cole
f7eef25fed New translations. 2018-08-05 20:44:05 +02:00
James Cole
049c93465a Update tests 2018-08-05 20:42:45 +02:00
James Cole
33294dd9f0 Allow editing of liabilities. 2018-08-05 18:59:15 +02:00
James Cole
0a89f4000d Synchronise API and app rule management. 2018-08-05 15:41:13 +02:00
James Cole
422e80530b Refactor rule creation. 2018-08-05 15:34:20 +02:00
James Cole
07a8c69ba8 New translations [skip ci] 2018-08-05 15:33:49 +02:00
James Cole
5449879a7d Fix for #1594 2018-08-05 07:36:33 +02:00
James Cole
8dbc846314 Basic code for tracking liabilities. 2018-08-04 17:30:47 +02:00
James Cole
f0d3ca5d53 Various code cleanup. 2018-08-04 17:30:06 +02:00
James Cole
5af026674f Updated translations. 2018-08-04 14:17:03 +02:00
James Cole
2ebb4778cd Merge pull request #1593 from lucavallerini/transactions-links-translatable
Transactions links are now translatable on admin views
2018-08-04 14:14:33 +02:00
James Cole
bf3c57d26b Remove translations. 2018-08-04 14:14:08 +02:00
Luca Vallerini
cb9c87102f Transactions links are now translatable on admin views 2018-08-04 13:03:54 +02:00
James Cole
c73b003de4 Merge pull request #1591 from claystation/master
BUGFIX: Initial user not set as owner
2018-08-04 12:08:00 +02:00
Clemens Wijnekus
771d448a7b Revert "Added .idea folder to Gitignore for IntelliJ based projects."
This reverts commit dd49926
2018-08-04 10:17:18 +02:00
Clemens Wijnekus
de12db5f05 Fix for setting initial user as Owner 2018-08-04 00:27:28 +02:00
Clemens Wijnekus
dd49926cc2 Added .idea folder to Gitignore for IntelliJ based projects. 2018-08-04 00:08:21 +02:00
James Cole
7a9ab190eb Fixes #1586 2018-08-03 16:55:10 +02:00
James Cole
2290fcde22 First code for liabilities and some tests. 2018-08-03 16:35:55 +02:00
James Cole
ae85876965 Make sure null value is turned into an empty string [skip ci] 2018-08-02 07:17:18 +02:00
James Cole
f07d8e958f Experimental sort routine for list of accounts [skip ci] 2018-08-02 07:14:00 +02:00
James Cole
610af45dee Experimental sort routine for list of accounts [skip ci] 2018-08-02 07:12:06 +02:00
James Cole
138a5bc3fe Add autocomplete field as suggested by Chrome. 2018-08-01 07:35:31 +02:00
James Cole
427e9c5637 Fix #1216 2018-08-01 07:32:53 +02:00
James Cole
e3e8336602 Update some code for Heroku. 2018-08-01 07:24:19 +02:00
James Cole
194073e49a Fix tests. 2018-07-31 20:39:36 +02:00
James Cole
1af45aff73 Fix missing link to admin. 2018-07-31 19:28:56 +02:00
James Cole
56518ea028 First working version of YNAB import #145 2018-07-31 18:19:48 +02:00
James Cole
c1ac2bb156 Expand text and routine for YNAB 2018-07-31 05:49:03 +02:00
James Cole
a004f27361 Updated strings 2018-07-31 05:35:25 +02:00
James Cole
7843c55409 Expand helptext for #1581 2018-07-31 05:30:27 +02:00
James Cole
41da7d9f9a Fix #1580 2018-07-31 05:27:33 +02:00
James Cole
2add644706 First basic import #145 2018-07-30 20:39:19 +02:00
James Cole
dfd9cf0874 New code for YNAB import. 2018-07-29 21:02:03 +02:00
James Cole
7ad09da4e9 Fix #1576 2018-07-29 16:04:22 +02:00
James Cole
8efbeb14d2 First code for YNAB import #145 2018-07-29 07:30:06 +02:00
James Cole
a1005d91df Expand views with CSRF token, to prevent error in console. #1575 2018-07-29 06:53:08 +02:00
James Cole
a681f1ce3c Empty URL warning 2018-07-28 21:03:08 +02:00
James Cole
5a0714ca1a Merge tag '4.7.5.3' into develop
4.7.5.3
2018-07-28 15:39:36 +02:00
James Cole
bd5c790043 Merge branch 'release/4.7.5.3' 2018-07-28 15:39:35 +02:00
James Cole
2ae3cf79e4 Update config files and change logs for hotfix. 2018-07-28 15:20:28 +02:00
James Cole
fb122ba097 Fix for #1572 2018-07-28 15:10:20 +02:00
James Cole
0c104cd86c New file list for Sandstorm. 2018-07-28 14:54:10 +02:00
James Cole
a687f4ad68 Merge tag '4.7.5.2' into develop
4.7.5.2
2018-07-28 13:38:09 +02:00
James Cole
228f42cf04 Merge branch 'release/4.7.5.2' 2018-07-28 13:38:06 +02:00
James Cole
6d4956b574 Updated files for 4.7.5.2 2018-07-28 12:10:25 +02:00
James Cole
0c7b652a70 Last code optimization before release. 2018-07-28 10:45:16 +02:00
James Cole
d35470a79e Found and fixed #1571 2018-07-28 10:03:47 +02:00
James Cole
719d610be3 Fix issue with new crud() method. 2018-07-28 07:26:33 +02:00
James Cole
07ae64693e new language strings and updated code 2018-07-28 06:27:30 +02:00
James Cole
0ccc1271a6 Update tests. 2018-07-27 06:06:29 +02:00
James Cole
26fa2b0b74 Speed up category test. 2018-07-27 06:02:34 +02:00
James Cole
6f64c19c32 Update changelog for next release. 2018-07-27 05:03:50 +02:00
James Cole
e3e0e12fef Various code cleanup. 2018-07-27 05:03:37 +02:00
James Cole
0312ba8ad7 Various bugfixes and code clean up. 2018-07-27 04:46:21 +02:00
James Cole
2ad8e7f343 Fix some errors found in debug logs. 2018-07-27 03:09:35 +02:00
James Cole
d6298d9f05 Add extra logging for common error on demo site [skip ci] 2018-07-26 06:28:49 +02:00
James Cole
89be30c4b9 Catch various errors. 2018-07-26 06:27:52 +02:00
James Cole
6bcfea1de4 Various code cleanup. 2018-07-26 06:10:17 +02:00
James Cole
e8c9554dd6 Remove TODO's, add some suppressors for code quality. 2018-07-25 19:43:02 +02:00
James Cole
02272f7db0 New strings [skip ci] 2018-07-25 16:44:06 +02:00
James Cole
5a73e79475 Update explanation about sha1 [skip ci] 2018-07-25 16:14:24 +02:00
James Cole
7f4ecd40ce Fix issues where data-variable was not initialized properly. 2018-07-25 07:11:04 +02:00
James Cole
7c950c3022 Remove a lot of deprecated code. 2018-07-25 06:45:25 +02:00
James Cole
dbf019135a Simplified tag cloud. 2018-07-25 06:18:20 +02:00
James Cole
e504ee82e5 Submitted debug code. 2018-07-24 21:13:12 +02:00
James Cole
780a15fe4f Remove array calls and fix various bugs. 2018-07-24 21:12:48 +02:00
James Cole
abb249643f Fix bad class reference. 2018-07-24 20:49:25 +02:00
James Cole
086eccaf4a Updates for new Sandstorm package. 2018-07-24 20:30:52 +02:00
James Cole
871033501a Update file list for Sandstorm. 2018-07-24 20:29:39 +02:00
James Cole
ccd727488f Update file list for Sandstorm. 2018-07-24 20:19:41 +02:00
James Cole
aa59d0f082 Merge pull request #1569 from ocdtrekkie/update-sandstorm-build
Update Sandstorm build instructions
2018-07-24 20:16:42 +02:00
Jacob Weisz
5d12f53283 Update Sandstorm build instructions
I've moved this to official Jessie 64-bit. vagrant-spk currently uses Stretch, but that'd likely require more changes and testing on your other build files.
2018-07-24 12:14:35 -05:00
James Cole
59c005875a Fix for #1568 2018-07-24 17:46:34 +02:00
James Cole
06d22e843a Code optimizations. 2018-07-23 21:49:15 +02:00
James Cole
4fa5f4e5a3 Fix some issues that triggered in scrutinizer. 2018-07-22 21:32:58 +02:00
James Cole
67ea825d4a Remove unused methods. 2018-07-22 21:09:57 +02:00
James Cole
a616e06f9d Add newlines to tests. [skip ci] 2018-07-22 20:33:17 +02:00
James Cole
b7752928a4 Give all of these files a newline at the end. 2018-07-22 20:32:02 +02:00
James Cole
ca096852a5 Code optimisations. 2018-07-22 18:50:27 +02:00
James Cole
ea2c48bca5 Fix tests. 2018-07-22 17:06:10 +02:00
James Cole
a722dc4235 Clean up code, remove unused methods. 2018-07-22 16:35:46 +02:00
James Cole
dbbf0ff5e4 Improve code in Jobs. 2018-07-22 15:20:45 +02:00
James Cole
a941519db5 Improve code quality. 2018-07-22 15:08:56 +02:00
James Cole
d4ba014a8a Clean up various code. 2018-07-22 12:52:07 +02:00
James Cole
d193a6aec4 Give commands proper exit codes. 2018-07-22 10:05:06 +02:00
James Cole
1f0fdf3da7 Fix #1563 2018-07-22 09:03:53 +02:00
James Cole
b705240faa Fix #1530 2018-07-22 08:58:58 +02:00
James Cole
662b832274 Fix max amount. 2018-07-22 08:36:30 +02:00
James Cole
aed7e6d289 Fix #1549 2018-07-22 08:27:18 +02:00
James Cole
f7a1201d02 Expand route link for transactions without a budget. 2018-07-22 08:14:42 +02:00
James Cole
4d5bdd25a8 Add phpdocs everywhere. 2018-07-22 08:10:16 +02:00
James Cole
4a90ce35f2 Add php doc [skip ci] 2018-07-21 08:55:32 +02:00
James Cole
02f5eddd14 Update PHP doc everywhere. 2018-07-21 08:06:24 +02:00
James Cole
5ca4f1b181 Remove null pointer. 2018-07-21 06:41:42 +02:00
James Cole
ec7ef3a813 Various fixes for tests and code quality. 2018-07-20 20:53:48 +02:00
James Cole
49ff6febe5 Fix tests. 2018-07-20 16:28:54 +02:00
James Cole
2d66a9212f Various code cleanup 2018-07-20 14:35:09 +02:00
James Cole
44fb307da4 Code cleanup. 2018-07-20 14:34:56 +02:00
James Cole
cfc2181a48 Show note of piggy bank [skip ci] 2018-07-20 12:17:43 +02:00
James Cole
cf4a846312 Show note of piggy bank [skip ci] 2018-07-20 12:16:01 +02:00
James Cole
633b357d7b Clean up two big methods. 2018-07-19 16:57:38 +02:00
James Cole
b96d67a54e Referenced the wrong array. 2018-07-18 07:29:58 +02:00
James Cole
5b83931b01 Clean up recurrence transformer. 2018-07-18 07:28:35 +02:00
James Cole
f22b54de30 Clean up sandstorm tests. 2018-07-18 07:16:46 +02:00
James Cole
a3306bb26f Leaving only the specials. 2018-07-18 07:16:32 +02:00
James Cole
0adacac269 Remove switches, add if-statement. 2018-07-18 06:58:51 +02:00
James Cole
7359ed2ba2 Updated file list for Sandstorm. 2018-07-18 06:35:27 +02:00
James Cole
5a5f4e8161 Small update for Sandstorm release. 2018-07-18 06:30:56 +02:00
James Cole
b886cc1333 Optimize some code. 2018-07-17 22:21:03 +02:00
James Cole
9299efd086 Fix #1553 2018-07-17 16:36:36 +02:00
James Cole
1502aa3b20 Small code cleanup [skip ci] 2018-07-15 19:17:26 +02:00
James Cole
73e32ecdcb Refer to correct repositories. 2018-07-15 15:45:45 +02:00
James Cole
ac8776aea4 Add annotated methods. 2018-07-15 10:00:08 +02:00
James Cole
7b41c5b301 Cast all translations to strings. 2018-07-15 09:38:49 +02:00
James Cole
369839e012 Clean up references to static Facade. 2018-07-15 09:27:38 +02:00
James Cole
8fde16422e See if this is the solution in Scrutinizer as well. 2018-07-14 23:32:03 +02:00
James Cole
f1462dbd3d Small code quality improvements. 2018-07-14 23:22:08 +02:00
James Cole
5dad569d62 Add some method annotators, see if this helps with Scrutinizer issues. 2018-07-14 23:04:05 +02:00
James Cole
c424bb097d Improve category code quality. 2018-07-14 22:48:22 +02:00
James Cole
e4b1760b20 Remove exit clause from test. 2018-07-14 17:33:10 +02:00
James Cole
780e365a78 Possible fix for #1527 2018-07-14 17:23:44 +02:00
James Cole
3d1523a060 Improve randomness in test data to prevent key collisions. 2018-07-14 16:41:07 +02:00
James Cole
ff403dfa2e Improve code quality in budget methods. 2018-07-14 16:40:46 +02:00
James Cole
89834baf01 Refactor references to static facades. Improve budget controller code. 2018-07-14 16:08:34 +02:00
James Cole
b8699422c8 Refactor budget controller. 2018-07-14 15:22:21 +02:00
James Cole
6bc772d640 Add Facade methods for scrutinizer. 2018-07-14 15:21:05 +02:00
James Cole
0712f30a51 Fix bug in API: missing destroy budget limit method. 2018-07-14 15:16:32 +02:00
James Cole
9116796d90 Refactor account code and tests. 2018-07-14 11:45:05 +02:00
James Cole
a95fdb903b Refactor account controller and some associated tests. 2018-07-14 11:16:12 +02:00
James Cole
2ca6421206 Remove Rabobank description fix from available fixes. 2018-07-14 08:34:27 +02:00
James Cole
cd076cc069 Fix a bug where transfers would be stored reversed (ie. source and destination switched). 2018-07-14 08:33:13 +02:00
James Cole
46482bdae1 Merge tag '4.7.5.1' into develop
4.7.5.1
2018-07-14 07:05:34 +02:00
James Cole
5189c897be Merge branch 'release/4.7.5.1' 2018-07-14 07:05:31 +02:00
James Cole
2c7d25d472 Final changelog. 2018-07-14 06:37:55 +02:00
James Cole
0da370c42d Not really a solution for the test, but might work. 2018-07-13 18:45:11 +02:00
James Cole
6f036d9120 Fix test. 2018-07-13 17:02:23 +02:00
James Cole
260bbd79fd Update composer file. 2018-07-13 16:40:00 +02:00
James Cole
37ad6a3a62 Updated translation. 2018-07-13 16:29:10 +02:00
James Cole
aa25007431 Fixes tests 2018-07-13 16:07:30 +02:00
James Cole
8b33ec1339 Fix a transaction currency bug. 2018-07-13 15:56:06 +02:00
James Cole
cede11ecea Delete old code. 2018-07-13 15:52:27 +02:00
James Cole
2b4088c5f7 Some code cleanup. 2018-07-13 15:50:42 +02:00
James Cole
d872484607 Speed up category tests. 2018-07-13 06:52:53 +02:00
James Cole
f3f2160d96 Update files and languages. 2018-07-13 06:39:50 +02:00
James Cole
bcdb849b46 Update for bug fix release. 2018-07-13 06:12:39 +02:00
James Cole
5846431b34 Various code coverage changes and code updates. 2018-07-12 21:32:58 +02:00
James Cole
0217d9396a Bill must be active when stored. 2018-07-10 20:21:34 +02:00
James Cole
c99e233026 Add some debug entries. 2018-07-09 20:42:16 +02:00
James Cole
f670d930f3 Clean up docker file. 2018-07-09 19:43:08 +02:00
James Cole
0237d78f61 Fix some tests. 2018-07-09 19:42:53 +02:00
James Cole
5665f127aa Improve code quality. 2018-07-09 19:24:08 +02:00
James Cole
76386dad7d Fix #1541 2018-07-09 19:23:19 +02:00
James Cole
42072fdda4 Fix #1452 2018-07-09 05:37:30 +02:00
James Cole
fc80f828be Fix #1538 2018-07-08 15:22:52 +02:00
James Cole
d05a1e0260 Specify return types. 2018-07-08 12:28:42 +02:00
James Cole
b315882f58 Various code cleanup. 2018-07-08 12:08:53 +02:00
James Cole
2f2f907ffe Various code optimalisations. 2018-07-08 07:59:58 +02:00
James Cole
10492e3b2f Expand documentation for Helper directory. 2018-07-07 23:14:16 +02:00
James Cole
8e08ff2d39 Fix the transaction factory and associated tests. 2018-07-07 22:28:08 +02:00
James Cole
e78a59a8a8 Code quality update. 2018-07-07 21:17:46 +02:00
James Cole
cbe47a9dcc Code clean up in Handlers. 2018-07-07 07:48:10 +02:00
James Cole
a1056147d8 Improve code quality and add documentation in folder "Generator" 2018-07-07 07:18:49 +02:00
James Cole
8692590600 Improve code quality for Export directory. 2018-07-06 19:06:08 +02:00
James Cole
57345113b5 Improve code quality for Export directory. 2018-07-06 19:05:27 +02:00
James Cole
52f02cb9eb Fix #1533 2018-07-06 18:43:46 +02:00
James Cole
5d4dcd7e4b Small code optimizations in Exceptions. 2018-07-06 07:37:14 +02:00
James Cole
7d1f4d8907 Improve Events code quality. 2018-07-06 07:19:19 +02:00
James Cole
a76241c7ba Code cleanup and documentation improvements. 2018-07-06 07:15:42 +02:00
James Cole
bdc6678341 Fix unit tests. 2018-07-05 21:44:13 +02:00
James Cole
c99b7e927d Code optimalisations. 2018-07-05 21:18:53 +02:00
James Cole
1675a0d442 Fix unit tests. 2018-07-05 20:15:20 +02:00
James Cole
c0d2cd8962 Fix unit tests. 2018-07-05 19:39:17 +02:00
James Cole
146c9fd947 Fix unit tests. 2018-07-05 19:02:22 +02:00
James Cole
666e9897ea Fix unit test. 2018-07-05 18:42:51 +02:00
James Cole
81d70bd811 Clean up API code. 2018-07-05 18:02:02 +02:00
James Cole
f6f8bb7fd1 Clean up API code. 2018-07-05 06:10:35 +02:00
James Cole
7c3aaf7b7c Fix #1531 2018-07-05 05:53:21 +02:00
James Cole
32ea28f783 Fix #1532 2018-07-05 05:44:49 +02:00
James Cole
17f365941b Merge tag '4.7.5' into develop
4.7.5
2018-07-03 20:33:36 +02:00
1214 changed files with 58465 additions and 25631 deletions

View File

@@ -0,0 +1,11 @@
[program:cron]
command=/usr/sbin/cron -f -L 15
user=root
autostart=true
autorestart=true
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
startsecs=10
startretries=3

View File

@@ -16,14 +16,14 @@ mkdir -p $FIREFLY_PATH/storage/upload
# make sure we own the volumes:
chown -R www-data:www-data -R $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/logs $FIREFLY_PATH/storage/framework/cache
chmod -R 775 $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/logs $FIREFLY_PATH/storage/framework/cache
chown -R www-data:www-data -R $FIREFLY_PATH/storage
chmod -R 775 $FIREFLY_PATH/storage
# remove any lingering files that may break upgrades:
rm -f $FIREFLY_PATH/storage/logs/laravel.log
cat .env.docker | envsubst > .env && cat .env
cat .env.docker | envsubst > .env
composer dump-autoload
php artisan package:discover
php artisan firefly:instructions install
exec apache2-foreground
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf --nodaemon

View File

@@ -0,0 +1,6 @@
[program:apache2]
command=/bin/bash -c "source /etc/apache2/envvars && exec /usr/sbin/apache2 -DFOREGROUND"
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0

View File

@@ -0,0 +1,30 @@
# supervisor config file
# Adapted from the config file distributed with the supervisor package on Debian
# Jessie
# Enable supervisord in non-daemon mode. Disable the logfile as we receive
# log messages via stdout/err. Set up the child process log directory in case
# the user doesn't set logging to stdout/err.
[supervisord]
nodaemon = true
logfile = NONE
pidfile = /var/run/supervisord.pid
childlogdir = /var/log/supervisor
loglevel=debug
# Enable supervisorctl via RPC interface over Unix socket
[unix_http_server]
file = /var/run/supervisor.sock
chmod = 0700
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl = unix:///var/run/supervisor.sock
# Include conf files for child processes
# Debian/Ubuntu packages use /etc/supervisor/conf.d
[include]
files = /etc/supervisor/conf.d/*.conf

26
.deploy/docker/vhost.conf Normal file
View File

@@ -0,0 +1,26 @@
server {
listen 80 default_server;
server_name _ *.vm docker;
root "/app/public";
index index.php;
include /opt/docker/etc/nginx/vhost.common.d/*.conf;
}
##############
# SSL
##############
server {
listen 443 default_server;
server_name _ *.vm docker;
root "/app/public";
index index.php;
include /opt/docker/etc/nginx/vhost.common.d/*.conf;
include /opt/docker/etc/nginx/vhost.ssl.conf;
}

View File

@@ -1,4 +1,3 @@
# Ignore composer specific files and vendor folder
composer.phar
composer.lock
vendor

View File

@@ -13,15 +13,31 @@ SITE_OWNER=${SITE_OWNER}
# Change it to a string of exactly 32 chars or use command `php artisan key:generate` to generate it
APP_KEY=${FF_APP_KEY}
# APP_URL and TRUSTED_PROXIES are useful when using Docker and/or a reverse proxy.
# Change this value to your preferred time zone.
# Example: Europe/Amsterdam
TZ=${TZ}
# This variable must match your installation's external address but keep in mind that
# it's only used on the command line as a fallback value.
APP_URL=${APP_URL}
# TRUSTED_PROXIES is a useful variable when using Docker and/or a reverse proxy.
TRUSTED_PROXIES=${TRUSTED_PROXIES}
# The log channel defines where your log entries go to.
LOG_CHANNEL=${LOG_CHANNEL}
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
# Also available are 'syslog', 'errorlog' and 'stdout' which will log to the system itself.
LOG_CHANNEL=stdout
# Log level. You can set this from least severe to most severe:
# debug, info, notice, warning, error, critical, alert, emergency
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
# nothing will get logged, ever.
APP_LOG_LEVEL=${APP_LOG_LEVEL}
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
# If you use SQLite, set connection to `sqlite` and remove the database, username and password settings.
# For other database types, please see the FAQ: http://firefly-iii.readthedocs.io/en/latest/support/faq.html
DB_CONNECTION=${FF_DB_CONNECTION}
DB_HOST=${FF_DB_HOST}
DB_PORT=${FF_DB_PORT}
@@ -29,17 +45,6 @@ DB_DATABASE=${FF_DB_NAME}
DB_USERNAME=${FF_DB_USER}
DB_PASSWORD=${FF_DB_PASSWORD}
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
# Also available are 'syslog' and 'errorlog' which will log to the system itself.
APP_LOG=syslog
# Log level. You can set this from least severe to most severe:
# debug, info, notice, warning, error, critical, alert, emergency
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
# nothing will get logged, ever.
APP_LOG_LEVEL=info
# If you're looking for performance improvements, you could install memcached.
CACHE_DRIVER=file
SESSION_DRIVER=file
@@ -103,4 +108,5 @@ IS_DOCKER=true
IS_SANDSTORM=false
IS_HEROKU=false
BUNQ_USE_SANDBOX=false
TZ=${TZ}
MAILGUN_DOMAIN=
MAILGUN_SECRET=

View File

@@ -15,15 +15,27 @@ APP_KEY=SomeRandomStringOf32CharsExactly
# Change this value to your preferred time zone.
# Example: Europe/Amsterdam
TZ=UTC
TZ=Europe/Amsterdam
# APP_URL and TRUSTED_PROXIES are useful when using Docker and/or a reverse proxy.
# This variable must match your installation's external address but keep in mind that
# it's only used on the command line as a fallback value.
APP_URL=http://localhost
# TRUSTED_PROXIES is a useful variable when using Docker and/or a reverse proxy.
TRUSTED_PROXIES=
# The log channel defines where your log entries go to.
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
# Also available are 'syslog', 'errorlog' and 'stdout' which will log to the system itself.
LOG_CHANNEL=daily
# Log level. You can set this from least severe to most severe:
# debug, info, notice, warning, error, critical, alert, emergency
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
# nothing will get logged, ever.
APP_LOG_LEVEL=notice
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
# For other database types, please see the FAQ: http://firefly-iii.readthedocs.io/en/latest/support/faq.html
DB_CONNECTION=mysql
@@ -33,17 +45,6 @@ DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
# Also available are 'syslog' and 'errorlog' which will log to the system itself.
APP_LOG=daily
# Log level. You can set this from least severe to most severe:
# debug, info, notice, warning, error, critical, alert, emergency
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
# nothing will get logged, ever.
APP_LOG_LEVEL=notice
# If you're looking for performance improvements, you could install memcached.
CACHE_DRIVER=file
SESSION_DRIVER=file
@@ -105,7 +106,7 @@ DEMO_USERNAME=
DEMO_PASSWORD=
IS_DOCKER=false
IS_SANDSTORM=false
BUNQ_USE_SANDBOX=false
IS_HEROKU=false
BUNQ_USE_SANDBOX=false
MAILGUN_DOMAIN=
MAILGUN_SECRET=

View File

@@ -17,12 +17,24 @@ APP_KEY=7ahyYVPVsmxjdhsweWCauGeJfwc92NP2
# Example: Europe/Amsterdam
TZ=UTC
# APP_URL and TRUSTED_PROXIES are useful when using Docker and/or a reverse proxy.
# This variable must match your installation's external address but keep in mind that
# it's only used on the command line as a fallback value.
APP_URL=http://localhost
TRUSTED_PROXIES=
# TRUSTED_PROXIES is a useful variable when using Docker and/or a reverse proxy.
TRUSTED_PROXIES=**
# The log channel defines where your log entries go to.
LOG_CHANNEL=syslog
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
# Also available are 'syslog', 'errorlog' and 'stdout' which will log to the system itself.
LOG_CHANNEL=stdout
# Log level. You can set this from least severe to most severe:
# debug, info, notice, warning, error, critical, alert, emergency
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
# nothing will get logged, ever.
APP_LOG_LEVEL=debug
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
# If you use SQLite, set connection to `sqlite` and remove the database, username and password settings.
@@ -33,17 +45,6 @@ DB_CONNECTION=pgsql
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
# Also available are 'syslog' and 'errorlog' which will log to the system itself.
APP_LOG=errorlog
# Log level. You can set this from least severe to most severe:
# debug, info, notice, warning, error, critical, alert, emergency
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
# nothing will get logged, ever.
APP_LOG_LEVEL=debug
# If you're looking for performance improvements, you could install memcached.
CACHE_DRIVER=file
SESSION_DRIVER=file
@@ -105,7 +106,7 @@ DEMO_USERNAME=
DEMO_PASSWORD=
IS_DOCKER=false
IS_SANDSTORM=false
BUNQ_USE_SANDBOX=false
IS_HEROKU=true
BUNQ_USE_SANDBOX=false
MAILGUN_DOMAIN=
MAILGUN_SECRET=

View File

@@ -17,12 +17,24 @@ APP_KEY=SomeRandomStringOf32CharsExactly
# Example: Europe/Amsterdam
TZ=UTC
# APP_URL and TRUSTED_PROXIES are useful when using Docker and/or a reverse proxy.
# This variable must match your installation's external address but keep in mind that
# it's only used on the command line as a fallback value.
APP_URL=http://localhost
# TRUSTED_PROXIES is a useful variable when using Docker and/or a reverse proxy.
TRUSTED_PROXIES=
# The log channel defines where your log entries go to.
LOG_CHANNEL=syslog
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
# Also available are 'syslog', 'errorlog' and 'stdout' which will log to the system itself.
LOG_CHANNEL=stdout
# Log level. You can set this from least severe to most severe:
# debug, info, notice, warning, error, critical, alert, emergency
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
# nothing will get logged, ever.
APP_LOG_LEVEL=debug
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
# If you use SQLite, set connection to `sqlite` and remove the database, username and password settings.
@@ -33,17 +45,6 @@ DB_DATABASE=firefly
DB_USERNAME=firefly
DB_PASSWORD=firefly
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
# Also available are 'syslog' and 'errorlog' which will log to the system itself.
APP_LOG=syslog
# Log level. You can set this from least severe to most severe:
# debug, info, notice, warning, error, critical, alert, emergency
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
# nothing will get logged, ever.
APP_LOG_LEVEL=info
# If you're looking for performance improvements, you could install memcached.
CACHE_DRIVER=file
SESSION_DRIVER=file
@@ -105,7 +106,7 @@ DEMO_USERNAME=
DEMO_PASSWORD=
IS_DOCKER=false
IS_SANDSTORM=true
BUNQ_USE_SANDBOX=false
IS_HEROKU=false
BUNQ_USE_SANDBOX=false
MAILGUN_DOMAIN=
MAILGUN_SECRET=

View File

@@ -17,27 +17,33 @@ APP_KEY=TestTestTestTestTestTestTestTest
# Example: Europe/Amsterdam
TZ=Europe/Amsterdam
# APP_URL and TRUSTED_PROXIES are useful when using Docker and/or a reverse proxy.
# This variable must match your installation's external address but keep in mind that
# it's only used on the command line as a fallback value.
APP_URL=http://localhost
# TRUSTED_PROXIES is a useful variable when using Docker and/or a reverse proxy.
TRUSTED_PROXIES=
# The log channel defines where your log entries go to.
LOG_CHANNEL=dailytest
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
# For other database types, please see the FAQ: http://firefly-iii.readthedocs.io/en/latest/support/faq.html
DB_CONNECTION=sqlite
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
# Also available are 'syslog' and 'errorlog' which will log to the system itself.
APP_LOG=daily
# Also available are 'syslog', 'errorlog' and 'stdout' which will log to the system itself.
LOG_CHANNEL=dailytest
# Log level. You can set this from least severe to most severe:
# debug, info, notice, warning, error, critical, alert, emergency
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
# nothing will get logged, ever.
APP_LOG_LEVEL=debug
APP_LOG_LEVEL=info
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
# For other database types, please see the FAQ: http://firefly-iii.readthedocs.io/en/latest/support/faq.html
DB_CONNECTION=sqlite
# If you're looking for performance improvements, you could install memcached.
CACHE_DRIVER=file
@@ -64,6 +70,9 @@ MAILGUN_SECRET=
MANDRILL_SECRET=
SPARKPOST_SECRET=
# Firefly III can send you the following messages
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=false
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
MAPBOX_API_KEY=
@@ -97,7 +106,7 @@ DEMO_USERNAME=
DEMO_PASSWORD=
IS_DOCKER=false
IS_SANDSTORM=false
BUNQ_USE_SANDBOX=true
IS_HEROKU=false
BUNQ_USE_SANDBOX=true
MAILGUN_DOMAIN=
MAILGUN_SECRET=

View File

@@ -9,9 +9,16 @@ VM_NAME = File.basename(File.dirname(File.dirname(__FILE__))) + "_sandstorm_#{Ti
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
# ugly hack to prevent hashicorp's bitrot. See https://github.com/hashicorp/vagrant/issues/9442
# this setting is required for pre-2.0 vagrant, but causes an error as of 2.0.3,
# remove entirely when confident nobody uses vagrant 1.x for anything.
unless Vagrant::DEFAULT_SERVER_URL.frozen?
Vagrant::DEFAULT_SERVER_URL.replace('https://vagrantcloud.com')
end
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# Base on the Sandstorm snapshots of the official Debian 8 (jessie) box.
config.vm.box = "sandstorm/debian-jessie64"
config.vm.box = "debian/contrib-jessie64"
if Vagrant.has_plugin?("vagrant-vbguest") then
# vagrant-vbguest is a Vagrant plugin that upgrades

View File

@@ -1,3 +1,78 @@
# 4.7.6.2
- Docker file builds again.
- Fix CSS of OAuth2 authorization view.
# 4.7.6.1
- An issue where I switched variables from the Docker `.env` file to the normal `.env` file and vice versa -- breaking both.
- [Issue 1649](https://github.com/firefly-iii/firefly-iii/issues/1649) 2FA QR code would not show up due to very strict security policy headers
- Docker build gave a cURL error whenever it runs PHP commands.
# 4.7.6
- [Issue 145](https://github.com/firefly-iii/firefly-iii/issues/145) You can now download transactions from YNAB.
- [Issue 306](https://github.com/firefly-iii/firefly-iii/issues/306) You can now add liabilities to Firefly III.
- [Issue 740](https://github.com/firefly-iii/firefly-iii/issues/740) Various charts are now currency aware.
- [Issue 833](https://github.com/firefly-iii/firefly-iii/issues/833) Bills can use non-default currencies.
- [Issue 1578](https://github.com/firefly-iii/firefly-iii/issues/1578) Firefly III will notify you if the cron job hasn't fired.
- [Issue 1623](https://github.com/firefly-iii/firefly-iii/issues/1623) New transactions will link back from the success message.
- [Issue 1624](https://github.com/firefly-iii/firefly-iii/issues/1624) transactions will link to the object.
- You can call the cron job over the web now (see docs).
- You don't need to call the cron job every minute any more.
- Various charts are now red/green to signify income and expenses.
- Option to add or remove accounts from the net worth calculations.
- This will be the last release on PHP 7.1. Future versions will require PHP 7.2.
- [Issue 1460](https://github.com/firefly-iii/firefly-iii/issues/1460) Downloading transactions from bunq should go more smoothly.
- [Issue 1464](https://github.com/firefly-iii/firefly-iii/issues/1464) Fixed the docker file to work on Raspberry Pi's.
- [Issue 1540](https://github.com/firefly-iii/firefly-iii/issues/1540) The Docker file now has a working cron job for recurring transactions.
- [Issue 1564](https://github.com/firefly-iii/firefly-iii/issues/1564) Fix double transfers when importing from bunq.
- [Issue 1575](https://github.com/firefly-iii/firefly-iii/issues/1575) Some views would give a XSRF token warning
- [Issue 1576](https://github.com/firefly-iii/firefly-iii/issues/1576) Fix assigning budgets
- [Issue 1580](https://github.com/firefly-iii/firefly-iii/issues/1580) Missing string for translation
- [Issue 1581](https://github.com/firefly-iii/firefly-iii/issues/1581) Expand help text
- [Issue 1584](https://github.com/firefly-iii/firefly-iii/issues/1584) Link to administration is back.
- [Issue 1586](https://github.com/firefly-iii/firefly-iii/issues/1586) Date fields in import were mislabeled.
- [Issue 1593](https://github.com/firefly-iii/firefly-iii/issues/1593) Link types are translatable.
- [Issue 1594](https://github.com/firefly-iii/firefly-iii/issues/1594) Very long breadcrumbs are weird.
- [Issue 1598](https://github.com/firefly-iii/firefly-iii/issues/1598) Fix budget calculations.
- [Issue 1597](https://github.com/firefly-iii/firefly-iii/issues/1597) Piggy banks are always inactive.
- [Issue 1605](https://github.com/firefly-iii/firefly-iii/issues/1605) System will ignore foreign currency setting if user doesn't indicate the amount.
- [Issue 1608](https://github.com/firefly-iii/firefly-iii/issues/1608) Spelling error in command line import.
- [Issue 1609](https://github.com/firefly-iii/firefly-iii/issues/1609) Link to budgets page was absolute.
- [Issue 1615](https://github.com/firefly-iii/firefly-iii/issues/1615) Fix currency bug in transactions.
- [Issue 1616](https://github.com/firefly-iii/firefly-iii/issues/1616) Fix null pointer exception in pie charts.
- [Issue 1617](https://github.com/firefly-iii/firefly-iii/issues/1617) Fix for complex tag names in URL's.
- [Issue 1620](https://github.com/firefly-iii/firefly-iii/issues/1620) Fixed index reference in API.
- [Issue 1639](https://github.com/firefly-iii/firefly-iii/issues/1639) Firefly III trusts the Heroku load balancer, fixing deployment on Heroku.
- [Issue 1642](https://github.com/firefly-iii/firefly-iii/issues/1642) Fix issue with split journals.
- [Issue 1643](https://github.com/firefly-iii/firefly-iii/issues/1643) Fix reconciliation issue.
- Users can no longer give expenses a budget.
- Fix bug in Spectre import.
- Heroku would not make you owner.
- Add `.htaccess` files to all public directories.
- New secure headers will make Firefly III slightly more secure.
# 4.7.5.3
- [Issue 1527](https://github.com/firefly-iii/firefly-iii/issues/1527), fixed views for transactions without a budget.
- [Issue 1553](https://github.com/firefly-iii/firefly-iii/issues/1553), report could not handle transactions before the first one in the system.
- [Issue 1549](https://github.com/firefly-iii/firefly-iii/issues/1549) update a budget will also update any rules that refer to that budget.
- [Issue 1530](https://github.com/firefly-iii/firefly-iii/issues/1530), fix issue with bill chart.
- [Issue 1563](https://github.com/firefly-iii/firefly-iii/issues/1563), fix piggy bank suggested amount
- [Issue 1571](https://github.com/firefly-iii/firefly-iii/issues/1571), fix OAuth in Sandstorm
- [Issue 1568](https://github.com/firefly-iii/firefly-iii/issues/1568), bug in Sandstorm user code.
- [Issue 1569](https://github.com/firefly-iii/firefly-iii/issues/1569), optimized Sandstorm build by [ocdtrekkie](https://github.com/ocdtrekkie)
- Fixed a bug where transfers would be stored inversely when using the CSV import.
- Retired the "Rabobank description"-fix, because it is no longer necessary.
- Fixed a bug where users could not delete budget limits in the API.
- Piggy bank notes are visible again.
# 4.7.5.1
- [Issue 1531](https://github.com/firefly-iii/firefly-iii/issues/1531), the database routine incorrectly reports empty categories.
- [Issue 1532](https://github.com/firefly-iii/firefly-iii/issues/1532), broken dropdown for autosuggest things.
- [Issue 1533](https://github.com/firefly-iii/firefly-iii/issues/1533), fix where the import could not import category names.
- [Issue 1538](https://github.com/firefly-iii/firefly-iii/issues/1538), fix a bug where Spectre would not work when ignoring rules.
- [Issue 1542](https://github.com/firefly-iii/firefly-iii/issues/1542), fix a bug where the importer was incapable of generating new currencies.
- [Issue 1541](https://github.com/firefly-iii/firefly-iii/issues/1541), no longer ignore composer.lock in Docker ignore.
- Bills are stored inactive.
# 4.7.5
- A new feature called "recurring transactions" that will make Firefly III automatically create transactions for you.
- New API end points for attachments, available budgets, budgets, budget limits, categories, configuration, currency exchange rates, journal links, link types, piggy banks, preferences, recurring transactions, rules, rule groups and tags.

View File

@@ -9,6 +9,10 @@ CURL_OPTS="--silent --show-error"
echo localhost > /etc/hostname
hostname localhost
# Install curl that is needed below.
apt-get update
apt-get install -y curl
# The following line copies stderr through stderr to cat without accidentally leaving it in the
# output file. Be careful when changing. See: https://github.com/sandstorm-io/vagrant-spk/pull/159
curl $CURL_OPTS https://install.sandstorm.io/ 2>&1 > /host-dot-sandstorm/caches/install.sh | cat

View File

@@ -209,13 +209,6 @@ opt/app/.env.sandstorm
opt/app/.gitattributes
opt/app/.htaccess
opt/app/.sandstorm/.gitattributes
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/action_provision
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/action_set_name
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/creator_uid
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/id
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/index_uuid
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/private_key
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/synced_folders
opt/app/.sandstorm/.vagrant/machines/default/virtualbox/vagrant_cwd
opt/app/.sandstorm/Vagrantfile
opt/app/.sandstorm/app-graphics/firefly-iii-128.png
@@ -242,15 +235,41 @@ opt/app/LICENSE
opt/app/app.json
opt/app/app/Api/V1/Controllers/AboutController.php
opt/app/app/Api/V1/Controllers/AccountController.php
opt/app/app/Api/V1/Controllers/AttachmentController.php
opt/app/app/Api/V1/Controllers/AvailableBudgetController.php
opt/app/app/Api/V1/Controllers/BillController.php
opt/app/app/Api/V1/Controllers/BudgetController.php
opt/app/app/Api/V1/Controllers/BudgetLimitController.php
opt/app/app/Api/V1/Controllers/CategoryController.php
opt/app/app/Api/V1/Controllers/ConfigurationController.php
opt/app/app/Api/V1/Controllers/Controller.php
opt/app/app/Api/V1/Controllers/CurrencyController.php
opt/app/app/Api/V1/Controllers/CurrencyExchangeRateController.php
opt/app/app/Api/V1/Controllers/JournalLinkController.php
opt/app/app/Api/V1/Controllers/LinkTypeController.php
opt/app/app/Api/V1/Controllers/PiggyBankController.php
opt/app/app/Api/V1/Controllers/PreferenceController.php
opt/app/app/Api/V1/Controllers/RecurrenceController.php
opt/app/app/Api/V1/Controllers/RuleController.php
opt/app/app/Api/V1/Controllers/RuleGroupController.php
opt/app/app/Api/V1/Controllers/TransactionController.php
opt/app/app/Api/V1/Controllers/UserController.php
opt/app/app/Api/V1/Requests/AccountRequest.php
opt/app/app/Api/V1/Requests/AttachmentRequest.php
opt/app/app/Api/V1/Requests/AvailableBudgetRequest.php
opt/app/app/Api/V1/Requests/BillRequest.php
opt/app/app/Api/V1/Requests/BudgetLimitRequest.php
opt/app/app/Api/V1/Requests/BudgetRequest.php
opt/app/app/Api/V1/Requests/CategoryRequest.php
opt/app/app/Api/V1/Requests/CurrencyRequest.php
opt/app/app/Api/V1/Requests/JournalLinkRequest.php
opt/app/app/Api/V1/Requests/LinkTypeRequest.php
opt/app/app/Api/V1/Requests/PiggyBankRequest.php
opt/app/app/Api/V1/Requests/PreferenceRequest.php
opt/app/app/Api/V1/Requests/RecurrenceRequest.php
opt/app/app/Api/V1/Requests/Request.php
opt/app/app/Api/V1/Requests/RuleGroupRequest.php
opt/app/app/Api/V1/Requests/RuleRequest.php
opt/app/app/Api/V1/Requests/TransactionRequest.php
opt/app/app/Api/V1/Requests/UserRequest.php
opt/app/app/Console/Commands/CreateExport.php
@@ -269,6 +288,7 @@ opt/app/app/Events/AdminRequestedTestMessage.php
opt/app/app/Events/Event.php
opt/app/app/Events/RegisteredUser.php
opt/app/app/Events/RequestedNewPassword.php
opt/app/app/Events/RequestedReportOnJournals.php
opt/app/app/Events/RequestedVersionCheckStatus.php
opt/app/app/Events/StoredTransactionJournal.php
opt/app/app/Events/UpdatedTransactionJournal.php
@@ -289,11 +309,13 @@ opt/app/app/Export/Exporter/ExporterInterface.php
opt/app/app/Export/ProcessorInterface.php
opt/app/app/Factory/AccountFactory.php
opt/app/app/Factory/AccountMetaFactory.php
opt/app/app/Factory/AttachmentFactory.php
opt/app/app/Factory/BillFactory.php
opt/app/app/Factory/BudgetFactory.php
opt/app/app/Factory/CategoryFactory.php
opt/app/app/Factory/PiggyBankEventFactory.php
opt/app/app/Factory/PiggyBankFactory.php
opt/app/app/Factory/RecurrenceFactory.php
opt/app/app/Factory/TagFactory.php
opt/app/app/Factory/TransactionCurrencyFactory.php
opt/app/app/Factory/TransactionFactory.php
@@ -325,6 +347,7 @@ opt/app/app/Generator/Report/Tag/MultiYearReportGenerator.php
opt/app/app/Generator/Report/Tag/YearReportGenerator.php
opt/app/app/Handlers/Events/APIEventHandler.php
opt/app/app/Handlers/Events/AdminEventHandler.php
opt/app/app/Handlers/Events/AutomationHandler.php
opt/app/app/Handlers/Events/StoredJournalEventHandler.php
opt/app/app/Handlers/Events/UpdatedJournalEventHandler.php
opt/app/app/Handlers/Events/UserEventHandler.php
@@ -365,8 +388,13 @@ opt/app/app/Helpers/Report/PopupReport.php
opt/app/app/Helpers/Report/PopupReportInterface.php
opt/app/app/Helpers/Report/ReportHelper.php
opt/app/app/Helpers/Report/ReportHelperInterface.php
opt/app/app/Helpers/Update/UpdateTrait.php
opt/app/app/Http/Controllers/Account/CreateController.php
opt/app/app/Http/Controllers/Account/DeleteController.php
opt/app/app/Http/Controllers/Account/EditController.php
opt/app/app/Http/Controllers/Account/IndexController.php
opt/app/app/Http/Controllers/Account/ReconcileController.php
opt/app/app/Http/Controllers/AccountController.php
opt/app/app/Http/Controllers/Account/ShowController.php
opt/app/app/Http/Controllers/Admin/ConfigurationController.php
opt/app/app/Http/Controllers/Admin/HomeController.php
opt/app/app/Http/Controllers/Admin/LinkController.php
@@ -379,7 +407,14 @@ opt/app/app/Http/Controllers/Auth/RegisterController.php
opt/app/app/Http/Controllers/Auth/ResetPasswordController.php
opt/app/app/Http/Controllers/Auth/TwoFactorController.php
opt/app/app/Http/Controllers/BillController.php
opt/app/app/Http/Controllers/BudgetController.php
opt/app/app/Http/Controllers/Budget/AmountController.php
opt/app/app/Http/Controllers/Budget/CreateController.php
opt/app/app/Http/Controllers/Budget/DeleteController.php
opt/app/app/Http/Controllers/Budget/EditController.php
opt/app/app/Http/Controllers/Budget/IndexController.php
opt/app/app/Http/Controllers/Budget/ShowController.php
opt/app/app/Http/Controllers/Category/NoCategoryController.php
opt/app/app/Http/Controllers/Category/ShowController.php
opt/app/app/Http/Controllers/CategoryController.php
opt/app/app/Http/Controllers/Chart/AccountController.php
opt/app/app/Http/Controllers/Chart/BillController.php
@@ -407,12 +442,18 @@ opt/app/app/Http/Controllers/Json/BoxController.php
opt/app/app/Http/Controllers/Json/ExchangeController.php
opt/app/app/Http/Controllers/Json/FrontpageController.php
opt/app/app/Http/Controllers/Json/IntroController.php
opt/app/app/Http/Controllers/Json/ReconcileController.php
opt/app/app/Http/Controllers/Json/RecurrenceController.php
opt/app/app/Http/Controllers/JsonController.php
opt/app/app/Http/Controllers/NewUserController.php
opt/app/app/Http/Controllers/PiggyBankController.php
opt/app/app/Http/Controllers/Popup/ReportController.php
opt/app/app/Http/Controllers/PreferencesController.php
opt/app/app/Http/Controllers/ProfileController.php
opt/app/app/Http/Controllers/Recurring/CreateController.php
opt/app/app/Http/Controllers/Recurring/DeleteController.php
opt/app/app/Http/Controllers/Recurring/EditController.php
opt/app/app/Http/Controllers/Recurring/IndexController.php
opt/app/app/Http/Controllers/Report/AccountController.php
opt/app/app/Http/Controllers/Report/BalanceController.php
opt/app/app/Http/Controllers/Report/BudgetController.php
@@ -420,7 +461,11 @@ opt/app/app/Http/Controllers/Report/CategoryController.php
opt/app/app/Http/Controllers/Report/ExpenseController.php
opt/app/app/Http/Controllers/Report/OperationsController.php
opt/app/app/Http/Controllers/ReportController.php
opt/app/app/Http/Controllers/RuleController.php
opt/app/app/Http/Controllers/Rule/CreateController.php
opt/app/app/Http/Controllers/Rule/DeleteController.php
opt/app/app/Http/Controllers/Rule/EditController.php
opt/app/app/Http/Controllers/Rule/IndexController.php
opt/app/app/Http/Controllers/Rule/SelectController.php
opt/app/app/Http/Controllers/RuleGroupController.php
opt/app/app/Http/Controllers/SearchController.php
opt/app/app/Http/Controllers/System/InstallController.php
@@ -471,6 +516,7 @@ opt/app/app/Http/Requests/PiggyBankFormRequest.php
opt/app/app/Http/Requests/ProfileFormRequest.php
opt/app/app/Http/Requests/ReconciliationStoreRequest.php
opt/app/app/Http/Requests/ReconciliationUpdateRequest.php
opt/app/app/Http/Requests/RecurrenceFormRequest.php
opt/app/app/Http/Requests/ReportFormRequest.php
opt/app/app/Http/Requests/Request.php
opt/app/app/Http/Requests/RuleFormRequest.php
@@ -482,8 +528,6 @@ opt/app/app/Http/Requests/TestRuleFormRequest.php
opt/app/app/Http/Requests/TokenFormRequest.php
opt/app/app/Http/Requests/UserFormRequest.php
opt/app/app/Http/Requests/UserRegistrationRequest.php
opt/app/app/Import/Configuration/BunqConfigurator.php
opt/app/app/Import/Configuration/ConfiguratorInterface.php
opt/app/app/Import/Converter/Amount.php
opt/app/app/Import/Converter/AmountCredit.php
opt/app/app/Import/Converter/AmountDebit.php
@@ -508,12 +552,6 @@ opt/app/app/Import/Mapper/TransactionCurrencies.php
opt/app/app/Import/MapperPreProcess/PreProcessorInterface.php
opt/app/app/Import/MapperPreProcess/TagsComma.php
opt/app/app/Import/MapperPreProcess/TagsSpace.php
opt/app/app/Import/Object/ImportAccount.php
opt/app/app/Import/Object/ImportBill.php
opt/app/app/Import/Object/ImportBudget.php
opt/app/app/Import/Object/ImportCategory.php
opt/app/app/Import/Object/ImportCurrency.php
opt/app/app/Import/Object/ImportJournal.php
opt/app/app/Import/Prerequisites/BunqPrerequisites.php
opt/app/app/Import/Prerequisites/FakePrerequisites.php
opt/app/app/Import/Prerequisites/FilePrerequisites.php
@@ -531,6 +569,7 @@ opt/app/app/Import/Specifics/RabobankDescription.php
opt/app/app/Import/Specifics/SnsDescription.php
opt/app/app/Import/Specifics/SpecificInterface.php
opt/app/app/Import/Storage/ImportArrayStorage.php
opt/app/app/Jobs/CreateRecurringTransactions.php
opt/app/app/Jobs/ExecuteRuleGroupOnExistingTransactions.php
opt/app/app/Jobs/ExecuteRuleOnExistingTransactions.php
opt/app/app/Jobs/Job.php
@@ -540,6 +579,7 @@ opt/app/app/Mail/AdminTestMail.php
opt/app/app/Mail/ConfirmEmailChangeMail.php
opt/app/app/Mail/OAuthTokenCreatedMail.php
opt/app/app/Mail/RegisteredUser.php
opt/app/app/Mail/ReportNewJournalsMail.php
opt/app/app/Mail/RequestedNewPassword.php
opt/app/app/Mail/UndoEmailChangeMail.php
opt/app/app/Models/Account.php
@@ -561,6 +601,11 @@ opt/app/app/Models/PiggyBank.php
opt/app/app/Models/PiggyBankEvent.php
opt/app/app/Models/PiggyBankRepetition.php
opt/app/app/Models/Preference.php
opt/app/app/Models/Recurrence.php
opt/app/app/Models/RecurrenceMeta.php
opt/app/app/Models/RecurrenceRepetition.php
opt/app/app/Models/RecurrenceTransaction.php
opt/app/app/Models/RecurrenceTransactionMeta.php
opt/app/app/Models/Role.php
opt/app/app/Models/Rule.php
opt/app/app/Models/RuleAction.php
@@ -588,8 +633,8 @@ opt/app/app/Providers/ExportJobServiceProvider.php
opt/app/app/Providers/FireflyServiceProvider.php
opt/app/app/Providers/FireflySessionProvider.php
opt/app/app/Providers/JournalServiceProvider.php
opt/app/app/Providers/LogServiceProvider.php
opt/app/app/Providers/PiggyBankServiceProvider.php
opt/app/app/Providers/RecurringServiceProvider.php
opt/app/app/Providers/RouteServiceProvider.php
opt/app/app/Providers/RuleGroupServiceProvider.php
opt/app/app/Providers/RuleServiceProvider.php
@@ -600,7 +645,6 @@ opt/app/app/Repositories/Account/AccountRepository.php
opt/app/app/Repositories/Account/AccountRepositoryInterface.php
opt/app/app/Repositories/Account/AccountTasker.php
opt/app/app/Repositories/Account/AccountTaskerInterface.php
opt/app/app/Repositories/Account/FindAccountsTrait.php
opt/app/app/Repositories/Attachment/AttachmentRepository.php
opt/app/app/Repositories/Attachment/AttachmentRepositoryInterface.php
opt/app/app/Repositories/Bill/BillRepository.php
@@ -621,18 +665,22 @@ opt/app/app/Repositories/LinkType/LinkTypeRepository.php
opt/app/app/Repositories/LinkType/LinkTypeRepositoryInterface.php
opt/app/app/Repositories/PiggyBank/PiggyBankRepository.php
opt/app/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php
opt/app/app/Repositories/Recurring/RecurringRepository.php
opt/app/app/Repositories/Recurring/RecurringRepositoryInterface.php
opt/app/app/Repositories/Rule/RuleRepository.php
opt/app/app/Repositories/Rule/RuleRepositoryInterface.php
opt/app/app/Repositories/RuleGroup/RuleGroupRepository.php
opt/app/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php
opt/app/app/Repositories/Tag/TagRepository.php
opt/app/app/Repositories/Tag/TagRepositoryInterface.php
opt/app/app/Repositories/TransactionType/TransactionTypeRepository.php
opt/app/app/Repositories/TransactionType/TransactionTypeRepositoryInterface.php
opt/app/app/Repositories/User/UserRepository.php
opt/app/app/Repositories/User/UserRepositoryInterface.php
opt/app/app/Rules/BelongsUser.php
opt/app/app/Rules/IsAssetAccountId.php
opt/app/app/Rules/IsValidAttachmentModel.php
opt/app/app/Rules/UniqueIban.php
opt/app/app/Rules/ValidRecurrenceRepetitionType.php
opt/app/app/Rules/ValidRecurrenceRepetitionValue.php
opt/app/app/Rules/ValidTransactions.php
opt/app/app/Services/Bunq/ApiContext.php
opt/app/app/Services/Bunq/MonetaryAccount.php
@@ -650,16 +698,20 @@ opt/app/app/Services/Internal/Destroy/BillDestroyService.php
opt/app/app/Services/Internal/Destroy/CategoryDestroyService.php
opt/app/app/Services/Internal/Destroy/CurrencyDestroyService.php
opt/app/app/Services/Internal/Destroy/JournalDestroyService.php
opt/app/app/Services/Internal/Destroy/RecurrenceDestroyService.php
opt/app/app/Services/Internal/File/EncryptService.php
opt/app/app/Services/Internal/Support/AccountServiceTrait.php
opt/app/app/Services/Internal/Support/BillServiceTrait.php
opt/app/app/Services/Internal/Support/JournalServiceTrait.php
opt/app/app/Services/Internal/Support/RecurringTransactionTrait.php
opt/app/app/Services/Internal/Support/TransactionServiceTrait.php
opt/app/app/Services/Internal/Support/TransactionTypeTrait.php
opt/app/app/Services/Internal/Update/AccountUpdateService.php
opt/app/app/Services/Internal/Update/BillUpdateService.php
opt/app/app/Services/Internal/Update/CategoryUpdateService.php
opt/app/app/Services/Internal/Update/CurrencyUpdateService.php
opt/app/app/Services/Internal/Update/JournalUpdateService.php
opt/app/app/Services/Internal/Update/RecurrenceUpdateService.php
opt/app/app/Services/Internal/Update/TransactionUpdateService.php
opt/app/app/Services/Password/PwndVerifierV2.php
opt/app/app/Services/Password/Verifier.php
@@ -705,10 +757,10 @@ opt/app/app/Support/Facades/Navigation.php
opt/app/app/Support/Facades/Preferences.php
opt/app/app/Support/Facades/Steam.php
opt/app/app/Support/FireflyConfig.php
opt/app/app/Support/Import/Information/BunqInformation.php
opt/app/app/Support/Http/Controllers/DateCalculation.php
opt/app/app/Support/Http/Controllers/RuleManagement.php
opt/app/app/Support/Import/Information/GetSpectreCustomerTrait.php
opt/app/app/Support/Import/Information/GetSpectreTokenTrait.php
opt/app/app/Support/Import/Information/InformationInterface.php
opt/app/app/Support/Import/JobConfiguration/Bunq/BunqJobConfigurationInterface.php
opt/app/app/Support/Import/JobConfiguration/Bunq/ChooseAccountsHandler.php
opt/app/app/Support/Import/JobConfiguration/Bunq/NewBunqJobHandler.php
@@ -743,7 +795,6 @@ opt/app/app/Support/Import/Routine/File/OpposingAccountMapper.php
opt/app/app/Support/Import/Routine/Spectre/StageAuthenticatedHandler.php
opt/app/app/Support/Import/Routine/Spectre/StageImportDataHandler.php
opt/app/app/Support/Import/Routine/Spectre/StageNewHandler.php
opt/app/app/Support/Models/TransactionJournalTrait.php
opt/app/app/Support/Navigation.php
opt/app/app/Support/Preferences.php
opt/app/app/Support/Search/Modifier.php
@@ -759,7 +810,6 @@ opt/app/app/Support/Twig/Journal.php
opt/app/app/Support/Twig/Loader/AccountLoader.php
opt/app/app/Support/Twig/Loader/TransactionJournalLoader.php
opt/app/app/Support/Twig/Loader/TransactionLoader.php
opt/app/app/Support/Twig/PiggyBank.php
opt/app/app/Support/Twig/Rule.php
opt/app/app/Support/Twig/Transaction.php
opt/app/app/Support/Twig/Translation.php
@@ -823,18 +873,32 @@ opt/app/app/TransactionRules/Triggers/TriggerInterface.php
opt/app/app/TransactionRules/Triggers/UserAction.php
opt/app/app/Transformers/AccountTransformer.php
opt/app/app/Transformers/AttachmentTransformer.php
opt/app/app/Transformers/AvailableBudgetTransformer.php
opt/app/app/Transformers/BillTransformer.php
opt/app/app/Transformers/BudgetLimitTransformer.php
opt/app/app/Transformers/BudgetTransformer.php
opt/app/app/Transformers/CategoryTransformer.php
opt/app/app/Transformers/CurrencyExchangeRateTransformer.php
opt/app/app/Transformers/CurrencyTransformer.php
opt/app/app/Transformers/JournalLinkTransformer.php
opt/app/app/Transformers/JournalMetaTransformer.php
opt/app/app/Transformers/LinkTypeTransformer.php
opt/app/app/Transformers/NoteTransformer.php
opt/app/app/Transformers/PiggyBankEventTransformer.php
opt/app/app/Transformers/PiggyBankTransformer.php
opt/app/app/Transformers/PreferenceTransformer.php
opt/app/app/Transformers/RecurrenceTransformer.php
opt/app/app/Transformers/RuleActionTransformer.php
opt/app/app/Transformers/RuleGroupTransformer.php
opt/app/app/Transformers/RuleTransformer.php
opt/app/app/Transformers/RuleTriggerTransformer.php
opt/app/app/Transformers/TagTransformer.php
opt/app/app/Transformers/TransactionTransformer.php
opt/app/app/Transformers/UserTransformer.php
opt/app/app/User.php
opt/app/app/Validation/FireflyValidator.php
opt/app/app/Validation/RecurrenceValidation.php
opt/app/app/Validation/TransactionValidation.php
opt/app/artisan
opt/app/bootstrap/app.php
opt/app/bootstrap/cache/packages.php
@@ -842,7 +906,6 @@ opt/app/bootstrap/cache/services.php
opt/app/changelog.md
opt/app/composer.json
opt/app/composer.lock
opt/app/composer.phar
opt/app/config/app.php
opt/app/config/auth.php
opt/app/config/breadcrumbs.php
@@ -887,6 +950,7 @@ opt/app/database/migrations/2018_01_01_000005_create_oauth_personal_access_clien
opt/app/database/migrations/2018_03_19_141348_changes_for_v472.php
opt/app/database/migrations/2018_04_07_210913_changes_for_v473.php
opt/app/database/migrations/2018_04_29_174524_changes_for_v474.php
opt/app/database/migrations/2018_06_08_200526_changes_for_v475.php
opt/app/database/seeds/AccountTypeSeeder.php
opt/app/database/seeds/ConfigSeeder.php
opt/app/database/seeds/DatabaseSeeder.php
@@ -1105,6 +1169,8 @@ opt/app/public/js/ff/piggy-banks/edit.js
opt/app/public/js/ff/piggy-banks/index.js
opt/app/public/js/ff/piggy-banks/show.js
opt/app/public/js/ff/preferences/index.js
opt/app/public/js/ff/recurring/create.js
opt/app/public/js/ff/recurring/edit.js
opt/app/public/js/ff/reports/account/month.js
opt/app/public/js/ff/reports/all.js
opt/app/public/js/ff/reports/audit/all.js
@@ -1153,6 +1219,12 @@ opt/app/public/lib/adminlte/css/skins/skin-blue-light.min.css
opt/app/public/lib/adminlte/img/icons.png
opt/app/public/lib/adminlte/js/app.js
opt/app/public/lib/adminlte/js/app.min.js
opt/app/public/lib/fc/fullcalendar.css
opt/app/public/lib/fc/fullcalendar.js
opt/app/public/lib/fc/fullcalendar.min.css
opt/app/public/lib/fc/fullcalendar.min.js
opt/app/public/lib/fc/fullcalendar.print.css
opt/app/public/lib/fc/fullcalendar.print.min.css
opt/app/public/lib/intro/intro.min.js
opt/app/public/lib/intro/introjs-rtl.min.css
opt/app/public/lib/intro/introjs.min.css
@@ -1419,6 +1491,8 @@ opt/app/resources/views/demo/import/index.twig
opt/app/resources/views/demo/index.twig
opt/app/resources/views/demo/no-demo-text.twig
opt/app/resources/views/demo/piggy-banks/index.twig
opt/app/resources/views/demo/recurring/index.twig
opt/app/resources/views/demo/recurring/recurring-create.twig
opt/app/resources/views/demo/reports/index.twig
opt/app/resources/views/demo/transactions/index.twig
opt/app/resources/views/emails/access-token-created-html.twig
@@ -1441,6 +1515,8 @@ opt/app/resources/views/emails/password-html.twig
opt/app/resources/views/emails/password-text.twig
opt/app/resources/views/emails/registered-html.twig
opt/app/resources/views/emails/registered-text.twig
opt/app/resources/views/emails/report-new-journals-html.twig
opt/app/resources/views/emails/report-new-journals-text.twig
opt/app/resources/views/emails/undo-email-change-html.twig
opt/app/resources/views/emails/undo-email-change-text.twig
opt/app/resources/views/error.twig
@@ -1461,7 +1537,6 @@ opt/app/resources/views/form/file.twig
opt/app/resources/views/form/help.twig
opt/app/resources/views/form/integer.twig
opt/app/resources/views/form/location.twig
opt/app/resources/views/form/multiRadio.twig
opt/app/resources/views/form/non-selectable-amount.twig
opt/app/resources/views/form/number.twig
opt/app/resources/views/form/options.twig
@@ -1538,6 +1613,11 @@ opt/app/resources/views/profile/change-password.twig
opt/app/resources/views/profile/code.twig
opt/app/resources/views/profile/delete-account.twig
opt/app/resources/views/profile/index.twig
opt/app/resources/views/recurring/create.twig
opt/app/resources/views/recurring/delete.twig
opt/app/resources/views/recurring/edit.twig
opt/app/resources/views/recurring/index.twig
opt/app/resources/views/recurring/show.twig
opt/app/resources/views/reports/account/report.twig
opt/app/resources/views/reports/audit/report.twig
opt/app/resources/views/reports/budget/month.twig
@@ -2060,30 +2140,6 @@ opt/app/vendor/defuse/php-encryption/src/Key.php
opt/app/vendor/defuse/php-encryption/src/KeyOrPassword.php
opt/app/vendor/defuse/php-encryption/src/KeyProtectedByPassword.php
opt/app/vendor/defuse/php-encryption/src/RuntimeTests.php
opt/app/vendor/doctrine/annotations/CHANGELOG.md
opt/app/vendor/doctrine/annotations/LICENSE
opt/app/vendor/doctrine/annotations/README.md
opt/app/vendor/doctrine/annotations/composer.json
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attribute.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attributes.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Enum.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Required.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Target.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationRegistry.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/CachedReader.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocLexer.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/FileCacheReader.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/IndexedReader.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PhpParser.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Reader.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/SimpleAnnotationReader.php
opt/app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/TokenParser.php
opt/app/vendor/doctrine/annotations/phpstan.neon
opt/app/vendor/doctrine/cache/LICENSE
opt/app/vendor/doctrine/cache/README.md
opt/app/vendor/doctrine/cache/UPGRADE.md
@@ -2118,89 +2174,11 @@ opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/VoidCache.php
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/WinCacheCache.php
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/XcacheCache.php
opt/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ZendDataCache.php
opt/app/vendor/doctrine/collections/CONTRIBUTING.md
opt/app/vendor/doctrine/collections/LICENSE
opt/app/vendor/doctrine/collections/README.md
opt/app/vendor/doctrine/collections/composer.json
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Collection.php
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Criteria.php
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ExpressionBuilder.php
opt/app/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Selectable.php
opt/app/vendor/doctrine/common/LICENSE
opt/app/vendor/doctrine/common/README.md
opt/app/vendor/doctrine/common/UPGRADE_TO_2_1
opt/app/vendor/doctrine/common/UPGRADE_TO_2_2
opt/app/vendor/doctrine/common/composer.json
opt/app/vendor/doctrine/common/humbug.json.dist
opt/app/vendor/doctrine/common/lib/Doctrine/Common/ClassLoader.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/CommonException.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Comparable.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/EventArgs.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/EventManager.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/EventSubscriber.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Lexer.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/NotifyPropertyChanged.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/AbstractManagerRegistry.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ConnectionRegistry.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LifecycleEventArgs.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LoadClassMetadataEventArgs.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/ManagerEventArgs.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/OnClearEventArgs.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/PreUpdateEventArgs.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ManagerRegistry.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ClassMetadata.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ClassMetadataFactory.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/AnnotationDriver.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/DefaultFileLocator.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileDriver.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileLocator.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriver.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriverChain.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/PHPDriver.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/StaticPHPDriver.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/SymfonyFileLocator.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/MappingException.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ReflectionService.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/StaticReflectionService.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManager.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManagerAware.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManagerDecorator.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectRepository.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/PersistentObject.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Proxy.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/PropertyChangedListener.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/AbstractProxyFactory.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Autoloader.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/InvalidArgumentException.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/OutOfBoundsException.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/ProxyException.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Exception/UnexpectedValueException.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/Proxy.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyDefinition.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Proxy/ProxyGenerator.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/ClassFinderInterface.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/Psr0FindFile.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/ReflectionProviderInterface.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/RuntimePublicReflectionProperty.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionClass.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionMethod.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionParser.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionProperty.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Util/ClassUtils.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Util/Debug.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Util/Inflector.php
opt/app/vendor/doctrine/common/lib/Doctrine/Common/Version.php
opt/app/vendor/doctrine/common/phpstan.neon
opt/app/vendor/doctrine/dbal/.github/ISSUE_TEMPLATE/BC_Break.md
opt/app/vendor/doctrine/dbal/.github/ISSUE_TEMPLATE/Bug.md
opt/app/vendor/doctrine/dbal/.github/ISSUE_TEMPLATE/Feature_Request.md
opt/app/vendor/doctrine/dbal/.github/ISSUE_TEMPLATE/Support_Question.md
opt/app/vendor/doctrine/dbal/.github/PULL_REQUEST_TEMPLATE.md
opt/app/vendor/doctrine/dbal/LICENSE
opt/app/vendor/doctrine/dbal/README.md
opt/app/vendor/doctrine/dbal/SECURITY.md
@@ -2324,6 +2302,7 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/KeywordList.ph
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MariaDb102Keywords.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MsSQLKeywords.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MySQL57Keywords.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MySQL80Keywords.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MySQLKeywords.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/OracleKeywords.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL100Keywords.php
@@ -2343,6 +2322,7 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLServerKeywo
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLiteKeywords.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MariaDb1027Platform.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySQL57Platform.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySQL80Platform.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/OraclePlatform.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL100Platform.php
@@ -2367,7 +2347,6 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/CompositeExpress
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryBuilder.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryException.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/README.markdown
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtils.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtilsException.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractAsset.php
@@ -2421,6 +2400,7 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWor
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Dumper.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/TransactionIsolationLevel.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ArrayType.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BigIntType.php
@@ -2455,6 +2435,16 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/VarDateTimeImmutableType.ph
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/VarDateTimeType.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Version.php
opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/VersionAwarePlatformDriver.php
opt/app/vendor/doctrine/dbal/phpstan.neon.dist
opt/app/vendor/doctrine/event-manager/LICENSE
opt/app/vendor/doctrine/event-manager/README.md
opt/app/vendor/doctrine/event-manager/composer.json
opt/app/vendor/doctrine/event-manager/docs/en/index.rst
opt/app/vendor/doctrine/event-manager/docs/en/reference/index.rst
opt/app/vendor/doctrine/event-manager/docs/en/sidebar.rst
opt/app/vendor/doctrine/event-manager/lib/Doctrine/Common/EventArgs.php
opt/app/vendor/doctrine/event-manager/lib/Doctrine/Common/EventManager.php
opt/app/vendor/doctrine/event-manager/lib/Doctrine/Common/EventSubscriber.php
opt/app/vendor/doctrine/inflector/LICENSE
opt/app/vendor/doctrine/inflector/README.md
opt/app/vendor/doctrine/inflector/composer.json
@@ -2904,6 +2894,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/Refr
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/ResetCommand.php
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/RollbackCommand.php
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/StatusCommand.php
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/TableGuesser.php
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Seeds/SeedCommand.php
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Seeds/SeederMakeCommand.php
opt/app/vendor/laravel/framework/src/Illuminate/Database/Console/Seeds/stubs/seeder.stub
@@ -3176,6 +3167,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/WithoutMiddle
opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Validation/ValidatesRequests.php
opt/app/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php
opt/app/vendor/laravel/framework/src/Illuminate/Foundation/stubs/facade.stub
opt/app/vendor/laravel/framework/src/Illuminate/Hashing/AbstractHasher.php
opt/app/vendor/laravel/framework/src/Illuminate/Hashing/ArgonHasher.php
opt/app/vendor/laravel/framework/src/Illuminate/Hashing/BcryptHasher.php
opt/app/vendor/laravel/framework/src/Illuminate/Hashing/HashManager.php
@@ -3383,6 +3375,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Redis/composer.json
opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/ControllerMakeCommand.php
opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/MiddlewareMakeCommand.php
opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.api.stub
opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.invokable.stub
opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.model.api.stub
opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.model.stub
opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.nested.api.stub
@@ -4432,9 +4425,6 @@ opt/app/vendor/ramsey/uuid/CONTRIBUTING.md
opt/app/vendor/ramsey/uuid/LICENSE
opt/app/vendor/ramsey/uuid/README.md
opt/app/vendor/ramsey/uuid/composer.json
opt/app/vendor/ramsey/uuid/docs/Makefile
opt/app/vendor/ramsey/uuid/docs/conf.py
opt/app/vendor/ramsey/uuid/docs/index.rst
opt/app/vendor/ramsey/uuid/src/BinaryUtils.php
opt/app/vendor/ramsey/uuid/src/Builder/DefaultUuidBuilder.php
opt/app/vendor/ramsey/uuid/src/Builder/DegradedUuidBuilder.php
@@ -4532,6 +4522,10 @@ opt/app/vendor/swiftmailer/swiftmailer/doc/messages.rst
opt/app/vendor/swiftmailer/swiftmailer/doc/plugins.rst
opt/app/vendor/swiftmailer/swiftmailer/doc/sending.rst
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder/IdnAddressEncoder.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder/Utf8AddressEncoder.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoderException.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Attachment.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php
@@ -4594,6 +4588,7 @@ opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.ph
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NullContentEncoder.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php
@@ -4670,6 +4665,8 @@ opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/Pl
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/EightBitMimeHandler.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/SmtpUtf8Handler.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpHandler.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php
opt/app/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php
@@ -6327,6 +6324,7 @@ opt/app/vendor/symfony/var-dumper/Resources/bin/var-dump-server
opt/app/vendor/symfony/var-dumper/Resources/css/htmlDescriptor.css
opt/app/vendor/symfony/var-dumper/Resources/functions/dump.php
opt/app/vendor/symfony/var-dumper/Resources/js/htmlDescriptor.js
opt/app/vendor/symfony/var-dumper/Server/Connection.php
opt/app/vendor/symfony/var-dumper/Server/DumpServer.php
opt/app/vendor/symfony/var-dumper/Test/VarDumperTestTrait.php
opt/app/vendor/symfony/var-dumper/Tests/Caster/CasterTest.php
@@ -6351,6 +6349,7 @@ opt/app/vendor/symfony/var-dumper/Tests/Fixtures/Twig.php
opt/app/vendor/symfony/var-dumper/Tests/Fixtures/dumb-var.php
opt/app/vendor/symfony/var-dumper/Tests/Fixtures/dump_server.php
opt/app/vendor/symfony/var-dumper/Tests/Fixtures/xml_reader.xml
opt/app/vendor/symfony/var-dumper/Tests/Server/ConnectionTest.php
opt/app/vendor/symfony/var-dumper/Tests/Test/VarDumperTestTraitTest.php
opt/app/vendor/symfony/var-dumper/VarDumper.php
opt/app/vendor/symfony/var-dumper/composer.json
@@ -7259,6 +7258,14 @@ opt/app/vendor/zendframework/zend-diactoros/src/ServerRequestFactory.php
opt/app/vendor/zendframework/zend-diactoros/src/Stream.php
opt/app/vendor/zendframework/zend-diactoros/src/UploadedFile.php
opt/app/vendor/zendframework/zend-diactoros/src/Uri.php
opt/app/vendor/zendframework/zend-diactoros/src/functions/create_uploaded_file.php
opt/app/vendor/zendframework/zend-diactoros/src/functions/marshal_headers_from_sapi.php
opt/app/vendor/zendframework/zend-diactoros/src/functions/marshal_method_from_sapi.php
opt/app/vendor/zendframework/zend-diactoros/src/functions/marshal_protocol_version_from_sapi.php
opt/app/vendor/zendframework/zend-diactoros/src/functions/marshal_uri_from_sapi.php
opt/app/vendor/zendframework/zend-diactoros/src/functions/normalize_server.php
opt/app/vendor/zendframework/zend-diactoros/src/functions/normalize_uploaded_files.php
opt/app/vendor/zendframework/zend-diactoros/src/functions/parse_cookie_header.php
proc/cpuinfo
sandstorm-http-bridge
sandstorm-http-bridge-config
@@ -7433,14 +7440,17 @@ usr/share/zoneinfo/Africa/Libreville
usr/share/zoneinfo/Africa/Lome
usr/share/zoneinfo/Africa/Luanda
usr/share/zoneinfo/Africa/Lubumbashi
usr/share/zoneinfo/Africa/Lusaka
usr/share/zoneinfo/Africa/Malabo
usr/share/zoneinfo/Africa/Maputo
usr/share/zoneinfo/Africa/Maseru
usr/share/zoneinfo/Africa/Mbabane
usr/share/zoneinfo/Africa/Mogadishu
usr/share/zoneinfo/Africa/Nairobi
usr/share/zoneinfo/Africa/Niamey
usr/share/zoneinfo/Africa/Nouakchott
usr/share/zoneinfo/Africa/Ouagadougou
usr/share/zoneinfo/Africa/Porto-Novo
usr/share/zoneinfo/Africa/Sao_Tome
usr/share/zoneinfo/Africa/Timbuktu
usr/share/zoneinfo/Africa/Tripoli
@@ -7459,7 +7469,9 @@ usr/share/zoneinfo/America/Argentina/Mendoza
usr/share/zoneinfo/America/Aruba
usr/share/zoneinfo/America/Atikokan
usr/share/zoneinfo/America/Atka
usr/share/zoneinfo/America/Cayman
usr/share/zoneinfo/America/Chicago
usr/share/zoneinfo/America/Coral_Harbour
usr/share/zoneinfo/America/Cordoba
usr/share/zoneinfo/America/Curacao
usr/share/zoneinfo/America/Denver
@@ -7480,6 +7492,7 @@ usr/share/zoneinfo/America/Jamaica
usr/share/zoneinfo/America/Kentucky
usr/share/zoneinfo/America/Kentucky/Louisville
usr/share/zoneinfo/America/Knox_IN
usr/share/zoneinfo/America/Kralendijk
usr/share/zoneinfo/America/Los_Angeles
usr/share/zoneinfo/America/Lower_Princes
usr/share/zoneinfo/America/Manaus
@@ -7498,6 +7511,7 @@ usr/share/zoneinfo/America/Porto_Acre
usr/share/zoneinfo/America/Puerto_Rico
usr/share/zoneinfo/America/Regina
usr/share/zoneinfo/America/Rio_Branco
usr/share/zoneinfo/America/Santa_Isabel
usr/share/zoneinfo/America/Santiago
usr/share/zoneinfo/America/Sao_Paulo
usr/share/zoneinfo/America/Shiprock
@@ -7511,6 +7525,7 @@ usr/share/zoneinfo/America/Tijuana
usr/share/zoneinfo/America/Toronto
usr/share/zoneinfo/America/Tortola
usr/share/zoneinfo/America/Vancouver
usr/share/zoneinfo/America/Virgin
usr/share/zoneinfo/America/Whitehorse
usr/share/zoneinfo/America/Winnipeg
usr/share/zoneinfo/Antarctica
@@ -7521,8 +7536,10 @@ usr/share/zoneinfo/Asia
usr/share/zoneinfo/Asia/Aden
usr/share/zoneinfo/Asia/Ashgabat
usr/share/zoneinfo/Asia/Bangkok
usr/share/zoneinfo/Asia/Calcutta
usr/share/zoneinfo/Asia/Chongqing
usr/share/zoneinfo/Asia/Chungking
usr/share/zoneinfo/Asia/Dacca
usr/share/zoneinfo/Asia/Dhaka
usr/share/zoneinfo/Asia/Dubai
usr/share/zoneinfo/Asia/Harbin
@@ -7530,24 +7547,31 @@ usr/share/zoneinfo/Asia/Ho_Chi_Minh
usr/share/zoneinfo/Asia/Hong_Kong
usr/share/zoneinfo/Asia/Istanbul
usr/share/zoneinfo/Asia/Jerusalem
usr/share/zoneinfo/Asia/Kashgar
usr/share/zoneinfo/Asia/Kathmandu
usr/share/zoneinfo/Asia/Katmandu
usr/share/zoneinfo/Asia/Kolkata
usr/share/zoneinfo/Asia/Macao
usr/share/zoneinfo/Asia/Macau
usr/share/zoneinfo/Asia/Makassar
usr/share/zoneinfo/Asia/Nicosia
usr/share/zoneinfo/Asia/Phnom_Penh
usr/share/zoneinfo/Asia/Qatar
usr/share/zoneinfo/Asia/Riyadh
usr/share/zoneinfo/Asia/Saigon
usr/share/zoneinfo/Asia/Seoul
usr/share/zoneinfo/Asia/Shanghai
usr/share/zoneinfo/Asia/Singapore
usr/share/zoneinfo/Asia/Taipei
usr/share/zoneinfo/Asia/Tehran
usr/share/zoneinfo/Asia/Tel_Aviv
usr/share/zoneinfo/Asia/Thimbu
usr/share/zoneinfo/Asia/Thimphu
usr/share/zoneinfo/Asia/Tokyo
usr/share/zoneinfo/Asia/Ulaanbaatar
usr/share/zoneinfo/Asia/Ulan_Bator
usr/share/zoneinfo/Asia/Urumqi
usr/share/zoneinfo/Asia/Yangon
usr/share/zoneinfo/Atlantic
usr/share/zoneinfo/Atlantic/Faroe
usr/share/zoneinfo/Atlantic/Jan_Mayen
@@ -7560,16 +7584,21 @@ usr/share/zoneinfo/Australia/Broken_Hill
usr/share/zoneinfo/Australia/Canberra
usr/share/zoneinfo/Australia/Darwin
usr/share/zoneinfo/Australia/Hobart
usr/share/zoneinfo/Australia/LHI
usr/share/zoneinfo/Australia/Lord_Howe
usr/share/zoneinfo/Australia/Melbourne
usr/share/zoneinfo/Australia/NSW
usr/share/zoneinfo/Australia/North
usr/share/zoneinfo/Australia/Perth
usr/share/zoneinfo/Australia/Queensland
usr/share/zoneinfo/Australia/Sydney
usr/share/zoneinfo/Australia/West
usr/share/zoneinfo/Brazil
usr/share/zoneinfo/Canada
usr/share/zoneinfo/Canada/Atlantic
usr/share/zoneinfo/Canada/East-Saskatchewan
usr/share/zoneinfo/Canada/Saskatchewan
usr/share/zoneinfo/Chile
usr/share/zoneinfo/Chile/EasterIsland
usr/share/zoneinfo/Etc
usr/share/zoneinfo/Etc/GMT
usr/share/zoneinfo/Etc/GMT+0
@@ -7583,6 +7612,7 @@ usr/share/zoneinfo/Etc/Zulu
usr/share/zoneinfo/Europe
usr/share/zoneinfo/Europe/Belfast
usr/share/zoneinfo/Europe/Belgrade
usr/share/zoneinfo/Europe/Bratislava
usr/share/zoneinfo/Europe/Busingen
usr/share/zoneinfo/Europe/Chisinau
usr/share/zoneinfo/Europe/Dublin
@@ -7594,25 +7624,37 @@ usr/share/zoneinfo/Europe/Jersey
usr/share/zoneinfo/Europe/Lisbon
usr/share/zoneinfo/Europe/Ljubljana
usr/share/zoneinfo/Europe/London
usr/share/zoneinfo/Europe/Mariehamn
usr/share/zoneinfo/Europe/Moscow
usr/share/zoneinfo/Europe/Nicosia
usr/share/zoneinfo/Europe/Oslo
usr/share/zoneinfo/Europe/Podgorica
usr/share/zoneinfo/Europe/Prague
usr/share/zoneinfo/Europe/Rome
usr/share/zoneinfo/Europe/San_Marino
usr/share/zoneinfo/Europe/Sarajevo
usr/share/zoneinfo/Europe/Skopje
usr/share/zoneinfo/Europe/Tiraspol
usr/share/zoneinfo/Europe/Vaduz
usr/share/zoneinfo/Europe/Vatican
usr/share/zoneinfo/Europe/Warsaw
usr/share/zoneinfo/Europe/Zagreb
usr/share/zoneinfo/Europe/Zurich
usr/share/zoneinfo/GB
usr/share/zoneinfo/GB-Eire
usr/share/zoneinfo/GMT
usr/share/zoneinfo/GMT+0
usr/share/zoneinfo/GMT-0
usr/share/zoneinfo/GMT0
usr/share/zoneinfo/Greenwich
usr/share/zoneinfo/Indian
usr/share/zoneinfo/Indian/Antananarivo
usr/share/zoneinfo/Indian/Comoro
usr/share/zoneinfo/Indian/Mayotte
usr/share/zoneinfo/Mexico
usr/share/zoneinfo/Mexico/BajaNorte
usr/share/zoneinfo/Mexico/BajaSur
usr/share/zoneinfo/Mexico/General
usr/share/zoneinfo/Pacific
usr/share/zoneinfo/Pacific/Auckland
usr/share/zoneinfo/Pacific/Chatham
@@ -7629,18 +7671,35 @@ usr/share/zoneinfo/Pacific/Pitcairn
usr/share/zoneinfo/Pacific/Pohnpei
usr/share/zoneinfo/Pacific/Samoa
usr/share/zoneinfo/Pacific/Truk
usr/share/zoneinfo/Pacific/Yap
usr/share/zoneinfo/SystemV
usr/share/zoneinfo/SystemV/AST4
usr/share/zoneinfo/SystemV/AST4ADT
usr/share/zoneinfo/SystemV/CST6
usr/share/zoneinfo/SystemV/CST6CDT
usr/share/zoneinfo/SystemV/EST5
usr/share/zoneinfo/SystemV/EST5EDT
usr/share/zoneinfo/SystemV/HST10
usr/share/zoneinfo/SystemV/MST7
usr/share/zoneinfo/SystemV/MST7MDT
usr/share/zoneinfo/SystemV/PST8
usr/share/zoneinfo/SystemV/PST8PDT
usr/share/zoneinfo/SystemV/YST9
usr/share/zoneinfo/SystemV/YST9YDT
usr/share/zoneinfo/US
usr/share/zoneinfo/US/Alaska
usr/share/zoneinfo/US/Aleutian
usr/share/zoneinfo/US/Arizona
usr/share/zoneinfo/US/Central
usr/share/zoneinfo/US/East-Indiana
usr/share/zoneinfo/US/Eastern
usr/share/zoneinfo/US/Hawaii
usr/share/zoneinfo/US/Indiana-Starke
usr/share/zoneinfo/US/Michigan
usr/share/zoneinfo/US/Mountain
usr/share/zoneinfo/US/Pacific
usr/share/zoneinfo/US/Pacific-New
usr/share/zoneinfo/US/Samoa
usr/share/zoneinfo/UTC
usr/share/zoneinfo/Universal
usr/share/zoneinfo/Zulu

View File

@@ -15,8 +15,8 @@ const pkgdef :Spk.PackageDefinition = (
manifest = (
appTitle = (defaultText = "Firefly III"),
appVersion = 14,
appMarketingVersion = (defaultText = "4.7.5"),
appVersion = 16,
appMarketingVersion = (defaultText = "4.7.6.2"),
actions = [
# Define your "new document" handlers here.

View File

@@ -14,10 +14,7 @@ apt-get install -y python-software-properties software-properties-common
# install all languages
sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# es_ES.UTF-8 UTF-8/es_ES.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# fr_FR.UTF-8 UTF-8/fr_FR.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# id_ID.UTF-8 UTF-8/id_ID.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# it_IT.UTF-8 UTF-8/it_IT.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# nl_NL.UTF-8 UTF-8/nl_NL.UTF-8 UTF-8/g' /etc/locale.gen
sed -i 's/# pl_PL.UTF-8 UTF-8/pl_PL.UTF-8 UTF-8/g' /etc/locale.gen
@@ -35,7 +32,7 @@ apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E9C74FEEA2098A6E
add-apt-repository "deb http://packages.dotdeb.org jessie all"
# add another repos
apt-get install apt-transport-https lsb-release ca-certificates
apt-get install -y apt-transport-https lsb-release ca-certificates
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list

View File

@@ -1,12 +1,16 @@
# use PHP 7.1 and Apache as a base.
FROM php:7.1-apache
# set working dir
ENV FIREFLY_PATH /var/www/firefly-iii
# If building on a RPi, use --build-arg cores=3 to use all cores when compiling
# to speed up the image build
ARG CORES
ENV CORES ${CORES:-1}
ENV FIREFLY_PATH /var/www/firefly-iii/
ENV CURL_VERSION 7.60.0
ENV OPENSSL_VERSION 1.1.1-pre6
WORKDIR $FIREFLY_PATH
ADD . $FIREFLY_PATH
LABEL version="1.0" maintainer="thegrumpydictator@gmail.com"
# install packages
RUN apt-get update -y && \
@@ -19,47 +23,60 @@ RUN apt-get update -y && \
libedit-dev \
libtidy-dev \
libxml2-dev \
unzip \
libsqlite3-dev \
nano \
libpq-dev \
libbz2-dev \
gettext-base \
cron \
rsyslog \
supervisor \
locales && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Setup the Composer installer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Install latest curl
RUN cd /tmp && \
wget https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz && \
tar -xvf openssl-${OPENSSL_VERSION}.tar.gz && \
cd openssl-${OPENSSL_VERSION} && \
./config && \
make && \
make -j${CORES} && \
make install
RUN cd /tmp && \
wget https://curl.haxx.se/download/curl-${CURL_VERSION}.tar.gz && \
tar -xvf curl-${CURL_VERSION}.tar.gz && \
cd curl-${CURL_VERSION} && \
./configure --with-ssl && \
make && \
./configure --with-ssl --host=$(gcc -dumpmachine) && \
make -j${CORES} && \
make install
# Make sure that libcurl is using the newer curl libaries
RUN echo "/usr/local/lib" >> /etc/ld.so.conf.d/00-curl.conf && ldconfig
# Create the log file to be able to run tail
RUN touch /var/log/cron.log
# Mimic the Debian/Ubuntu config file structure for supervisor
COPY .deploy/docker/supervisord.conf /etc/supervisor/supervisord.conf
RUN mkdir -p /etc/supervisor/conf.d /var/log/supervisor
# Setup cron job
RUN (crontab -l ; echo "* * * * * root $FIREFLY_PATH/artisan schedule:run >> /var/log/cron.log") | crontab
# copy Firefly III supervisor conf file.
COPY ./.deploy/docker/firefly-iii.conf /etc/supervisor/conf.d/firefly-iii.conf
# copy cron job supervisor conf file.
COPY ./.deploy/docker/cronjob.conf /etc/supervisor/conf.d/cronjob.conf
# test crons added via crontab
RUN echo "0 3 * * * /usr/local/bin/php /var/www/firefly-iii/artisan firefly:cron" | crontab -
#RUN (crontab -l ; echo "*/1 * * * * free >> /var/www/firefly-iii/public/cron.html") 2>&1 | crontab -
# Install PHP exentions.
RUN docker-php-ext-install -j$(nproc) curl gd intl json readline tidy zip bcmath xml mbstring pdo_sqlite pdo_mysql bz2 pdo_pgsql
RUN docker-php-ext-install -j$(nproc) gd intl tidy zip bcmath pdo_mysql bz2 pdo_pgsql
# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Generate locales supported by Firefly III
RUN echo "de_DE.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\nes_ES.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nid_ID.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8pt_BR.UTF-8 UTF-8ru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\n\n" > /etc/locale.gen && locale-gen
RUN echo "en_US.UTF-8 UTF-8\nde_DE.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8\npt_BR.UTF-8 UTF-8\nru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\n\n" > /etc/locale.gen && locale-gen
# copy Apache config to correct spot.
COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf
@@ -70,7 +87,7 @@ RUN a2enmod rewrite
# Enable apache mod ssl..
RUN a2enmod ssl
# Create volumes for several directories:
# Create volumes
VOLUME $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload
# Enable default site (Firefly III)
@@ -79,15 +96,19 @@ COPY ./.deploy/docker/apache-firefly.conf /etc/apache2/sites-available/000-defau
# Make sure we own Firefly III directory
RUN chown -R www-data:www-data /var/www && chmod -R 775 $FIREFLY_PATH/storage
# Copy in Firefly Source
WORKDIR $FIREFLY_PATH
ADD . $FIREFLY_PATH
# Fix the link to curl:
RUN rm -rf /usr/local/lib/libcurl.so.4 && ln -s /usr/lib/x86_64-linux-gnu/libcurl.so.4.4.0 /usr/local/lib/libcurl.so.4
# Run composer
ENV COMPOSER_ALLOW_SUPERUSER 1
RUN composer install --prefer-dist --no-dev --no-scripts --no-suggest
# Expose port 80
EXPOSE 80
# Run the command on container startup
CMD cron
# Run entrypoint thing
ENTRYPOINT [".deploy/docker/entrypoint.sh"]

View File

@@ -35,7 +35,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
/**
* Returns basic information about this installation.
*
* Class AboutController
* Class AboutController.
*/
class AboutController extends Controller
{

View File

@@ -1,5 +1,4 @@
<?php
/**
* AccountController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -41,13 +40,15 @@ use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class AccountController
* Class AccountController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class AccountController extends Controller
{
/** @var CurrencyRepositoryInterface */
/** @var CurrencyRepositoryInterface The currency repository */
private $currencyRepository;
/** @var AccountRepositoryInterface */
/** @var AccountRepositoryInterface The account repository */
private $repository;
/**
@@ -125,6 +126,8 @@ class AccountController extends Controller
}
/**
* Show single instance.
*
* @param Request $request
* @param Account $account
*
@@ -146,6 +149,8 @@ class AccountController extends Controller
}
/**
* Store a new instance.
*
* @param AccountRequest $request
*
* @return \Illuminate\Http\JsonResponse
@@ -197,52 +202,30 @@ class AccountController extends Controller
}
/**
* All the available types.
*
* @param string $type
*
* @return array
*/
private function mapTypes(string $type): array
{
$types = [
'all' => [
AccountType::DEFAULT,
AccountType::CASH,
AccountType::ASSET,
AccountType::EXPENSE,
AccountType::REVENUE,
AccountType::INITIAL_BALANCE,
AccountType::BENEFICIARY,
AccountType::IMPORT,
AccountType::RECONCILIATION,
AccountType::LOAN,
],
'asset' => [
AccountType::DEFAULT,
AccountType::ASSET,
],
'cash' => [
AccountType::CASH,
],
'expense' => [
AccountType::EXPENSE,
AccountType::BENEFICIARY,
],
'revenue' => [
AccountType::REVENUE,
],
'special' => [
AccountType::CASH,
AccountType::INITIAL_BALANCE,
AccountType::IMPORT,
AccountType::RECONCILIATION,
AccountType::LOAN,
],
'hidden' => [
AccountType::INITIAL_BALANCE,
AccountType::IMPORT,
AccountType::RECONCILIATION,
AccountType::LOAN,
],
$types = [
'all' => [AccountType::DEFAULT, AccountType::CASH, AccountType::ASSET, AccountType::EXPENSE, AccountType::REVENUE,
AccountType::INITIAL_BALANCE, AccountType::BENEFICIARY, AccountType::IMPORT, AccountType::RECONCILIATION,
AccountType::LOAN,],
'asset' => [AccountType::DEFAULT, AccountType::ASSET,],
'cash' => [AccountType::CASH,],
'expense' => [AccountType::EXPENSE, AccountType::BENEFICIARY,],
'revenue' => [AccountType::REVENUE,],
'special' => [AccountType::CASH, AccountType::INITIAL_BALANCE, AccountType::IMPORT, AccountType::RECONCILIATION,
AccountType::LOAN,],
'hidden' => [AccountType::INITIAL_BALANCE, AccountType::IMPORT, AccountType::RECONCILIATION, AccountType::LOAN,],
'liability' => [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD],
'liabilities' => [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD],
'cc' => [AccountType::CREDITCARD],
'creditcard' => [AccountType::CREDITCARD],
'credit_card' => [AccountType::CREDITCARD],
AccountType::DEFAULT => [AccountType::DEFAULT],
AccountType::CASH => [AccountType::CASH],
AccountType::ASSET => [AccountType::ASSET],
@@ -253,11 +236,16 @@ class AccountController extends Controller
AccountType::IMPORT => [AccountType::IMPORT],
AccountType::RECONCILIATION => [AccountType::RECONCILIATION],
AccountType::LOAN => [AccountType::LOAN],
AccountType::MORTGAGE => [AccountType::MORTGAGE],
AccountType::DEBT => [AccountType::DEBT],
AccountType::CREDITCARD => [AccountType::CREDITCARD],
];
$return = $types['all'];
if (isset($types[$type])) {
return $types[$type];
$return = $types[$type];
}
return $types['all']; // @codeCoverageIgnore
return $return; // @codeCoverageIgnore
}
}

View File

@@ -41,11 +41,13 @@ use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class AttachmentController
* Class AttachmentController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class AttachmentController extends Controller
{
/** @var AttachmentRepositoryInterface */
/** @var AttachmentRepositoryInterface The attachment repository */
private $repository;
/**
@@ -81,6 +83,8 @@ class AttachmentController extends Controller
}
/**
* Download an attachment.
*
* @param Attachment $attachment
*
* @return LaravelResponse
@@ -88,7 +92,7 @@ class AttachmentController extends Controller
*/
public function download(Attachment $attachment): LaravelResponse
{
if ($attachment->uploaded === false) {
if (false === $attachment->uploaded) {
throw new FireflyException('No file has been uploaded for this attachment (yet).');
}
if ($this->repository->exists($attachment)) {
@@ -211,6 +215,8 @@ class AttachmentController extends Controller
}
/**
* Upload an attachment.
*
* @param Request $request
* @param Attachment $attachment
*
@@ -226,4 +232,4 @@ class AttachmentController extends Controller
return response()->json([], 204);
}
}
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\AvailableBudgetRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
@@ -39,13 +40,15 @@ use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class AvailableBudgetController
* Class AvailableBudgetController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class AvailableBudgetController extends Controller
{
/** @var CurrencyRepositoryInterface */
/** @var CurrencyRepositoryInterface The currency repository */
private $currencyRepository;
/** @var BudgetRepositoryInterface */
/** @var BudgetRepositoryInterface The budget repository */
private $repository;
/**
@@ -144,11 +147,18 @@ class AvailableBudgetController extends Controller
* @param AvailableBudgetRequest $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function store(AvailableBudgetRequest $request): JsonResponse
{
$data = $request->getAll();
$currency = $this->currencyRepository->findNull($data['transaction_currency_id']);
$data = $request->getAll();
$currency = $this->currencyRepository->findNull($data['currency_id']);
if (null === $currency) {
$currency = $this->currencyRepository->findByCodeNull($data['currency_code']);
}
if (null === $currency) {
throw new FireflyException('Could not find the indicated currency.');
}
$availableBudget = $this->repository->setAvailableBudget($currency, $data['start_date'], $data['end_date'], $data['amount']);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
@@ -159,6 +169,8 @@ class AvailableBudgetController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update the specified resource in storage.
*
@@ -180,4 +192,4 @@ class AvailableBudgetController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}
}

View File

@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Transformers\BillTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
@@ -39,11 +40,11 @@ use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class BillController
* Class BillController.
*/
class BillController extends Controller
{
/** @var BillRepositoryInterface */
/** @var BillRepositoryInterface The bill repository */
private $repository;
/**
@@ -54,9 +55,12 @@ class BillController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var BillRepositoryInterface repository */
$this->repository = app(BillRepositoryInterface::class);
$this->repository->setUser(auth()->user());
$this->repository->setUser($admin);
return $next($request);
}
@@ -103,6 +107,8 @@ class BillController extends Controller
/**
* Show the specified bill.
*
* @param Request $request
* @param Bill $bill
*
@@ -124,6 +130,8 @@ class BillController extends Controller
}
/**
* Store a bill.
*
* @param BillRequest $request
*
* @return JsonResponse
@@ -147,6 +155,8 @@ class BillController extends Controller
/**
* Update a bill.
*
* @param BillRequest $request
* @param Bill $bill
*

View File

@@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Transformers\BudgetTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
@@ -38,11 +39,13 @@ use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class BudgetController
* Class BudgetController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class BudgetController extends Controller
{
/** @var BudgetRepositoryInterface */
/** @var BudgetRepositoryInterface The budget repository */
private $repository;
/**
@@ -53,9 +56,12 @@ class BudgetController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var BudgetRepositoryInterface repository */
$this->repository = app(BudgetRepositoryInterface::class);
$this->repository->setUser(auth()->user());
$this->repository->setUser($admin);
return $next($request);
}
@@ -111,6 +117,8 @@ class BudgetController extends Controller
/**
* Show a budget.
*
* @param Request $request
* @param Budget $budget
*
@@ -132,6 +140,8 @@ class BudgetController extends Controller
}
/**
* Store a budget.
*
* @param BudgetRequest $request
*
* @return JsonResponse
@@ -154,6 +164,8 @@ class BudgetController extends Controller
/**
* Update a budget.
*
* @param BudgetRequest $request
* @param Budget $budget
*
@@ -173,4 +185,4 @@ class BudgetController extends Controller
}
}
}

View File

@@ -23,9 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use Carbon\Carbon;
use Exception;
use FireflyIII\Api\V1\Requests\AvailableBudgetRequest;
use FireflyIII\Api\V1\Requests\BudgetLimitRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\BudgetLimit;
@@ -36,23 +34,21 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use InvalidArgumentException;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
use Log;
use Throwable;
/**
* Class BudgetLimitController
* Class BudgetLimitController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class BudgetLimitController extends Controller
{
///** @var CurrencyRepositoryInterface */
//private $currencyRepository;
/** @var BudgetRepositoryInterface */
/** @var BudgetRepositoryInterface The budget repository */
private $repository;
/**
@@ -66,7 +62,6 @@ class BudgetLimitController extends Controller
/** @var User $user */
$user = auth()->user();
$this->repository = app(BudgetRepositoryInterface::class);
//$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
@@ -97,56 +92,26 @@ class BudgetLimitController extends Controller
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// read budget from request
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$budgetId = (int)($request->get('budget_id') ?? 0);
$budget = null;
if ($budgetId > 0) {
$budget = $this->repository->findNull($budgetId);
}
// read start date from request
$start = null;
try {
$start = Carbon::createFromFormat('Y-m-d', $request->get('start'));
$this->parameters->set('start', $start->format('Y-m-d'));
} catch (InvalidArgumentException $e) {
Log::debug(sprintf('Could not parse start date "%s": %s', $request->get('start'), $e->getMessage()));
}
// read end date from request
$end = null;
try {
$end = Carbon::createFromFormat('Y-m-d', $request->get('end'));
$this->parameters->set('end', $end->format('Y-m-d'));
} catch (InvalidArgumentException $e) {
Log::debug(sprintf('Could not parse end date "%s": %s', $request->get('end'), $e->getMessage()));
}
$budget = $this->repository->findNull($budgetId);
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$this->parameters->set('budget_id', $budgetId);
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budget limits. Count it and split it.
$collection = new Collection;
if (null === $budget) {
$collection = $this->repository->getAllBudgetLimits($start, $end);
$collection = $this->repository->getAllBudgetLimits($this->parameters->get('start'), $this->parameters->get('end'));
}
if (null !== $budget) {
$collection = $this->repository->getBudgetLimits($budget, $start, $end);
$collection = $this->repository->getBudgetLimits($budget, $this->parameters->get('start'), $this->parameters->get('end'));
}
$count = $collection->count();
$budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.budget_limits.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($budgetLimits, new BudgetLimitTransformer($this->parameters), 'budget_limits');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
@@ -206,8 +171,8 @@ class BudgetLimitController extends Controller
/**
* Update the specified resource in storage.
*
* @param AvailableBudgetRequest $request
* @param BudgetLimit $budgetLimit
* @param BudgetLimitRequest $request
* @param BudgetLimit $budgetLimit
*
* @return JsonResponse
*/
@@ -229,4 +194,4 @@ class BudgetLimitController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}
}

View File

@@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Transformers\CategoryTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
@@ -38,11 +39,13 @@ use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class CategoryController
* Class CategoryController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class CategoryController extends Controller
{
/** @var CategoryRepositoryInterface */
/** @var CategoryRepositoryInterface The category repository */
private $repository;
/**
@@ -53,9 +56,12 @@ class CategoryController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var CategoryRepositoryInterface repository */
$this->repository = app(CategoryRepositoryInterface::class);
$this->repository->setUser(auth()->user());
$this->repository->setUser($admin);
return $next($request);
}
@@ -111,6 +117,8 @@ class CategoryController extends Controller
/**
* Show the category.
*
* @param Request $request
* @param Category $category
*
@@ -132,6 +140,8 @@ class CategoryController extends Controller
}
/**
* Store new category.
*
* @param CategoryRequest $request
*
* @return JsonResponse
@@ -154,6 +164,8 @@ class CategoryController extends Controller
/**
* Update the category.
*
* @param CategoryRequest $request
* @param Category $category
*
@@ -173,4 +185,4 @@ class CategoryController extends Controller
}
}
}

View File

@@ -25,39 +25,67 @@ namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Configuration;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
/**
* Class ConfigurationController
* Class ConfigurationController.
*/
class ConfigurationController extends Controller
{
/** @var UserRepositoryInterface The user repository */
private $repository;
/**
* @throws FireflyException
* BudgetController constructor.
*/
public function index()
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @noinspection UnusedConstructorDependenciesInspection */
$this->repository = app(UserRepositoryInterface::class);
/** @var User $admin */
$admin = auth()->user();
if (!$this->repository->hasRole($admin, 'owner')) {
/** @noinspection ExceptionsAnnotatingAndHandlingInspection */
throw new FireflyException('No access to method.'); // @codeCoverageIgnore
}
return $next($request);
}
);
}
/**
* Show all configuration.
*
* @return JsonResponse
*/
public function index(): JsonResponse
{
if (!auth()->user()->hasRole('owner')) {
throw new FireflyException('No access to method.'); // @codeCoverageIgnore
}
$configData = $this->getConfigData();
return response()->json(['data' => $configData], 200)->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update the configuration.
*
* @param Request $request
*
* @return JsonResponse
* @throws FireflyException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function update(Request $request): JsonResponse
{
if (!auth()->user()->hasRole('owner')) {
throw new FireflyException('No access to method.'); // @codeCoverageIgnore
}
$name = $request->get('name');
$value = $request->get('value');
$valid = ['is_demo_site', 'permission_update_check', 'single_user_mode'];
@@ -68,7 +96,7 @@ class ConfigurationController extends Controller
switch ($name) {
case 'is_demo_site':
case 'single_user_mode':
$configValue = $value === 'true';
$configValue = 'true' === $value;
break;
case 'permission_update_check':
$configValue = (int)$value >= -1 && (int)$value <= 1 ? (int)$value : -1;
@@ -81,7 +109,10 @@ class ConfigurationController extends Controller
}
/**
* Get all config values.
*
* @return array
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
private function getConfigData(): array
{
@@ -102,4 +133,4 @@ class ConfigurationController extends Controller
return $data;
}
}
}

View File

@@ -37,12 +37,13 @@ use Symfony\Component\HttpFoundation\ParameterBag;
* Class Controller.
*
* @codeCoverageIgnore
* @SuppressWarnings(PHPMD.NumberOfChildren)
*/
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
/** @var ParameterBag */
/** @var ParameterBag Parameters from the URI are stored here. */
protected $parameters;
/**
@@ -56,39 +57,42 @@ class Controller extends BaseController
}
/**
* Method to help build URI's.
*
* @return string
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function buildParams(): string
{
$return = '?';
$params = [];
foreach ($this->parameters as $key => $value) {
if ($key === 'page') {
if ('page' === $key) {
continue;
}
if ($value instanceof Carbon) {
$params[$key] = $value->format('Y-m-d');
continue;
}
if (!$value instanceof Carbon) {
$params[$key] = $value;
}
$params[$key] = $value;
}
$return .= http_build_query($params);
if (\strlen($return) === 1) {
return '';
}
return $return;
}
/**
* Method to grab all parameters from the URI.
*
* @return ParameterBag
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
private function getParameters(): ParameterBag
{
$bag = new ParameterBag;
$page = (int)request()->get('page');
if ($page === 0) {
if (0 === $page) {
$page = 1;
}
$bag->set('page', $page);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Transformers\CurrencyTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
@@ -40,29 +41,32 @@ use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class CurrencyController
* Class CurrencyController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class CurrencyController extends Controller
{
/** @var CurrencyRepositoryInterface */
/** @var CurrencyRepositoryInterface The currency repository */
private $repository;
/** @var UserRepositoryInterface */
/** @var UserRepositoryInterface The user repository */
private $userRepository;
/**
* CurrencyRepository constructor.
*
* @throws FireflyException
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var CurrencyRepositoryInterface repository */
$this->repository = app(CurrencyRepositoryInterface::class);
$this->userRepository = app(UserRepositoryInterface::class);
$this->repository->setUser(auth()->user());
$this->repository->setUser($admin);
return $next($request);
}
@@ -79,7 +83,10 @@ class CurrencyController extends Controller
*/
public function delete(TransactionCurrency $currency): JsonResponse
{
if (!$this->userRepository->hasRole(auth()->user(), 'owner')) {
/** @var User $admin */
$admin = auth()->user();
if (!$this->userRepository->hasRole($admin, 'owner')) {
// access denied:
throw new FireflyException('No access to method, user is not owner.'); // @codeCoverageIgnore
}
@@ -123,6 +130,8 @@ class CurrencyController extends Controller
/**
* Show a currency.
*
* @param Request $request
* @param TransactionCurrency $currency
*
@@ -146,6 +155,8 @@ class CurrencyController extends Controller
}
/**
* Store new currency.
*
* @param CurrencyRequest $request
*
* @return JsonResponse
@@ -155,11 +166,11 @@ class CurrencyController extends Controller
{
$currency = $this->repository->store($request->getAll());
if ($request->boolean('default') === true) {
app('preferences')->set('currencyPreference', $currency->code);
app('preferences')->mark();
}
if (null !== $currency) {
if (true === $request->boolean('default')) {
app('preferences')->set('currencyPreference', $currency->code);
app('preferences')->mark();
}
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
@@ -176,6 +187,8 @@ class CurrencyController extends Controller
/**
* Update a currency.
*
* @param CurrencyRequest $request
* @param TransactionCurrency $currency
*
@@ -186,7 +199,7 @@ class CurrencyController extends Controller
$data = $request->getAll();
$currency = $this->repository->update($currency, $data);
if ($request->boolean('default') === true) {
if (true === $request->boolean('default')) {
app('preferences')->set('currencyPreference', $currency->code);
app('preferences')->mark();
}

View File

@@ -28,20 +28,19 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Services\Currency\ExchangeRateInterface;
use FireflyIII\Transformers\CurrencyExchangeRateTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use InvalidArgumentException;
use League\Fractal\Manager;
use League\Fractal\Resource\Item;
use Log;
use League\Fractal\Serializer\JsonApiSerializer;
/**
*
* Class CurrencyExchangeRateController
*/
class CurrencyExchangeRateController extends Controller
{
/** @var CurrencyRepositoryInterface */
/** @var CurrencyRepositoryInterface The currency repository */
private $repository;
/**
@@ -52,8 +51,11 @@ class CurrencyExchangeRateController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
$this->repository = app(CurrencyRepositoryInterface::class);
$this->repository->setUser(auth()->user());
$this->repository->setUser($admin);
return $next($request);
}
@@ -62,6 +64,8 @@ class CurrencyExchangeRateController extends Controller
}
/**
* Show an exchange rate.
*
* @param Request $request
*
* @return JsonResponse
@@ -72,8 +76,8 @@ class CurrencyExchangeRateController extends Controller
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// currencies
$fromCurrency = $this->repository->findByCodeNull($request->get('from') ?? 'EUR');
$toCurrency = $this->repository->findByCodeNull($request->get('to') ?? 'USD');
@@ -84,27 +88,19 @@ class CurrencyExchangeRateController extends Controller
throw new FireflyException('Unknown destination currency.');
}
$dateObj = new Carbon;
try {
$dateObj = Carbon::createFromFormat('Y-m-d', $request->get('date') ?? date('Y-m-d'));
} catch (InvalidArgumentException $e) {
Log::debug($e->getMessage());
}
$dateObj = Carbon::createFromFormat('Y-m-d', $request->get('date') ?? date('Y-m-d'));
$this->parameters->set('from', $fromCurrency->code);
$this->parameters->set('to', $toCurrency->code);
$this->parameters->set('date', $dateObj->format('Y-m-d'));
// get the exchange rate.
$rate = $this->repository->getExchangeRate($fromCurrency, $toCurrency, $dateObj);
if (null === $rate) {
/** @var User $admin */
$admin = auth()->user();
// create service:
/** @var ExchangeRateInterface $service */
$service = app(ExchangeRateInterface::class);
$service->setUser(auth()->user());
// get rate:
$service->setUser($admin);
$rate = $service->getRate($fromCurrency, $toCurrency, $dateObj);
}
@@ -112,4 +108,4 @@ class CurrencyExchangeRateController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}
}

View File

@@ -39,13 +39,21 @@ use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class JournalLinkController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class JournalLinkController extends Controller
{
/** @var JournalRepositoryInterface */
/** @var JournalRepositoryInterface The journal repository */
private $journalRepository;
/** @var LinkTypeRepositoryInterface */
/** @var LinkTypeRepositoryInterface The link type repository */
private $repository;
/**
* JournalLinkController constructor.
*/
public function __construct()
{
parent::__construct();
@@ -167,14 +175,15 @@ class JournalLinkController extends Controller
$data['direction'] = 'inward';
$journalLink = $this->repository->storeLink($data, $inward, $outward);
$resource = new Item($journalLink, new JournalLinkTransformer($this->parameters), 'journal_links');
$resource = new Item($journalLink, new JournalLinkTransformer($this->parameters), 'journal_links');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update object.
*
* @param JournalLinkRequest $request
* @param TransactionJournalLink $journalLink
*
@@ -204,4 +213,4 @@ class JournalLinkController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}
}

View File

@@ -40,17 +40,21 @@ use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class LinkTypeController.
*
* Class LinkTypeController
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class LinkTypeController extends Controller
{
/** @var LinkTypeRepositoryInterface */
/** @var LinkTypeRepositoryInterface The link type repository */
private $repository;
/** @var UserRepositoryInterface */
/** @var UserRepositoryInterface The user repository */
private $userRepository;
/**
* LinkTypeController constructor.
*/
public function __construct()
{
parent::__construct();
@@ -77,7 +81,7 @@ class LinkTypeController extends Controller
*/
public function delete(LinkType $linkType): JsonResponse
{
if ($linkType->editable === false) {
if (false === $linkType->editable) {
throw new FireflyException(sprintf('You cannot delete this link type (#%d, "%s")', $linkType->id, $linkType->name));
}
$this->repository->destroy($linkType, null);
@@ -151,7 +155,10 @@ class LinkTypeController extends Controller
*/
public function store(LinkTypeRequest $request): JsonResponse
{
if (!$this->userRepository->hasRole(auth()->user(), 'owner')) {
/** @var User $admin */
$admin = auth()->user();
if (!$this->userRepository->hasRole($admin, 'owner')) {
throw new FireflyException('You need the "owner"-role to do this.');
}
$data = $request->getAll();
@@ -168,6 +175,8 @@ class LinkTypeController extends Controller
}
/**
* Update object.
*
* @param LinkTypeRequest $request
* @param LinkType $linkType
*
@@ -176,10 +185,14 @@ class LinkTypeController extends Controller
*/
public function update(LinkTypeRequest $request, LinkType $linkType): JsonResponse
{
if ($linkType->editable === false) {
if (false === $linkType->editable) {
throw new FireflyException(sprintf('You cannot edit this link type (#%d, "%s")', $linkType->id, $linkType->name));
}
if (!$this->userRepository->hasRole(auth()->user(), 'owner')) {
/** @var User $admin */
$admin = auth()->user();
if (!$this->userRepository->hasRole($admin, 'owner')) {
throw new FireflyException('You need the "owner"-role to do this.');
}
@@ -194,4 +207,4 @@ class LinkTypeController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}
}

View File

@@ -39,24 +39,30 @@ use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* TODO order up and down.
* Class PiggyBankController
* Class PiggyBankController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class PiggyBankController extends Controller
{
/** @var PiggyBankRepositoryInterface */
/** @var PiggyBankRepositoryInterface The piggy bank repository */
private $repository;
/**
* PiggyBankController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
/** @var User $admin */
$admin = auth()->user();
$this->repository = app(PiggyBankRepositoryInterface::class);
$this->repository->setUser($admin);
return $next($request);
}
@@ -155,11 +161,13 @@ class PiggyBankController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
throw new FireflyException('Could not store new piggy bank.'); // @codeCoverageIgnore
throw new FireflyException('Could not store new piggy bank.');
}
/**
* Update piggy bank.
*
* @param PiggyBankRequest $request
* @param PiggyBank $piggyBank
*
@@ -177,4 +185,4 @@ class PiggyBankController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}
}

View File

@@ -34,7 +34,6 @@ use League\Fractal\Manager;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
use Preferences;
/**
*
@@ -42,20 +41,6 @@ use Preferences;
*/
class PreferenceController extends Controller
{
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
// todo add local repositories.
return $next($request);
}
);
}
/**
* List all of them.
*
@@ -74,7 +59,7 @@ class PreferenceController extends Controller
];
$preferences = new Collection;
foreach ($available as $name) {
$pref = Preferences::getForUser($user, $name);
$pref = app('preferences')->getForUser($user, $name);
if (null !== $pref) {
$preferences->push($pref);
}
@@ -116,10 +101,13 @@ class PreferenceController extends Controller
}
/**
* Update a preference.
*
* @param PreferenceRequest $request
* @param Preference $preference
*
* @return JsonResponse
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function update(PreferenceRequest $request, Preference $preference): JsonResponse
{
@@ -138,10 +126,10 @@ class PreferenceController extends Controller
break;
case 'customFiscalYear':
case 'twoFactorAuthEnabled':
$newValue = (int)$data['data'] === 1;
$newValue = 1 === (int)$data['data'];
break;
}
$result = Preferences::set($preference->name, $newValue);
$result = app('preferences')->set($preference->name, $newValue);
// create some objects:
$manager = new Manager;
@@ -154,4 +142,4 @@ class PreferenceController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}
}

View File

@@ -38,14 +38,16 @@ use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
*
* Class RecurrenceController
*/
class RecurrenceController extends Controller
{
/** @var RecurringRepositoryInterface */
/** @var RecurringRepositoryInterface The recurring transaction repository */
private $repository;
/**
* RecurrenceController constructor.
*/
public function __construct()
{
parent::__construct();
@@ -155,6 +157,8 @@ class RecurrenceController extends Controller
}
/**
* Update single recurrence.
*
* @param RecurrenceRequest $request
* @param Recurrence $recurrence
*
@@ -163,9 +167,6 @@ class RecurrenceController extends Controller
public function update(RecurrenceRequest $request, Recurrence $recurrence): JsonResponse
{
$data = $request->getAll();
//
$category = $this->repository->update($recurrence, $data);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
@@ -176,4 +177,4 @@ class RecurrenceController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}
}

View File

@@ -42,9 +42,12 @@ use League\Fractal\Serializer\JsonApiSerializer;
*/
class RuleController extends Controller
{
/** @var RuleRepositoryInterface */
/** @var RuleRepositoryInterface The rule repository */
private $ruleRepository;
/**
* RuleController constructor.
*/
public function __construct()
{
parent::__construct();
@@ -98,7 +101,7 @@ class RuleController extends Controller
// make paginator:
$paginator = new LengthAwarePaginator($rules, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.piggy_banks.index') . $this->buildParams());
$paginator->setPath(route('api.v1.rules.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
@@ -136,7 +139,7 @@ class RuleController extends Controller
/**
* Store new object.
*
* @param Request $request
* @param RuleRequest $request
*
* @return JsonResponse
*/
@@ -153,6 +156,8 @@ class RuleController extends Controller
}
/**
* Update a rule.
*
* @param RuleRequest $request
* @param Rule $rule
*
@@ -160,9 +165,9 @@ class RuleController extends Controller
*/
public function update(RuleRequest $request, Rule $rule): JsonResponse
{
$rule = $this->ruleRepository->update($rule, $request->getAll());
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$rule = $this->ruleRepository->update($rule, $request->getAll());
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($rule, new RuleTransformer($this->parameters), 'rules');
@@ -170,4 +175,4 @@ class RuleController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}
}

View File

@@ -38,11 +38,17 @@ use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class RuleGroupController
*/
class RuleGroupController extends Controller
{
/** @var RuleGroupRepositoryInterface */
/** @var RuleGroupRepositoryInterface The rule group repository */
private $ruleGroupRepository;
/**
* RuleGroupController constructor.
*/
public function __construct()
{
parent::__construct();
@@ -62,7 +68,7 @@ class RuleGroupController extends Controller
/**
* Delete the resource.
*
* @param string $object
* @param RuleGroup $ruleGroup
*
* @return JsonResponse
*/
@@ -89,7 +95,7 @@ class RuleGroupController extends Controller
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
// get list of rule groups. Count it and split it.
$collection = $this->ruleGroupRepository->get();
$count = $collection->count();
$ruleGroups = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
@@ -151,8 +157,10 @@ class RuleGroupController extends Controller
}
/**
* @param Request $request
* @param string $object
* Update a rule group.
*
* @param RuleGroupRequest $request
* @param RuleGroup $ruleGroup
*
* @return JsonResponse
*/
@@ -168,4 +176,4 @@ class RuleGroupController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}
}

View File

@@ -25,7 +25,8 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\TransactionRequest;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
@@ -33,36 +34,39 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Transformers\TransactionTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Serializer\JsonApiSerializer;
use Log;
/**
* Class TransactionController
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class TransactionController extends Controller
{
/** @var JournalRepositoryInterface */
/** @var JournalRepositoryInterface The journal repository */
private $repository;
/**
* TransactionController constructor.
*
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var JournalRepositoryInterface repository */
$this->repository = app(JournalRepositoryInterface::class);
$this->repository->setUser(auth()->user());
$this->repository->setUser($admin);
return $next($request);
}
@@ -74,9 +78,9 @@ class TransactionController extends Controller
*
* @param \FireflyIII\Models\Transaction $transaction
*
* @return \Illuminate\Http\Response
* @return JsonResponse
*/
public function delete(Transaction $transaction)
public function delete(Transaction $transaction): JsonResponse
{
$journal = $transaction->transactionJournal;
$this->repository->destroy($journal);
@@ -85,33 +89,32 @@ class TransactionController extends Controller
}
/**
* Show all transactions.
*
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function index(Request $request)
public function index(Request $request): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// read type from URI
$type = $request->get('type') ?? 'default';
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
// types to get, page size:
$types = $this->mapTypes($this->parameters->get('type'));
$types = $this->mapTypes($this->parameters->get('type'));
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// collect transactions using the journal collector
$collector = app(JournalCollectorInterface::class);
$collector->setUser(auth()->user());
/** @var User $admin */
$admin = auth()->user();
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($admin);
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
$collector->setAllAssetAccounts();
// remove internal transfer filter:
if (\in_array(TransactionType::TRANSFER, $types)) {
if (\in_array(TransactionType::TRANSFER, $types, true)) {
$collector->removeFilter(InternalTransferFilter::class);
}
@@ -120,11 +123,10 @@ class TransactionController extends Controller
}
$collector->setLimit($pageSize)->setPage($this->parameters->get('page'));
$collector->setTypes($types);
$paginator = $collector->getPaginatedJournals();
$paginator = $collector->getPaginatedTransactions();
$paginator->setPath(route('api.v1.transactions.index') . $this->buildParams());
$transactions = $paginator->getCollection();
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
@@ -133,13 +135,15 @@ class TransactionController extends Controller
/**
* Show a single transaction.
*
* @param Request $request
* @param Transaction $transaction
* @param string $include
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function show(Request $request, Transaction $transaction, string $include = null)
public function show(Request $request, Transaction $transaction, string $include = null): JsonResponse
{
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
@@ -151,7 +155,7 @@ class TransactionController extends Controller
$manager->parseIncludes($include);
// collect transactions using the journal collector
$collector = app(JournalCollectorInterface::class);
$collector = app(TransactionCollectorInterface::class);
$collector->setUser(auth()->user());
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
// filter on specific journals.
@@ -166,20 +170,23 @@ class TransactionController extends Controller
$collector->addFilter(NegativeAmountFilter::class);
}
$transactions = $collector->getJournals();
$transactions = $collector->getTransactions();
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Store a new transaction.
*
* @param TransactionRequest $request
*
* @param JournalRepositoryInterface $repository
*
* @return \Illuminate\Http\JsonResponse
* @throws FireflyException
* @return JsonResponse
*/
public function store(TransactionRequest $request, JournalRepositoryInterface $repository)
public function store(TransactionRequest $request, JournalRepositoryInterface $repository): JsonResponse
{
$data = $request->getAll();
$data['user'] = auth()->user()->id;
@@ -194,7 +201,7 @@ class TransactionController extends Controller
$manager->parseIncludes($include);
// collect transactions using the journal collector
$collector = app(JournalCollectorInterface::class);
$collector = app(TransactionCollectorInterface::class);
$collector->setUser(auth()->user());
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
// filter on specific journals.
@@ -209,7 +216,7 @@ class TransactionController extends Controller
$collector->addFilter(NegativeAmountFilter::class);
}
$transactions = $collector->getJournals();
$transactions = $collector->getTransactions();
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -217,23 +224,21 @@ class TransactionController extends Controller
/**
* Update a transaction.
*
* @param TransactionRequest $request
* @param JournalRepositoryInterface $repository
* @param Transaction $transaction
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function update(TransactionRequest $request, JournalRepositoryInterface $repository, Transaction $transaction)
public function update(TransactionRequest $request, JournalRepositoryInterface $repository, Transaction $transaction): JsonResponse
{
$data = $request->getAll();
$data['user'] = auth()->user()->id;
Log::debug('Inside transaction update');
$journal = $repository->update($transaction->transactionJournal, $data);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$journal = $repository->update($transaction->transactionJournal, $data);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// add include parameter:
@@ -242,7 +247,7 @@ class TransactionController extends Controller
// needs a lot of extra data to match the journal collector. Or just expand that one.
// collect transactions using the journal collector
$collector = app(JournalCollectorInterface::class);
$collector = app(TransactionCollectorInterface::class);
$collector->setUser(auth()->user());
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
// filter on specific journals.
@@ -257,7 +262,7 @@ class TransactionController extends Controller
$collector->addFilter(NegativeAmountFilter::class);
}
$transactions = $collector->getJournals();
$transactions = $collector->getTransactions();
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters), 'transactions');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
@@ -265,72 +270,38 @@ class TransactionController extends Controller
}
/**
* All the types you can request.
*
* @param string $type
*
* @return array
*/
private function mapTypes(string $type): array
{
$types = [
'all' => [
TransactionType::WITHDRAWAL,
TransactionType::DEPOSIT,
TransactionType::TRANSFER,
TransactionType::OPENING_BALANCE,
TransactionType::RECONCILIATION,
],
'withdrawal' => [
TransactionType::WITHDRAWAL,
],
'withdrawals' => [
TransactionType::WITHDRAWAL,
],
'expense' => [
TransactionType::WITHDRAWAL,
],
'income' => [
TransactionType::DEPOSIT,
],
'deposit' => [
TransactionType::DEPOSIT,
],
'deposits' => [
TransactionType::DEPOSIT,
],
'transfer' => [
TransactionType::TRANSFER,
],
'transfers' => [
TransactionType::TRANSFER,
],
'opening_balance' => [
TransactionType::OPENING_BALANCE,
],
'reconciliation' => [
TransactionType::RECONCILIATION,
],
'reconciliations' => [
TransactionType::RECONCILIATION,
],
'special' => [
TransactionType::OPENING_BALANCE,
TransactionType::RECONCILIATION,
],
'specials' => [
TransactionType::OPENING_BALANCE,
TransactionType::RECONCILIATION,
],
'default' => [
TransactionType::WITHDRAWAL,
TransactionType::DEPOSIT,
TransactionType::TRANSFER,
],
$types = [
'all' => [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE,
TransactionType::RECONCILIATION,],
'withdrawal' => [TransactionType::WITHDRAWAL,],
'withdrawals' => [TransactionType::WITHDRAWAL,],
'expense' => [TransactionType::WITHDRAWAL,],
'income' => [TransactionType::DEPOSIT,],
'deposit' => [TransactionType::DEPOSIT,],
'deposits' => [TransactionType::DEPOSIT,],
'transfer' => [TransactionType::TRANSFER,],
'transfers' => [TransactionType::TRANSFER,],
'opening_balance' => [TransactionType::OPENING_BALANCE,],
'reconciliation' => [TransactionType::RECONCILIATION,],
'reconciliations' => [TransactionType::RECONCILIATION,],
'special' => [TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,],
'specials' => [TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,],
'default' => [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER,],
];
$return = $types['default'];
if (isset($types[$type])) {
return $types[$type];
$return = $types[$type];
}
return $types['default']; // @codeCoverageIgnore
return $return;
}
}

View File

@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Transformers\UserTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
@@ -39,18 +40,18 @@ use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class UserController
* Class UserController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class UserController extends Controller
{
/** @var UserRepositoryInterface */
/** @var UserRepositoryInterface The user repository */
private $repository;
/**
* UserController constructor.
*
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function __construct()
{
@@ -70,12 +71,14 @@ class UserController extends Controller
*
* @param \FireflyIII\User $user
*
* @return \Illuminate\Http\Response
* @return JsonResponse
* @throws FireflyException
*/
public function delete(User $user)
public function delete(User $user): JsonResponse
{
if (auth()->user()->hasRole('owner')) {
/** @var User $admin */
$admin = auth()->user();
if ($this->repository->hasRole($admin, 'owner')) {
$this->repository->destroy($user);
return response()->json([], 204);
@@ -88,9 +91,9 @@ class UserController extends Controller
*
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function index(Request $request)
public function index(Request $request): JsonResponse
{
// user preferences
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
@@ -117,12 +120,14 @@ class UserController extends Controller
}
/**
* Show a single user.
*
* @param Request $request
* @param User $user
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function show(Request $request, User $user)
public function show(Request $request, User $user): JsonResponse
{
// make manager
$manager = new Manager();
@@ -140,11 +145,13 @@ class UserController extends Controller
}
/**
* Store a new user.
*
* @param UserRequest $request
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function store(UserRequest $request)
public function store(UserRequest $request): JsonResponse
{
$data = $request->getAll();
$user = $this->repository->store($data);
@@ -165,12 +172,14 @@ class UserController extends Controller
}
/**
* Update a user.
*
* @param UserRequest $request
* @param User $user
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function update(UserRequest $request, User $user)
public function update(UserRequest $request, User $user): JsonResponse
{
$data = $request->getAll();
$user = $this->repository->update($user, $data);

View File

@@ -23,7 +23,6 @@
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
/**
* Class AccountRequest
*/
@@ -31,6 +30,8 @@ class AccountRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -40,6 +41,8 @@ class AccountRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -47,6 +50,7 @@ class AccountRequest extends Request
$data = [
'name' => $this->string('name'),
'active' => $this->boolean('active'),
'include_net_worth' => $this->boolean('include_net_worth'),
'accountType' => $this->string('type'),
'account_type_id' => null,
'currency_id' => $this->integer('currency_id'),
@@ -61,12 +65,28 @@ class AccountRequest extends Request
'ccType' => $this->string('cc_type'),
'ccMonthlyPaymentDate' => $this->string('cc_monthly_payment_date'),
'notes' => $this->string('notes'),
'interest' => $this->string('interest'),
'interest_period' => $this->string('interest_period'),
];
// new fields for liabilities
// 'liability_type' => $this->string('liability_type'),
// 'liability_start_date' => $this->date('liability_start_date'),
//];
if ('liability' === $data['accountType']) {
$data['openingBalance'] = bcmul($this->string('liability_amount'), '-1');
$data['openingBalanceDate'] = $this->date('liability_start_date');
$data['accountType'] = $this->string('liability_type');
$data['account_type_id'] = null;
}
return $data;
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
@@ -86,10 +106,18 @@ class AccountRequest extends Request
'account_number' => 'between:1,255|nullable|uniqueAccountNumberForUser',
'account_role' => 'in:' . $accountRoles . '|required_if:type,asset',
'active' => 'required|boolean',
'include_net_worth' => 'required|boolean',
'cc_type' => 'in:' . $ccPaymentTypes . '|required_if:account_role,ccAsset',
'cc_monthly_payment_date' => 'date' . '|required_if:account_role,ccAsset|required_if:cc_type,monthlyFull',
'type' => 'required|in:' . $types,
'notes' => 'min:0|max:65536',
// required fields for liabilities:
'liability_type' => 'required_if:type,liability|in:loan,debt,mortgage,credit card',
'liability_amount' => 'required_if:type,liability|min:0|numeric',
'liability_start_date' => 'required_if:type,liability|date',
'interest' => 'required_if:type,liability|between:0,100|numeric',
'interest_period' => 'required_if:type,liability|in:daily,monthly,yearly',
];
switch ($this->method()) {
default:

View File

@@ -26,7 +26,6 @@ namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Models\Bill;
use FireflyIII\Models\ImportJob;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Rules\IsBase64;
use FireflyIII\Rules\IsValidAttachmentModel;
/**
@@ -35,6 +34,8 @@ use FireflyIII\Rules\IsValidAttachmentModel;
class AttachmentRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -44,6 +45,8 @@ class AttachmentRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -58,6 +61,8 @@ class AttachmentRequest extends Request
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
@@ -89,4 +94,4 @@ class AttachmentRequest extends Request
return $rules;
}
}
}

View File

@@ -29,6 +29,8 @@ namespace FireflyIII\Api\V1\Requests;
class AvailableBudgetRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -38,32 +40,38 @@ class AvailableBudgetRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
{
return [
'transaction_currency_id' => $this->integer('transaction_currency_id'),
'amount' => $this->string('amount'),
'start_date' => $this->date('start_date'),
'end_date' => $this->date('end_date'),
'currency_id' => $this->integer('currency_id'),
'currency_code' => $this->string('currency_code'),
'amount' => $this->string('amount'),
'start_date' => $this->date('start_date'),
'end_date' => $this->date('end_date'),
];
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
$rules = [
'transaction_currency_id' => 'required|numeric|exists:transaction_currencies,id',
'amount' => 'required|numeric|more:0',
'start_date' => 'required|date|before:end_date',
'end_date' => 'required|date|after:start_date',
'currency_id' => 'numeric|exists:transaction_currencies,id|required_without:currency_code',
'currency_code' => 'min:3|max:3|exists:transaction_currencies,code|required_without:currency_id',
'amount' => 'required|numeric|more:0',
'start_date' => 'required|date|before:end_date',
'end_date' => 'required|date|after:start_date',
];
return $rules;
}
}
}

View File

@@ -33,6 +33,8 @@ class BillRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -42,6 +44,8 @@ class BillRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -64,6 +68,8 @@ class BillRequest extends Request
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
@@ -109,7 +115,7 @@ class BillRequest extends Request
$min = (float)($data['amount_min'] ?? 0);
$max = (float)($data['amount_max'] ?? 0);
if ($min > $max) {
$validator->errors()->add('amount_min', trans('validation.amount_min_over_max'));
$validator->errors()->add('amount_min', (string)trans('validation.amount_min_over_max'));
}
}
);

View File

@@ -30,6 +30,8 @@ namespace FireflyIII\Api\V1\Requests;
class BudgetLimitRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -39,6 +41,8 @@ class BudgetLimitRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -52,6 +56,8 @@ class BudgetLimitRequest extends Request
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
@@ -74,4 +80,4 @@ class BudgetLimitRequest extends Request
return $rules;
}
}
}

View File

@@ -31,6 +31,8 @@ use FireflyIII\Models\Budget;
class BudgetRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -40,6 +42,8 @@ class BudgetRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -52,6 +56,8 @@ class BudgetRequest extends Request
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
@@ -73,4 +79,4 @@ class BudgetRequest extends Request
return $rules;
}
}
}

View File

@@ -31,6 +31,8 @@ use FireflyIII\Models\Category;
class CategoryRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -40,6 +42,8 @@ class CategoryRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -51,6 +55,8 @@ class CategoryRequest extends Request
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
@@ -72,4 +78,4 @@ class CategoryRequest extends Request
return $rules;
}
}
}

View File

@@ -30,6 +30,8 @@ namespace FireflyIII\Api\V1\Requests;
class CurrencyRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -39,6 +41,8 @@ class CurrencyRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -53,6 +57,8 @@ class CurrencyRequest extends Request
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
@@ -62,7 +68,7 @@ class CurrencyRequest extends Request
'code' => 'required|between:3,3|unique:transaction_currencies,code',
'symbol' => 'required|between:1,5|unique:transaction_currencies,symbol',
'decimal_places' => 'required|between:0,20|numeric|min:0|max:20',
'default' => 'in:true,false',
'default' => 'boolean',
];
switch ($this->method()) {

View File

@@ -23,6 +23,9 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
use Illuminate\Validation\Validator;
/**
*
@@ -31,6 +34,8 @@ namespace FireflyIII\Api\V1\Requests;
class JournalLinkRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -40,29 +45,87 @@ class JournalLinkRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
{
return [
'link_type_id' => $this->integer('link_type_id'),
'inward_id' => $this->integer('inward_id'),
'outward_id' => $this->integer('outward_id'),
'notes' => $this->string('notes'),
'link_type_id' => $this->integer('link_type_id'),
'link_type_name' => $this->string('link_type_name'),
'inward_id' => $this->integer('inward_id'),
'outward_id' => $this->integer('outward_id'),
'notes' => $this->string('notes'),
];
}
/**
*
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
return [
'link_type_id' => 'required|exists:link_types,id',
'inward_id' => 'required|belongsToUser:transaction_journals,id',
'outward_id' => 'required|belongsToUser:transaction_journals,id',
'notes' => 'between:0,65000',
'link_type_id' => 'exists:link_types,id|required_without:link_type_name',
'link_type_name' => 'exists:link_types,name|required_without:link_type_id',
'inward_id' => 'required|belongsToUser:transaction_journals,id',
'outward_id' => 'required|belongsToUser:transaction_journals,id',
'notes' => 'between:0,65000',
];
}
}
/**
* Configure the validator instance.
*
* @param Validator $validator
*
* @return void
*/
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator) {
$this->validateExistingLink($validator);
}
);
}
/**
* @param Validator $validator
*/
private function validateExistingLink(Validator $validator): void
{
/** @var LinkTypeRepositoryInterface $repository */
$repository = app(LinkTypeRepositoryInterface::class);
$repository->setUser(auth()->user());
/** @var JournalRepositoryInterface $journalRepos */
$journalRepos = app(JournalRepositoryInterface::class);
$journalRepos->setUser(auth()->user());
$data = $validator->getData();
$inwardId = (int)($data['inward_id'] ?? 0);
$outwardId = (int)($data['outward_id'] ?? 0);
$inward = $journalRepos->findNull($inwardId);
$outward = $journalRepos->findNull($outwardId);
if (null === $inward) {
$validator->errors()->add('inward_id', 'Invalid inward ID.');
return;
}
if (null === $outward) {
$validator->errors()->add('outward_id', 'Invalid outward ID.');
return;
}
if ($repository->findLink($inward, $outward)) {
$validator->errors()->add('outward_id', 'Already have a link between inward and outward.');
$validator->errors()->add('inward_id', 'Already have a link between inward and outward.');
}
}
}

View File

@@ -33,6 +33,8 @@ use Illuminate\Validation\Rule;
class LinkTypeRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -42,6 +44,8 @@ class LinkTypeRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -56,6 +60,8 @@ class LinkTypeRequest extends Request
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
@@ -65,7 +71,6 @@ class LinkTypeRequest extends Request
'outward' => 'required|unique:link_types,outward|min:1|different:inward',
'inward' => 'required|unique:link_types,inward|min:1|different:outward',
];
// Rule::unique('users')->ignore($user->id),
switch ($this->method()) {
@@ -83,4 +88,4 @@ class LinkTypeRequest extends Request
return $rules;
}
}
}

View File

@@ -33,6 +33,8 @@ use FireflyIII\Rules\IsAssetAccountId;
class PiggyBankRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -42,6 +44,8 @@ class PiggyBankRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -53,11 +57,13 @@ class PiggyBankRequest extends Request
'current_amount' => $this->string('current_amount'),
'start_date' => $this->date('start_date'),
'target_date' => $this->date('target_date'),
'note' => $this->string('notes'),
'notes' => $this->string('notes'),
];
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
@@ -87,4 +93,4 @@ class PiggyBankRequest extends Request
return $rules;
}
}
}

View File

@@ -32,6 +32,8 @@ class PreferenceRequest extends Request
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -40,6 +42,11 @@ class PreferenceRequest extends Request
return auth()->check();
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
{
return [
@@ -47,6 +54,11 @@ class PreferenceRequest extends Request
];
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
return [
@@ -54,4 +66,4 @@ class PreferenceRequest extends Request
];
}
}
}

View File

@@ -24,20 +24,21 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\BelongsUser;
use FireflyIII\Validation\RecurrenceValidation;
use FireflyIII\Validation\TransactionValidation;
use Illuminate\Validation\Validator;
use InvalidArgumentException;
use Log;
/**
* Class RecurrenceRequest
*/
class RecurrenceRequest extends Request
{
use RecurrenceValidation, TransactionValidation;
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -47,6 +48,8 @@ class RecurrenceRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -67,61 +70,21 @@ class RecurrenceRequest extends Request
'piggy_bank_name' => $this->string('piggy_bank_name'),
'tags' => explode(',', $this->string('tags')),
],
'transactions' => [],
'repetitions' => [],
'transactions' => $this->getTransactionData(),
'repetitions' => $this->getRepetitionData(),
];
// repetition data:
/** @var array $repetitions */
$repetitions = $this->get('repetitions');
/** @var array $repetition */
foreach ($repetitions as $repetition) {
$return['repetitions'][] = [
'type' => $repetition['type'],
'moment' => $repetition['moment'],
'skip' => (int)$repetition['skip'],
'weekend' => (int)$repetition['weekend'],
];
}
// transaction data:
/** @var array $transactions */
$transactions = $this->get('transactions');
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return['transactions'][] = [
'amount' => $transaction['amount'],
'currency_id' => isset($transaction['currency_id']) ? (int)$transaction['currency_id'] : null,
'currency_code' => $transaction['currency_code'] ?? null,
'foreign_amount' => $transaction['foreign_amount'] ?? null,
'foreign_currency_id' => isset($transaction['foreign_currency_id']) ? (int)$transaction['foreign_currency_id'] : null,
'foreign_currency_code' => $transaction['foreign_currency_code'] ?? null,
'budget_id' => isset($transaction['budget_id']) ? (int)$transaction['budget_id'] : null,
'budget_name' => $transaction['budget_name'] ?? null,
'category_id' => isset($transaction['category_id']) ? (int)$transaction['category_id'] : null,
'category_name' => $transaction['category_name'] ?? null,
'source_id' => isset($transaction['source_id']) ? (int)$transaction['source_id'] : null,
'source_name' => isset($transaction['source_name']) ? (string)$transaction['source_name'] : null,
'destination_id' => isset($transaction['destination_id']) ? (int)$transaction['destination_id'] : null,
'destination_name' => isset($transaction['destination_name']) ? (string)$transaction['destination_name'] : null,
'description' => $transaction['description'],
];
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
$today = new Carbon;
$today->addDay();
$today = Carbon::now()->addDay();
return [
'type' => 'required|in:withdrawal,transfer,deposit',
@@ -132,18 +95,12 @@ class RecurrenceRequest extends Request
'nr_of_repetitions' => 'numeric|between:1,31',
'apply_rules' => 'required|boolean',
'active' => 'required|boolean',
// rules for meta values:
'tags' => 'between:1,64000',
'piggy_bank_id' => 'numeric',
// rules for repetitions.
'repetitions.*.type' => 'required|in:daily,weekly,ndom,monthly,yearly',
'repetitions.*.moment' => 'between:0,10',
'repetitions.*.skip' => 'required|numeric|between:0,31',
'repetitions.*.weekend' => 'required|numeric|min:1|max:4',
// rules for transactions.
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id|required_without:transactions.*.currency_code',
'transactions.*.currency_code' => 'min:3|max:3|exists:transaction_currencies,code|required_without:transactions.*.currency_id',
'transactions.*.foreign_amount' => 'numeric|more:0',
@@ -171,312 +128,76 @@ class RecurrenceRequest extends Request
{
$validator->after(
function (Validator $validator) {
$this->atLeastOneTransaction($validator);
$this->atLeastOneRepetition($validator);
$this->validRepeatsUntil($validator);
$this->validRepetitionMoment($validator);
$this->foreignCurrencyInformation($validator);
$this->validateOneTransaction($validator);
$this->validateOneRepetition($validator);
$this->validateRecurrenceRepetition($validator);
$this->validateRepetitionMoment($validator);
$this->validateForeignCurrencyInformation($validator);
$this->validateAccountInformation($validator);
}
);
}
/**
* Throws an error when this asset account is invalid.
* Returns the repetition data as it is found in the submitted data.
*
* @noinspection MoreThanThreeArgumentsInspection
*
* @param Validator $validator
* @param int|null $accountId
* @param null|string $accountName
* @param string $idField
* @param string $nameField
*
* @return null|Account
* @return array
*/
protected function assetAccountExists(Validator $validator, ?int $accountId, ?string $accountName, string $idField, string $nameField): ?Account
private function getRepetitionData(): array
{
$accountId = (int)$accountId;
$accountName = (string)$accountName;
// both empty? hard exit.
if ($accountId < 1 && '' === $accountName) {
$validator->errors()->add($idField, trans('validation.filled', ['attribute' => $idField]));
return null;
}
// ID belongs to user and is asset account:
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$set = $repository->getAccountsById([$accountId]);
Log::debug(sprintf('Count of accounts found by ID %d is: %d', $accountId, $set->count()));
if ($set->count() === 1) {
/** @var Account $first */
$first = $set->first();
if ($first->accountType->type !== AccountType::ASSET) {
$validator->errors()->add($idField, trans('validation.belongs_user'));
return null;
}
// we ignore the account name at this point.
return $first;
$return = [];
// repetition data:
/** @var array $repetitions */
$repetitions = $this->get('repetitions');
/** @var array $repetition */
foreach ($repetitions as $repetition) {
$return[] = [
'type' => $repetition['type'],
'moment' => $repetition['moment'],
'skip' => (int)$repetition['skip'],
'weekend' => (int)$repetition['weekend'],
];
}
$account = $repository->findByName($accountName, [AccountType::ASSET]);
if (null === $account) {
$validator->errors()->add($nameField, trans('validation.belongs_user'));
return null;
}
return $account;
return $return;
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
*
* @param Validator $validator
* @return array
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function atLeastOneRepetition(Validator $validator): void
private function getTransactionData(): array
{
$data = $validator->getData();
$repetitions = $data['repetitions'] ?? [];
// need at least one transaction
if (\count($repetitions) === 0) {
$validator->errors()->add('description', trans('validation.at_least_one_repetition'));
$return = [];
// transaction data:
/** @var array $transactions */
$transactions = $this->get('transactions');
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return[] = [
'amount' => $transaction['amount'],
'currency_id' => isset($transaction['currency_id']) ? (int)$transaction['currency_id'] : null,
'currency_code' => $transaction['currency_code'] ?? null,
'foreign_amount' => $transaction['foreign_amount'] ?? null,
'foreign_currency_id' => isset($transaction['foreign_currency_id']) ? (int)$transaction['foreign_currency_id'] : null,
'foreign_currency_code' => $transaction['foreign_currency_code'] ?? null,
'budget_id' => isset($transaction['budget_id']) ? (int)$transaction['budget_id'] : null,
'budget_name' => $transaction['budget_name'] ?? null,
'category_id' => isset($transaction['category_id']) ? (int)$transaction['category_id'] : null,
'category_name' => $transaction['category_name'] ?? null,
'source_id' => isset($transaction['source_id']) ? (int)$transaction['source_id'] : null,
'source_name' => isset($transaction['source_name']) ? (string)$transaction['source_name'] : null,
'destination_id' => isset($transaction['destination_id']) ? (int)$transaction['destination_id'] : null,
'destination_name' => isset($transaction['destination_name']) ? (string)$transaction['destination_name'] : null,
'description' => $transaction['description'],
];
}
return $return;
}
/**
* Adds an error to the validator when there are no transactions in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneTransaction(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
// need at least one transaction
if (\count($transactions) === 0) {
$validator->errors()->add('description', trans('validation.at_least_one_transaction'));
}
}
/**
* TODO can be made a rule?
* If the transactions contain foreign amounts, there must also be foreign currency information.
*
* @param Validator $validator
*/
protected function foreignCurrencyInformation(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
foreach ($transactions as $index => $transaction) {
// must have currency info.
if (isset($transaction['foreign_amount'])
&& !(isset($transaction['foreign_currency_id'])
|| isset($transaction['foreign_currency_code']))) {
$validator->errors()->add(
'transactions.' . $index . '.foreign_amount',
trans('validation.require_currency_info')
);
}
}
}
/**
* Throws an error when the given opposing account (of type $type) is invalid.
* Empty data is allowed, system will default to cash.
*
* @noinspection MoreThanThreeArgumentsInspection
*
* @param Validator $validator
* @param string $type
* @param int|null $accountId
* @param null|string $accountName
* @param string $idField
*
* @return null|Account
*/
protected function opposingAccountExists(Validator $validator, string $type, ?int $accountId, ?string $accountName, string $idField): ?Account
{
$accountId = (int)$accountId;
$accountName = (string)$accountName;
// both empty? done!
if ($accountId < 1 && \strlen($accountName) === 0) {
return null;
}
if ($accountId !== 0) {
// ID belongs to user and is $type account:
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$set = $repository->getAccountsById([$accountId]);
if ($set->count() === 1) {
/** @var Account $first */
$first = $set->first();
if ($first->accountType->type !== $type) {
$validator->errors()->add($idField, trans('validation.belongs_user'));
return null;
}
// we ignore the account name at this point.
return $first;
}
}
// not having an opposing account by this name is NOT a problem.
return null;
}
/**
* TODO can be a rule?
*
* Validates the given account information. Switches on given transaction type.
*
* @param Validator $validator
*/
protected function validateAccountInformation(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
$idField = 'description';
$transactionType = $data['type'] ?? 'false';
foreach ($transactions as $index => $transaction) {
$sourceId = isset($transaction['source_id']) ? (int)$transaction['source_id'] : null;
$sourceName = $transaction['source_name'] ?? null;
$destinationId = isset($transaction['destination_id']) ? (int)$transaction['destination_id'] : null;
$destinationName = $transaction['destination_name'] ?? null;
$sourceAccount = null;
$destinationAccount = null;
switch ($transactionType) {
case 'withdrawal':
$idField = 'transactions.' . $index . '.source_id';
$nameField = 'transactions.' . $index . '.source_name';
$sourceAccount = $this->assetAccountExists($validator, $sourceId, $sourceName, $idField, $nameField);
$idField = 'transactions.' . $index . '.destination_id';
$destinationAccount = $this->opposingAccountExists($validator, AccountType::EXPENSE, $destinationId, $destinationName, $idField);
break;
case 'deposit':
$idField = 'transactions.' . $index . '.source_id';
$sourceAccount = $this->opposingAccountExists($validator, AccountType::REVENUE, $sourceId, $sourceName, $idField);
$idField = 'transactions.' . $index . '.destination_id';
$nameField = 'transactions.' . $index . '.destination_name';
$destinationAccount = $this->assetAccountExists($validator, $destinationId, $destinationName, $idField, $nameField);
break;
case 'transfer':
$idField = 'transactions.' . $index . '.source_id';
$nameField = 'transactions.' . $index . '.source_name';
$sourceAccount = $this->assetAccountExists($validator, $sourceId, $sourceName, $idField, $nameField);
$idField = 'transactions.' . $index . '.destination_id';
$nameField = 'transactions.' . $index . '.destination_name';
$destinationAccount = $this->assetAccountExists($validator, $destinationId, $destinationName, $idField, $nameField);
break;
default:
$validator->errors()->add($idField, trans('validation.invalid_account_info'));
return;
}
// add some errors in case of same account submitted:
if (null !== $sourceAccount && null !== $destinationAccount && $sourceAccount->id === $destinationAccount->id) {
$validator->errors()->add($idField, trans('validation.source_equals_destination'));
}
}
}
/**
* @param Validator $validator
*/
private function validRepeatsUntil(Validator $validator): void
{
$data = $validator->getData();
$repetitions = $data['nr_of_repetitions'] ?? null;
$repeatUntil = $data['repeat_until'] ?? null;
if (null !== $repetitions && null !== $repeatUntil) {
// expect a date OR count:
$validator->errors()->add('repeat_until', trans('validation.require_repeat_until'));
$validator->errors()->add('nr_of_repetitions', trans('validation.require_repeat_until'));
return;
}
}
/**
* TODO merge this in a rule somehow.
*
* @param Validator $validator
*/
private function validRepetitionMoment(Validator $validator): void
{
$data = $validator->getData();
$repetitions = $data['repetitions'] ?? [];
/**
* @var int $index
* @var array $repetition
*/
foreach ($repetitions as $index => $repetition) {
switch ($repetition['type']) {
default:
$validator->errors()->add(sprintf('repetitions.%d.type', $index), trans('validation.valid_recurrence_rep_type'));
return;
case 'daily':
if ('' !== (string)$repetition['moment']) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
}
return;
case 'monthly':
$dayOfMonth = (int)$repetition['moment'];
if ($dayOfMonth < 1 || $dayOfMonth > 31) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
}
return;
case 'ndom':
$parameters = explode(',', $repetition['moment']);
if (\count($parameters) !== 2) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
return;
}
$nthDay = (int)($parameters[0] ?? 0.0);
$dayOfWeek = (int)($parameters[1] ?? 0.0);
if ($nthDay < 1 || $nthDay > 5) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
return;
}
if ($dayOfWeek < 1 || $dayOfWeek > 7) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
return;
}
return;
case 'weekly':
$dayOfWeek = (int)$repetition['moment'];
if ($dayOfWeek < 1 || $dayOfWeek > 7) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
return;
}
break;
case 'yearly':
try {
Carbon::createFromFormat('Y-m-d', $repetition['moment']);
} catch (InvalidArgumentException $e) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
return;
}
}
}
}
}
}

View File

@@ -28,6 +28,10 @@ use FireflyIII\Http\Requests\Request as FireflyIIIRequest;
/**
* Class Request.
*
* Technically speaking this class does not have to be extended like this but who knows what the future brings.
*
* @SuppressWarnings(PHPMD.NumberOfChildren)
*/
class Request extends FireflyIIIRequest
{

View File

@@ -33,6 +33,8 @@ use FireflyIII\Models\RuleGroup;
class RuleGroupRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -42,6 +44,8 @@ class RuleGroupRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -54,6 +58,8 @@ class RuleGroupRequest extends Request
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
@@ -76,4 +82,4 @@ class RuleGroupRequest extends Request
return $rules;
}
}
}

View File

@@ -32,6 +32,8 @@ use Illuminate\Validation\Validator;
class RuleRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -41,6 +43,8 @@ class RuleRequest extends Request
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -52,31 +56,18 @@ class RuleRequest extends Request
'rule_group_title' => $this->string('rule_group_title'),
'trigger' => $this->string('trigger'),
'strict' => $this->boolean('strict'),
'stop-processing' => $this->boolean('stop_processing'),
'stop_processing' => $this->boolean('stop_processing'),
'active' => $this->boolean('active'),
'rule-triggers' => [],
'rule-actions' => [],
'rule_triggers' => $this->getRuleTriggers(),
'rule_actions' => $this->getRuleActions(),
];
foreach ($this->get('rule-triggers') as $trigger) {
$data['rule-triggers'][] = [
'name' => $trigger['name'],
'value' => $trigger['value'],
'stop-processing' => (int)($trigger['stop-processing'] ?? 0) === 1,
];
}
foreach ($this->get('rule-actions') as $action) {
$data['rule-actions'][] = [
'name' => $action['name'],
'value' => $action['value'],
'stop-processing' => (int)($action['stop-processing'] ?? 0) === 1,
];
}
return $data;
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
@@ -93,12 +84,12 @@ class RuleRequest extends Request
'rule_group_id' => 'required|belongsToUser:rule_groups|required_without:rule_group_title',
'rule_group_title' => 'nullable|between:1,255|required_without:rule_group_id|belongsToUser:rule_groups,title',
'trigger' => 'required|in:store-journal,update-journal',
'rule-triggers.*.name' => 'required|in:' . implode(',', $validTriggers),
'rule-triggers.*.stop-processing' => 'boolean',
'rule-triggers.*.value' => 'required|min:1|ruleTriggerValue', //
'rule-actions.*.name' => 'required|in:' . implode(',', $validActions),
'rule-actions.*.value' => 'required_if:rule-action.*.type,' . $contextActions . '|ruleActionValue',
'rule-actions.*.stop-processing' => 'boolean',
'rule_triggers.*.name' => 'required|in:' . implode(',', $validTriggers),
'rule_triggers.*.stop_processing' => 'boolean',
'rule_triggers.*.value' => 'required|min:1|ruleTriggerValue',
'rule_actions.*.name' => 'required|in:' . implode(',', $validActions),
'rule_actions.*.value' => 'required_if:rule_actions.*.type,' . $contextActions . '|ruleActionValue',
'rule_actions.*.stop_processing' => 'boolean',
'strict' => 'required|boolean',
'stop_processing' => 'required|boolean',
'active' => 'required|boolean',
@@ -132,10 +123,10 @@ class RuleRequest extends Request
protected function atLeastOneAction(Validator $validator): void
{
$data = $validator->getData();
$repetitions = $data['rule-actions'] ?? [];
$repetitions = $data['rule_actions'] ?? [];
// need at least one transaction
if (\count($repetitions) === 0) {
$validator->errors()->add('title', trans('validation.at_least_one_action'));
if (0 === \count($repetitions)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_action'));
}
}
@@ -147,10 +138,50 @@ class RuleRequest extends Request
protected function atLeastOneTrigger(Validator $validator): void
{
$data = $validator->getData();
$repetitions = $data['rule-triggers'] ?? [];
$repetitions = $data['rule_triggers'] ?? [];
// need at least one transaction
if (\count($repetitions) === 0) {
$validator->errors()->add('title', trans('validation.at_least_one_trigger'));
if (0 === \count($repetitions)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_trigger'));
}
}
}
/**
* @return array
*/
private function getRuleActions(): array
{
$actions = $this->get('rule_actions');
$return = [];
if (\is_array($actions)) {
foreach ($actions as $action) {
$return[] = [
'name' => $action['name'],
'value' => $action['value'],
'stop_processing' => 1 === (int)($action['stop-processing'] ?? '0'),
];
}
}
return $return;
}
/**
* @return array
*/
private function getRuleTriggers(): array
{
$triggers = $this->get('rule_triggers');
$return = [];
if (\is_array($triggers)) {
foreach ($triggers as $trigger) {
$return[] = [
'name' => $trigger['name'],
'value' => $trigger['value'],
'stop_processing' => 1 === (int)($trigger['stop-processing'] ?? '0'),
];
}
}
return $return;
}
}

View File

@@ -24,12 +24,8 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\BelongsUser;
use FireflyIII\Validation\TransactionValidation;
use Illuminate\Validation\Validator;
@@ -38,7 +34,11 @@ use Illuminate\Validation\Validator;
*/
class TransactionRequest extends Request
{
use TransactionValidation;
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
@@ -48,12 +48,15 @@ class TransactionRequest extends Request
}
/**
* Get all data. Is pretty complex because of all the ??-statements.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @return array
*/
public function getAll(): array
{
$data = [
// basic fields for journal:
'type' => $this->string('type'),
'date' => $this->date('date'),
'description' => $this->string('description'),
@@ -62,8 +65,6 @@ class TransactionRequest extends Request
'bill_id' => $this->integer('bill_id'),
'bill_name' => $this->string('bill_name'),
'tags' => explode(',', $this->string('tags')),
// then, custom fields for journal
'interest_date' => $this->date('interest_date'),
'book_date' => $this->date('book_date'),
'process_date' => $this->date('process_date'),
@@ -72,39 +73,17 @@ class TransactionRequest extends Request
'invoice_date' => $this->date('invoice_date'),
'internal_reference' => $this->string('internal_reference'),
'notes' => $this->string('notes'),
// then, transactions (see below).
'transactions' => [],
'transactions' => $this->getTransactionData(),
];
foreach ($this->get('transactions') as $index => $transaction) {
$array = [
'description' => $transaction['description'] ?? null,
'amount' => $transaction['amount'],
'currency_id' => isset($transaction['currency_id']) ? (int)$transaction['currency_id'] : null,
'currency_code' => $transaction['currency_code'] ?? null,
'foreign_amount' => $transaction['foreign_amount'] ?? null,
'foreign_currency_id' => isset($transaction['foreign_currency_id']) ? (int)$transaction['foreign_currency_id'] : null,
'foreign_currency_code' => $transaction['foreign_currency_code'] ?? null,
'budget_id' => isset($transaction['budget_id']) ? (int)$transaction['budget_id'] : null,
'budget_name' => $transaction['budget_name'] ?? null,
'category_id' => isset($transaction['category_id']) ? (int)$transaction['category_id'] : null,
'category_name' => $transaction['category_name'] ?? null,
'source_id' => isset($transaction['source_id']) ? (int)$transaction['source_id'] : null,
'source_name' => isset($transaction['source_name']) ? (string)$transaction['source_name'] : null,
'destination_id' => isset($transaction['destination_id']) ? (int)$transaction['destination_id'] : null,
'destination_name' => isset($transaction['destination_name']) ? (string)$transaction['destination_name'] : null,
'reconciled' => $transaction['reconciled'] ?? false,
'identifier' => $index,
];
$data['transactions'][] = $array;
}
return $data;
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function rules(): array
{
@@ -149,13 +128,8 @@ class TransactionRequest extends Request
'transactions.*.destination_name' => 'between:1,255|nullable',
];
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
unset($rules['type'], $rules['piggy_bank_id'], $rules['piggy_bank_name']);
break;
if ('PUT' === $this->method()) {
unset($rules['type'], $rules['piggy_bank_id'], $rules['piggy_bank_name']);
}
return $rules;
@@ -174,11 +148,11 @@ class TransactionRequest extends Request
{
$validator->after(
function (Validator $validator) {
$this->atLeastOneTransaction($validator);
$this->checkValidDescriptions($validator);
$this->equalToJournalDescription($validator);
$this->emptySplitDescriptions($validator);
$this->foreignCurrencyInformation($validator);
$this->validateOneTransaction($validator);
$this->validateDescriptions($validator);
$this->validateJournalDescription($validator);
$this->validateSplitDescriptions($validator);
$this->validateForeignCurrencyInformation($validator);
$this->validateAccountInformation($validator);
$this->validateSplitAccounts($validator);
}
@@ -186,335 +160,37 @@ class TransactionRequest extends Request
}
/**
* Throws an error when this asset account is invalid.
* Get transaction data.
*
* @noinspection MoreThanThreeArgumentsInspection
*
* @param Validator $validator
* @param int|null $accountId
* @param null|string $accountName
* @param string $idField
* @param string $nameField
*
* @return null|Account
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @return array
*/
protected function assetAccountExists(Validator $validator, ?int $accountId, ?string $accountName, string $idField, string $nameField): ?Account
private function getTransactionData(): array
{
$accountId = (int)$accountId;
$accountName = (string)$accountName;
// both empty? hard exit.
if ($accountId < 1 && \strlen($accountName) === 0) {
$validator->errors()->add($idField, trans('validation.filled', ['attribute' => $idField]));
return null;
}
// ID belongs to user and is asset account:
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$set = $repository->getAccountsById([$accountId]);
if ($set->count() === 1) {
/** @var Account $first */
$first = $set->first();
if ($first->accountType->type !== AccountType::ASSET) {
$validator->errors()->add($idField, trans('validation.belongs_user'));
return null;
}
// we ignore the account name at this point.
return $first;
$return = [];
foreach ($this->get('transactions') as $index => $transaction) {
$return[] = [
'description' => $transaction['description'] ?? null,
'amount' => $transaction['amount'],
'currency_id' => isset($transaction['currency_id']) ? (int)$transaction['currency_id'] : null,
'currency_code' => $transaction['currency_code'] ?? null,
'foreign_amount' => $transaction['foreign_amount'] ?? null,
'foreign_currency_id' => isset($transaction['foreign_currency_id']) ? (int)$transaction['foreign_currency_id'] : null,
'foreign_currency_code' => $transaction['foreign_currency_code'] ?? null,
'budget_id' => isset($transaction['budget_id']) ? (int)$transaction['budget_id'] : null,
'budget_name' => $transaction['budget_name'] ?? null,
'category_id' => isset($transaction['category_id']) ? (int)$transaction['category_id'] : null,
'category_name' => $transaction['category_name'] ?? null,
'source_id' => isset($transaction['source_id']) ? (int)$transaction['source_id'] : null,
'source_name' => isset($transaction['source_name']) ? (string)$transaction['source_name'] : null,
'destination_id' => isset($transaction['destination_id']) ? (int)$transaction['destination_id'] : null,
'destination_name' => isset($transaction['destination_name']) ? (string)$transaction['destination_name'] : null,
'reconciled' => $transaction['reconciled'] ?? false,
'identifier' => $index,
];
}
$account = $repository->findByName($accountName, [AccountType::ASSET]);
if (null === $account) {
$validator->errors()->add($nameField, trans('validation.belongs_user'));
return null;
}
return $account;
return $return;
}
/**
* Adds an error to the validator when there are no transactions in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneTransaction(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
// need at least one transaction
if (\count($transactions) === 0) {
$validator->errors()->add('description', trans('validation.at_least_one_transaction'));
}
}
/**
* Adds an error to the "description" field when the user has submitted no descriptions and no
* journal description.
*
* @param Validator $validator
*/
protected function checkValidDescriptions(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
$journalDescription = (string)($data['description'] ?? '');
$validDescriptions = 0;
foreach ($transactions as $index => $transaction) {
if (\strlen((string)($transaction['description'] ?? '')) > 0) {
$validDescriptions++;
}
}
// no valid descriptions and empty journal description? error.
if ($validDescriptions === 0 && \strlen($journalDescription) === 0) {
$validator->errors()->add('description', trans('validation.filled', ['attribute' => trans('validation.attributes.description')]));
}
}
/**
* Adds an error to the validator when the user submits a split transaction (more than 1 transactions)
* but does not give them a description.
*
* @param Validator $validator
*/
protected function emptySplitDescriptions(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
foreach ($transactions as $index => $transaction) {
$description = (string)($transaction['description'] ?? '');
// filled description is mandatory for split transactions.
if (\count($transactions) > 1 && \strlen($description) === 0) {
$validator->errors()->add(
'transactions.' . $index . '.description',
trans('validation.filled', ['attribute' => trans('validation.attributes.transaction_description')])
);
}
}
}
/**
* Adds an error to the validator when any transaction descriptions are equal to the journal description.
*
* @param Validator $validator
*/
protected function equalToJournalDescription(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
$journalDescription = (string)($data['description'] ?? '');
foreach ($transactions as $index => $transaction) {
$description = (string)($transaction['description'] ?? '');
// description cannot be equal to journal description.
if ($description === $journalDescription) {
$validator->errors()->add('transactions.' . $index . '.description', trans('validation.equal_description'));
}
}
}
/**
* TODO can be made a rule?
*
* If the transactions contain foreign amounts, there must also be foreign currency information.
*
* @param Validator $validator
*/
protected function foreignCurrencyInformation(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
foreach ($transactions as $index => $transaction) {
// must have currency info.
if (isset($transaction['foreign_amount'])
&& !(isset($transaction['foreign_currency_id'])
|| isset($transaction['foreign_currency_code']))) {
$validator->errors()->add(
'transactions.' . $index . '.foreign_amount',
trans('validation.require_currency_info')
);
}
}
}
/**
* Throws an error when the given opposing account (of type $type) is invalid.
* Empty data is allowed, system will default to cash.
*
* @noinspection MoreThanThreeArgumentsInspection
*
* @param Validator $validator
* @param string $type
* @param int|null $accountId
* @param null|string $accountName
* @param string $idField
*
* @return null|Account
*/
protected function opposingAccountExists(Validator $validator, string $type, ?int $accountId, ?string $accountName, string $idField): ?Account
{
$accountId = (int)$accountId;
$accountName = (string)$accountName;
// both empty? done!
if ($accountId < 1 && \strlen($accountName) === 0) {
return null;
}
if ($accountId !== 0) {
// ID belongs to user and is $type account:
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$set = $repository->getAccountsById([$accountId]);
if ($set->count() === 1) {
/** @var Account $first */
$first = $set->first();
if ($first->accountType->type !== $type) {
$validator->errors()->add($idField, trans('validation.belongs_user'));
return null;
}
// we ignore the account name at this point.
return $first;
}
}
// not having an opposing account by this name is NOT a problem.
return null;
}
/**
* Validates the given account information. Switches on given transaction type.
*
* @param Validator $validator
*
* @throws FireflyException
*/
protected function validateAccountInformation(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
if (!isset($data['type'])) {
// the journal may exist in the request:
/** @var Transaction $transaction */
$transaction = $this->route()->parameter('transaction');
if (null === $transaction) {
return; // @codeCoverageIgnore
}
$data['type'] = strtolower($transaction->transactionJournal->transactionType->type);
}
foreach ($transactions as $index => $transaction) {
$sourceId = isset($transaction['source_id']) ? (int)$transaction['source_id'] : null;
$sourceName = $transaction['source_name'] ?? null;
$destinationId = isset($transaction['destination_id']) ? (int)$transaction['destination_id'] : null;
$destinationName = $transaction['destination_name'] ?? null;
$sourceAccount = null;
$destinationAccount = null;
switch ($data['type']) {
case 'withdrawal':
$idField = 'transactions.' . $index . '.source_id';
$nameField = 'transactions.' . $index . '.source_name';
$sourceAccount = $this->assetAccountExists($validator, $sourceId, $sourceName, $idField, $nameField);
$idField = 'transactions.' . $index . '.destination_id';
$destinationAccount = $this->opposingAccountExists($validator, AccountType::EXPENSE, $destinationId, $destinationName, $idField);
break;
case 'deposit':
$idField = 'transactions.' . $index . '.source_id';
$sourceAccount = $this->opposingAccountExists($validator, AccountType::REVENUE, $sourceId, $sourceName, $idField);
$idField = 'transactions.' . $index . '.destination_id';
$nameField = 'transactions.' . $index . '.destination_name';
$destinationAccount = $this->assetAccountExists($validator, $destinationId, $destinationName, $idField, $nameField);
break;
case 'transfer':
$idField = 'transactions.' . $index . '.source_id';
$nameField = 'transactions.' . $index . '.source_name';
$sourceAccount = $this->assetAccountExists($validator, $sourceId, $sourceName, $idField, $nameField);
$idField = 'transactions.' . $index . '.destination_id';
$nameField = 'transactions.' . $index . '.destination_name';
$destinationAccount = $this->assetAccountExists($validator, $destinationId, $destinationName, $idField, $nameField);
break;
default:
// @codeCoverageIgnoreStart
throw new FireflyException(
sprintf('The validator cannot handle transaction type "%s" in validateAccountInformation().', $data['type'])
);
// @codeCoverageIgnoreEnd
}
// add some errors in case of same account submitted:
if (null !== $sourceAccount && null !== $destinationAccount && $sourceAccount->id === $destinationAccount->id) {
$validator->errors()->add($idField, trans('validation.source_equals_destination'));
}
}
}
/**
* @param Validator $validator
*
* @throws FireflyException
*/
protected function validateSplitAccounts(Validator $validator): void
{
$data = $validator->getData();
$count = isset($data['transactions']) ? \count($data['transactions']) : 0;
if ($count < 2) {
return;
}
// this is pretty much impossible:
// @codeCoverageIgnoreStart
if (!isset($data['type'])) {
// the journal may exist in the request:
/** @var Transaction $transaction */
$transaction = $this->route()->parameter('transaction');
if (null === $transaction) {
return;
}
$data['type'] = strtolower($transaction->transactionJournal->transactionType->type);
}
// @codeCoverageIgnoreEnd
// collect all source ID's and destination ID's, if present:
$sources = [];
$destinations = [];
foreach ($data['transactions'] as $transaction) {
$sources[] = isset($transaction['source_id']) ? (int)$transaction['source_id'] : 0;
$destinations[] = isset($transaction['destination_id']) ? (int)$transaction['destination_id'] : 0;
}
$destinations = array_unique($destinations);
$sources = array_unique($sources);
// switch on type:
switch ($data['type']) {
case 'withdrawal':
if (\count($sources) > 1) {
$validator->errors()->add('transactions.0.source_id', trans('validation.all_accounts_equal'));
}
break;
case 'deposit':
if (\count($destinations) > 1) {
$validator->errors()->add('transactions.0.destination_id', trans('validation.all_accounts_equal'));
}
break;
case 'transfer':
if (\count($sources) > 1 || \count($destinations) > 1) {
$validator->errors()->add('transactions.0.source_id', trans('validation.all_accounts_equal'));
$validator->errors()->add('transactions.0.destination_id', trans('validation.all_accounts_equal'));
}
break;
default:
// @codeCoverageIgnoreStart
throw new FireflyException(
sprintf('The validator cannot handle transaction type "%s" in validateSplitAccounts().', $data['type'])
);
// @codeCoverageIgnoreEnd
}
}
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User;
@@ -33,24 +34,32 @@ use FireflyIII\User;
class UserRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
{
$result = false;
// Only allow authenticated users
if (!auth()->check()) {
return false; // @codeCoverageIgnore
}
/** @var User $user */
$user = auth()->user();
if (!$user->hasRole('owner')) {
return false; // @codeCoverageIgnore
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
if ($repository->hasRole($user, 'owner')) {
$result = true; // @codeCoverageIgnore
}
}
return true;
return $result;
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
@@ -65,6 +74,8 @@ class UserRequest extends Request
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array

View File

@@ -1,5 +1,4 @@
<?php
/**
* CreateExport.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -20,6 +19,8 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
@@ -38,10 +39,13 @@ use Storage;
* Class CreateExport.
*
* Generates export from the command line.
*
* @codeCoverageIgnore
*/
class CreateExport extends Command
{
use VerifiesAccessToken;
/**
* The console command description.
*
@@ -64,9 +68,11 @@ class CreateExport extends Command
/**
* Execute the console command.
*
* @return mixed
* @return int
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function handle()
public function handle(): int
{
if (!$this->verifyAccessToken()) {
$this->error('Invalid access token.');
@@ -86,6 +92,9 @@ class CreateExport extends Command
// set user
$user = $userRepository->findNull((int)$this->option('user'));
if (null === $user) {
return 1;
}
$jobRepository->setUser($user);
$journalRepository->setUser($user);
$accountRepository->setUser($user);

View File

@@ -1,5 +1,4 @@
<?php
/**
* CreateImport.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -20,6 +19,8 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
@@ -33,10 +34,11 @@ use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use Illuminate\Console\Command;
use Log;
use Preferences;
/**
* Class CreateImport.
*
* @codeCoverageIgnore
*/
class CreateImport extends Command
{
@@ -81,10 +83,15 @@ class CreateImport extends Command
$configuration = (string)$this->argument('configuration');
$user = $userRepository->findNull((int)$this->option('user'));
$cwd = getcwd();
$type = strtolower((string)$this->option('type'));
$provider = strtolower((string)$this->option('provider'));
$configurationData = [];
if (null === $user) {
$this->errorLine('User is NULL.');
return 1;
}
if (!$this->validArguments()) {
$this->errorLine('Invalid arguments.');
@@ -145,7 +152,7 @@ class CreateImport extends Command
if (true === $this->option('start')) {
$this->infoLine('The has started. The process is not visible. Please wait.');
$this->infoLine('The import routine has started. The process is not visible. Please wait.');
Log::debug('Go for import!');
// run it!
@@ -182,7 +189,7 @@ class CreateImport extends Command
}
$count++;
}
if ($importJob->status === 'provider_finished') {
if ('provider_finished' === $importJob->status) {
$this->infoLine('Import has finished. Please wait for storage of data.');
// set job to be storing data:
$jobRepository->setStatus($importJob, 'storing_data');
@@ -226,7 +233,7 @@ class CreateImport extends Command
}
}
// clear cache for user:
Preferences::setForUser($user, 'lastActivity', microtime());
app('preferences')->setForUser($user, 'lastActivity', microtime());
return 0;
}
@@ -260,8 +267,8 @@ class CreateImport extends Command
*/
private function validArguments(): bool
{
$file = $this->argument('file');
$configuration = $this->argument('configuration');
$file = (string)$this->argument('file');
$configuration = (string)$this->argument('configuration');
$cwd = getcwd();
$validTypes = config('import.options.file.import_formats');
$type = strtolower($this->option('type'));
@@ -274,19 +281,19 @@ class CreateImport extends Command
return false;
}
if ($provider === 'file' && !\in_array($type, $validTypes, true)) {
if ('file' === $provider && !\in_array($type, $validTypes, true)) {
$this->errorLine(sprintf('Cannot import file of type "%s"', $type));
return false;
}
if ($provider === 'file' && !file_exists($file)) {
if ('file' === $provider && !file_exists($file)) {
$this->errorLine(sprintf('Firefly III cannot find file "%s" (working directory: "%s").', $file, $cwd));
return false;
}
if ($provider === 'file' && !file_exists($configuration)) {
if ('file' === $provider && !file_exists($configuration)) {
$this->errorLine(sprintf('Firefly III cannot find configuration file "%s" (working directory: "%s").', $configuration, $cwd));
return false;

View File

@@ -0,0 +1,67 @@
<?php
namespace FireflyIII\Console\Commands;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Cronjobs\RecurringCronjob;
use Illuminate\Console\Command;
/**
* Class Cron
*
* @codeCoverageIgnore
*/
class Cron extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Runs all Firefly III cron-job related commands. Configure a cron job according to the official Firefly III documentation.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly:cron';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle(): int
{
$recurring = new RecurringCronjob;
try {
$result = $recurring->fire();
} catch (FireflyException $e) {
$this->error($e->getMessage());
return 0;
}
if (false === $result) {
$this->line('The recurring transaction cron job did not fire.');
}
if (true === $result) {
$this->line('The recurring transaction cron job fired successfully.');
}
$this->info('More feedback on the cron jobs can be found in the log files.');
return 0;
}
}

View File

@@ -1,5 +1,4 @@
<?php
/**
* DecryptAttachment.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -20,6 +19,8 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
@@ -30,6 +31,8 @@ use Log;
/**
* Class DecryptAttachment.
*
* @codeCoverageIgnore
*/
class DecryptAttachment extends Command
{
@@ -51,44 +54,45 @@ class DecryptAttachment extends Command
/**
* Execute the console command.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's five its fine.
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
* @return int
*/
public function handle()
public function handle(): int
{
/** @var AttachmentRepositoryInterface $repository */
$repository = app(AttachmentRepositoryInterface::class);
$attachmentId = (int)$this->argument('id');
$attachment = $repository->findWithoutUser($attachmentId);
$attachmentName = trim($this->argument('name'));
$storagePath = realpath(trim($this->argument('directory')));
if (null === $attachment->id) {
$attachmentName = trim((string)$this->argument('name'));
$storagePath = realpath(trim((string)$this->argument('directory')));
if (null === $attachment) {
$this->error(sprintf('No attachment with id #%d', $attachmentId));
Log::error(sprintf('DecryptAttachment: No attachment with id #%d', $attachmentId));
return;
return 1;
}
if ($attachmentName !== $attachment->filename) {
$this->error('File name does not match.');
Log::error('DecryptAttachment: File name does not match.');
return;
return 1;
}
if (!is_dir($storagePath)) {
$this->error(sprintf('Path "%s" is not a directory.', $storagePath));
Log::error(sprintf('DecryptAttachment: Path "%s" is not a directory.', $storagePath));
return;
return 1;
}
if (!is_writable($storagePath)) {
$this->error(sprintf('Path "%s" is not writable.', $storagePath));
Log::error(sprintf('DecryptAttachment: Path "%s" is not writable.', $storagePath));
return;
return 1;
}
$fullPath = $storagePath . DIRECTORY_SEPARATOR . $attachment->filename;
@@ -98,9 +102,10 @@ class DecryptAttachment extends Command
if (false === $result) {
$this->error('Could not write to file.');
return;
return 1;
}
$this->info(sprintf('%d bytes written. Exiting now..', $result));
return 0;
}
}

View File

@@ -1,5 +1,4 @@
<?php
/**
* EncryptFile.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -30,6 +29,8 @@ use Illuminate\Console\Command;
/**
* Class EncryptFile.
*
* @codeCoverageIgnore
*/
class EncryptFile extends Command
{

View File

@@ -1,5 +1,4 @@
<?php
/**
* Import.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -20,6 +19,9 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
/** @noinspection PhpDynamicAsStaticMethodCallInspection */
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
@@ -27,12 +29,14 @@ namespace FireflyIII\Console\Commands;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Import\Routine\RoutineInterface;
use FireflyIII\Models\ImportJob;
use FireflyIII\Models\Tag;
use Illuminate\Console\Command;
use Illuminate\Support\MessageBag;
use Log;
/**
* Class Import.
*
* @codeCoverageIgnore
*/
class Import extends Command
{
@@ -52,23 +56,26 @@ class Import extends Command
/**
* Run the import routine.
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
* @throws FireflyException
*/
public function handle()
public function handle(): int
{
Log::debug('Start start-import command');
$jobKey = $this->argument('key');
$job = ImportJob::where('key', $jobKey)->first();
$jobKey = (string)$this->argument('key');
/** @var ImportJob $job */
$job = ImportJob::where('key', $jobKey)->first();
if (null === $job) {
$this->errorLine(sprintf('No job found with key "%s"', $jobKey));
return;
return 1;
}
if (!$this->isValid($job)) {
$this->errorLine('Job is not valid for some reason. Exit.');
return;
return 1;
}
$this->infoLine(sprintf('Going to import job with key "%s" of type "%s"', $job->key, $job->file_type));
@@ -83,21 +90,32 @@ class Import extends Command
/** @var RoutineInterface $routine */
$routine = app($className);
$routine->setJob($job);
$routine->setImportJob($job);
$routine->run();
/** @var MessageBag $error */
foreach ($routine->getErrors() as $index => $error) {
/**
* @var int $index
* @var string $error
*/
foreach ($job->errors as $index => $error) {
$this->errorLine(sprintf('Error importing line #%d: %s', $index, $error));
}
$this->infoLine(
sprintf('The import has finished. %d transactions have been imported out of %d records.', $routine->getJournals()->count(), $routine->getLines())
);
/** @var Tag $tag */
$tag = $job->tag()->first();
$count = 0;
if (null === $tag) {
$count = $tag->transactionJournals()->count();
}
$this->infoLine(sprintf('The import has finished. %d transactions have been imported.', $count));
return 0;
}
/**
* Displays an error.
*
* @param string $message
* @param array|null $data
*/
@@ -109,6 +127,8 @@ class Import extends Command
}
/**
* Displays an informational message.
*
* @param string $message
* @param array $data
*/

View File

@@ -1,5 +1,4 @@
<?php
/**
* ScanAttachments.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -20,6 +19,8 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection PhpDynamicAsStaticMethodCallInspection */
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
@@ -33,6 +34,8 @@ use Storage;
/**
* Class ScanAttachments.
*
* @codeCoverageIgnore
*/
class ScanAttachments extends Command
{
@@ -53,7 +56,7 @@ class ScanAttachments extends Command
/**
* Execute the console command.
*/
public function handle()
public function handle(): int
{
$attachments = Attachment::get();
$disk = Storage::disk('upload');
@@ -63,13 +66,13 @@ class ScanAttachments extends Command
try {
$content = $disk->get($fileName);
} catch (FileNotFoundException $e) {
$this->error(sprintf('Could not find data for attachment #%d', $attachment->id));
$this->error(sprintf('Could not find data for attachment #%d: %s', $attachment->id, $e->getMessage()));
continue;
}
try {
$decrypted = Crypt::decrypt($content);
} catch (DecryptException $e) {
$this->error(sprintf('Could not decrypt data of attachment #%d', $attachment->id));
$this->error(sprintf('Could not decrypt data of attachment #%d: %s', $attachment->id, $e->getMessage()));
continue;
}
$tmpfname = tempnam(sys_get_temp_dir(), 'FireflyIII');
@@ -81,5 +84,7 @@ class ScanAttachments extends Command
$attachment->save();
$this->line(sprintf('Fixed attachment #%d', $attachment->id));
}
return 0;
}
}

View File

@@ -20,6 +20,10 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
/** @noinspection PhpStaticAsDynamicMethodCallInspection */
/** @noinspection PhpDynamicAsStaticMethodCallInspection */
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
@@ -42,22 +46,24 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionJournalMeta;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\User;
use Illuminate\Console\Command;
use Illuminate\Database\QueryException;
use Illuminate\Support\Collection;
use Log;
use Preferences;
use Schema;
use UnexpectedValueException;
/**
* Class UpgradeDatabase.
*
* Upgrade user database.
*
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects) // it just touches a lot of things.
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @codeCoverageIgnore
*/
class UpgradeDatabase extends Command
{
@@ -77,7 +83,7 @@ class UpgradeDatabase extends Command
/**
* Execute the console command.
*/
public function handle()
public function handle(): int
{
$this->setTransactionIdentifier();
$this->updateAccountCurrencies();
@@ -91,22 +97,39 @@ class UpgradeDatabase extends Command
$this->migrateBillsToRules();
$this->info('Firefly III database is up to date.');
return 0;
}
public function migrateBillsToRules()
/**
* Since it is one routine these warnings make sense and should be supressed.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
public function migrateBillsToRules(): void
{
foreach (User::get() as $user) {
/** @var Preference $lang */
$lang = Preferences::getForUser($user, 'language', 'en_US');
$lang = app('preferences')->getForUser($user, 'language', 'en_US');
$groupName = (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data);
$ruleGroup = $user->ruleGroups()->where('title', $groupName)->first();
$currencyPreference = Preferences::getForUser($user, 'currencyPreference', config('firefly.default_currency', 'EUR'));
$currency = TransactionCurrency::where('code', $currencyPreference->data)->first();
$currencyPreference = app('preferences')->getForUser($user, 'currencyPreference', config('firefly.default_currency', 'EUR'));
if (null === $currencyPreference) {
$this->error('User has no currency preference. Impossible.');
return;
}
$currency = TransactionCurrency::where('code', $currencyPreference->data)->first();
if (null === $currency) {
$this->line('Fall back to default currency in migrateBillsToRules().');
$currency = app('amount')->getDefaultCurrency();
}
if ($ruleGroup === null) {
if (null === $ruleGroup) {
$array = RuleGroup::get(['order'])->pluck('order')->toArray();
$order = \count($array) > 0 ? max($array) + 1 : 1;
$ruleGroup = RuleGroup::create(
@@ -126,7 +149,7 @@ class UpgradeDatabase extends Command
$collection = $user->bills()->get();
/** @var Bill $bill */
foreach ($collection as $bill) {
if ($bill->match !== 'MIGRATED_TO_RULES') {
if ('MIGRATED_TO_RULES' !== $bill->match) {
$rule = Rule::create(
[
'user_id' => $user->id,
@@ -177,7 +200,7 @@ class UpgradeDatabase extends Command
[
'rule_id' => $rule->id,
'trigger_type' => 'amount_more',
'trigger_value' => round($bill->amount_min, $currency->decimal_places),
'trigger_value' => round((float)$bill->amount_min, $currency->decimal_places),
'active' => 1,
'stop_processing' => 0,
'order' => 4,
@@ -189,7 +212,7 @@ class UpgradeDatabase extends Command
[
'rule_id' => $rule->id,
'trigger_type' => 'amount_exactly',
'trigger_value' => round($bill->amount_min, $currency->decimal_places),
'trigger_value' => round((float)$bill->amount_min, $currency->decimal_places),
'active' => 1,
'stop_processing' => 0,
'order' => 3,
@@ -260,23 +283,29 @@ class UpgradeDatabase extends Command
/**
* Each (asset) account must have a reference to a preferred currency. If the account does not have one, it's forced upon the account.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's seven but it can't really be helped.
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function updateAccountCurrencies(): void
{
$accounts = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereIn('account_types.type', [AccountType::DEFAULT, AccountType::ASSET])->get(['accounts.*']);
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$accounts->each(
function (Account $account) {
function (Account $account) use ($repository) {
$repository->setUser($account->user);
// get users preference, fall back to system pref.
$defaultCurrencyCode = Preferences::getForUser($account->user, 'currencyPreference', config('firefly.default_currency', 'EUR'))->data;
$defaultCurrencyCode = app('preferences')->getForUser($account->user, 'currencyPreference', config('firefly.default_currency', 'EUR'))->data;
$defaultCurrency = TransactionCurrency::where('code', $defaultCurrencyCode)->first();
$accountCurrency = (int)$account->getMeta('currency_id');
$accountCurrency = (int)$repository->getMetaValue($account, 'currency_id');
$openingBalance = $account->getOpeningBalance();
$obCurrency = (int)$openingBalance->transaction_currency_id;
if (null === $defaultCurrency) {
throw new UnexpectedValueException('The default currency is NULL, and this is more or less impossible.');
}
// both 0? set to default currency:
if (0 === $accountCurrency && 0 === $obCurrency) {
AccountMeta::where('account_id', $account->id)->where('name', 'currency_id')->forceDelete();
@@ -317,19 +346,22 @@ class UpgradeDatabase extends Command
* Both source and destination must match the respective currency preference of the related asset account.
* So FF3 must verify all transactions.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function updateOtherCurrencies(): void
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$set = TransactionJournal
/** @var AccountRepositoryInterface $accountRepos */
$accountRepos = app(AccountRepositoryInterface::class);
$set = TransactionJournal
::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->whereIn('transaction_types.type', [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE])
->get(['transaction_journals.*']);
$set->each(
function (TransactionJournal $journal) use ($repository) {
function (TransactionJournal $journal) use ($repository, $accountRepos) {
// get the transaction with the asset account in it:
/** @var Transaction $transaction */
$transaction = $journal->transactions()
@@ -339,9 +371,13 @@ class UpgradeDatabase extends Command
if (null === $transaction) {
return;
}
$accountRepos->setUser($journal->user);
/** @var Account $account */
$account = $transaction->account;
$currency = $repository->find((int)$account->getMeta('currency_id'));
$account = $transaction->account;
$currency = $repository->findNull((int)$accountRepos->getMetaValue($account, 'currency_id'));
if (null === $currency) {
return;
}
$transactions = $journal->transactions()->get();
$transactions->each(
function (Transaction $transaction) use ($currency) {
@@ -377,7 +413,7 @@ class UpgradeDatabase extends Command
* Both source and destination must match the respective currency preference. So FF3 must verify ALL
* transactions.
*/
public function updateTransferCurrencies()
public function updateTransferCurrencies(): void
{
$set = TransactionJournal
::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
@@ -449,6 +485,7 @@ class UpgradeDatabase extends Command
*/
private function migrateNotes(): void
{
/** @noinspection PhpUndefinedMethodInspection */
$set = TransactionJournalMeta::whereName('notes')->get();
/** @var TransactionJournalMeta $meta */
foreach ($set as $meta) {
@@ -479,8 +516,15 @@ class UpgradeDatabase extends Command
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$currency = $repository->find((int)$transaction->account->getMeta('currency_id'));
$journal = $transaction->transactionJournal;
/** @var AccountRepositoryInterface $accountRepos */
$accountRepos = app(AccountRepositoryInterface::class);
$accountRepos->setUser($transaction->account->user);
$currency = $repository->findNull((int)$accountRepos->getMetaValue($transaction->account, 'currency_id'));
$journal = $transaction->transactionJournal;
if (null === $currency) {
return;
}
if (!((int)$currency->id === (int)$journal->transaction_currency_id)) {
$this->line(
@@ -549,11 +593,11 @@ class UpgradeDatabase extends Command
*
* The transaction that is sent to this function MUST be the source transaction (amount negative).
*
* Method is long and complex bit I'm taking it for granted.
* Method is long and complex but I'll allow it. https://imgur.com/gallery/dVDJiez
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
* @param Transaction $transaction
*/
@@ -561,7 +605,14 @@ class UpgradeDatabase extends Command
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$currency = $repository->findNull((int)$transaction->account->getMeta('currency_id'));
/** @var AccountRepositoryInterface $accountRepos */
$accountRepos = app(AccountRepositoryInterface::class);
/** @var JournalRepositoryInterface $journalRepos */
$journalRepos = app(JournalRepositoryInterface::class);
$accountRepos->setUser($transaction->account->user);
$journalRepos->setUser($transaction->account->user);
$currency = $repository->findNull((int)$accountRepos->getMetaValue($transaction->account, 'currency_id'));
if (null === $currency) {
Log::error(sprintf('Account #%d ("%s") must have currency preference but has none.', $transaction->account->id, $transaction->account->name));
@@ -597,7 +648,7 @@ class UpgradeDatabase extends Command
$journal = $transaction->transactionJournal;
/** @var Transaction $opposing */
$opposing = $journal->transactions()->where('amount', '>', 0)->where('identifier', $transaction->identifier)->first();
$opposingCurrency = $repository->findNull((int)$opposing->account->getMeta('currency_id'));
$opposingCurrency = $repository->findNull((int)$accountRepos->getMetaValue($opposing->account, 'currency_id'));
if (null === $opposingCurrency) {
Log::error(sprintf('Account #%d ("%s") must have currency preference but has none.', $opposing->account->id, $opposing->account->name));
@@ -653,7 +704,7 @@ class UpgradeDatabase extends Command
// when both are zero, try to grab it from journal:
if (null === $opposing->foreign_amount && null === $transaction->foreign_amount) {
$foreignAmount = $journal->getMeta('foreign_amount');
$foreignAmount = $journalRepos->getMetaField($journal, 'foreign_amount');
if (null === $foreignAmount) {
Log::debug(sprintf('Journal #%d has missing foreign currency data, forced to do 1:1 conversion :(.', $transaction->transaction_journal_id));
$transaction->foreign_amount = bcmul((string)$transaction->amount, '-1');

View File

@@ -1,5 +1,4 @@
<?php
/**
* UpgradeFireflyInstructions.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -28,6 +27,8 @@ use Illuminate\Console\Command;
/**
* Class UpgradeFireflyInstructions.
*
* @codeCoverageIgnore
*/
class UpgradeFireflyInstructions extends Command
{
@@ -47,14 +48,16 @@ class UpgradeFireflyInstructions extends Command
/**
* Execute the console command.
*/
public function handle()
public function handle(): int
{
if ('update' === $this->argument('task')) {
if ('update' === (string)$this->argument('task')) {
$this->updateInstructions();
}
if ('install' === $this->argument('task')) {
if ('install' === (string)$this->argument('task')) {
$this->installInstructions();
}
return 0;
}
/**
@@ -62,7 +65,7 @@ class UpgradeFireflyInstructions extends Command
*
* @param string $text
*/
private function boxed(string $text)
private function boxed(string $text): void
{
$parts = explode("\n", wordwrap($text));
foreach ($parts as $string) {
@@ -75,7 +78,7 @@ class UpgradeFireflyInstructions extends Command
*
* @param string $text
*/
private function boxedInfo(string $text)
private function boxedInfo(string $text): void
{
$parts = explode("\n", wordwrap($text));
foreach ($parts as $string) {
@@ -86,7 +89,7 @@ class UpgradeFireflyInstructions extends Command
/**
* Render instructions.
*/
private function installInstructions()
private function installInstructions(): void
{
/** @var string $version */
$version = config('firefly.version');
@@ -94,8 +97,7 @@ class UpgradeFireflyInstructions extends Command
$text = '';
foreach (array_keys($config) as $compare) {
// if string starts with:
$len = \strlen($compare);
if (substr($version, 0, $len) === $compare) {
if (0 === strpos($version, $compare)) {
$text = $config[$compare];
}
}
@@ -120,7 +122,7 @@ class UpgradeFireflyInstructions extends Command
/**
* Show a line.
*/
private function showLine()
private function showLine(): void
{
$line = '+';
for ($i = 0; $i < 78; ++$i) {
@@ -133,7 +135,7 @@ class UpgradeFireflyInstructions extends Command
/**
* Render upgrade instructions.
*/
private function updateInstructions()
private function updateInstructions(): void
{
/** @var string $version */
$version = config('firefly.version');
@@ -141,8 +143,7 @@ class UpgradeFireflyInstructions extends Command
$text = '';
foreach (array_keys($config) as $compare) {
// if string starts with:
$len = \strlen($compare);
if (substr($version, 0, $len) === $compare) {
if (0 === strpos($version, $compare)) {
$text = $config[$compare];
}
}

View File

@@ -1,5 +1,4 @@
<?php
/**
* UseEncryption.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -29,6 +28,7 @@ use Illuminate\Support\Str;
/**
* Class UseEncryption.
* @codeCoverageIgnore
*/
class UseEncryption extends Command
{
@@ -48,12 +48,12 @@ class UseEncryption extends Command
/**
* Execute the console command.
*/
public function handle()
public function handle(): int
{
if (config('firefly.encryption') === true) {
if (true === config('firefly.encryption')) {
$this->info('Firefly III configuration calls for encrypted data.');
}
if (config('firefly.encryption') === false) {
if (false === config('firefly.encryption')) {
$this->info('Firefly III configuration calls for unencrypted data.');
}
$this->handleObjects('Account', 'name', 'encrypted');
@@ -63,6 +63,8 @@ class UseEncryption extends Command
$this->handleObjects('Category', 'name', 'encrypted');
$this->handleObjects('PiggyBank', 'name', 'encrypted');
$this->handleObjects('TransactionJournal', 'description', 'encrypted');
return 0;
}
/**
@@ -72,18 +74,21 @@ class UseEncryption extends Command
* @param string $field
* @param string $indicator
*/
public function handleObjects(string $class, string $field, string $indicator)
public function handleObjects(string $class, string $field, string $indicator): void
{
$fqn = sprintf('FireflyIII\Models\%s', $class);
$encrypt = config('firefly.encryption') === true ? 0 : 1;
$set = $fqn::where($indicator, $encrypt)->get();
$encrypt = true === config('firefly.encryption') ? 0 : 1;
/** @noinspection PhpUndefinedMethodInspection */
$set = $fqn::where($indicator, $encrypt)->get();
foreach ($set as $entry) {
$newName = $entry->$field;
$entry->$field = $newName;
/** @noinspection PhpUndefinedMethodInspection */
$entry->save();
}
/** @noinspection PhpUndefinedMethodInspection */
$this->line(sprintf('Updated %d %s.', $set->count(), strtolower(Str::plural($class))));
}
}

View File

@@ -1,5 +1,4 @@
<?php
/**
* VerifiesAccessToken.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -26,12 +25,12 @@ namespace FireflyIII\Console\Commands;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use Log;
use Preferences;
/**
* Trait VerifiesAccessToken.
*
* Verifies user access token for sensitive commands.
* @codeCoverageIgnore
*/
trait VerifiesAccessToken
{
@@ -62,7 +61,7 @@ trait VerifiesAccessToken
return false;
}
$accessToken = Preferences::getForUser($user, 'access_token', null);
$accessToken = app('preferences')->getForUser($user, 'access_token', null);
if (null === $accessToken) {
Log::error(sprintf('User #%d has no access token, so cannot access command line options.', $userId));

View File

@@ -1,5 +1,4 @@
<?php
/**
* VerifyDatabase.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -20,6 +19,8 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection PhpDynamicAsStaticMethodCallInspection */
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
@@ -29,6 +30,7 @@ use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\LinkType;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
@@ -39,14 +41,16 @@ use FireflyIII\User;
use Illuminate\Console\Command;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Database\Eloquent\Builder;
use Preferences;
use Log;
use Schema;
use stdClass;
/**
* Class VerifyDatabase.
*
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @codeCoverageIgnore
*/
class VerifyDatabase extends Command
{
@@ -66,15 +70,15 @@ class VerifyDatabase extends Command
/**
* Execute the console command.
*/
public function handle()
public function handle(): int
{
// if table does not exist, return false
if (!Schema::hasTable('users')) {
return;
return 1;
}
$this->reportObject('budget');
$this->reportObject('category');
$this->reportEmptyBudgets();
$this->reportEmptyCategories();
$this->reportObject('tag');
$this->reportAccounts();
$this->reportBudgetLimits();
@@ -91,6 +95,8 @@ class VerifyDatabase extends Command
$this->fixDoubleAmounts();
$this->fixBadMeta();
$this->removeBills();
return 0;
}
/**
@@ -102,10 +108,10 @@ class VerifyDatabase extends Command
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
$pref = Preferences::getForUser($user, 'access_token', null);
$pref = app('preferences')->getForUser($user, 'access_token', null);
if (null === $pref) {
$token = $user->generateAccessToken();
Preferences::setForUser($user, 'access_token', $token);
app('preferences')->setForUser($user, 'access_token', $token);
$this->line(sprintf('Generated access token for user %s', $user->email));
++$count;
}
@@ -145,9 +151,10 @@ class VerifyDatabase extends Command
}
/**
* Fix the situation where the matching transactions
* of a journal somehow have non-matching categories
* or budgets
* Fix the situation where the matching transactions of a journal somehow have non-matching categories or budgets.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
private function fixBadMeta(): void
{
@@ -208,6 +215,12 @@ class VerifyDatabase extends Command
}
}
/**
* Makes sure amounts are stored correctly.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
private function fixDoubleAmounts(): void
{
$count = 0;
@@ -257,7 +270,7 @@ class VerifyDatabase extends Command
}
/**
*
* Removes bills from journals that should not have bills.
*/
private function removeBills(): void
{
@@ -305,7 +318,7 @@ class VerifyDatabase extends Command
/**
* Reports on accounts with no transactions.
*/
private function reportAccounts()
private function reportAccounts(): void
{
$set = Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
->leftJoin('users', 'accounts.user_id', '=', 'users.id')
@@ -378,6 +391,82 @@ class VerifyDatabase extends Command
}
}
/**
* Report on budgets with no transactions or journals.
*/
private function reportEmptyBudgets(): void
{
$set = Budget::leftJoin('budget_transaction_journal', 'budgets.id', '=', 'budget_transaction_journal.budget_id')
->leftJoin('users', 'budgets.user_id', '=', 'users.id')
->distinct()
->whereNull('budget_transaction_journal.budget_id')
->whereNull('budgets.deleted_at')
->get(['budgets.id', 'budgets.name', 'budgets.user_id', 'users.email']);
/** @var stdClass $entry */
foreach ($set as $entry) {
$objName = $entry->name;
try {
$objName = Crypt::decrypt($objName);
} catch (DecryptException $e) {
// it probably was not encrypted.
Log::debug(sprintf('Not a problem: %s', $e->getMessage()));
}
// also count the transactions:
$countTransactions = DB::table('budget_transaction')->where('budget_id', $entry->id)->count();
if (0 === $countTransactions) {
$line = sprintf(
'User #%d (%s) has budget #%d ("%s") which has no transactions.',
$entry->user_id,
$entry->email,
$entry->id,
$objName
);
$this->line($line);
}
}
}
/**
* Report on categories with no transactions or journals.
*/
private function reportEmptyCategories(): void
{
$set = Category::leftJoin('category_transaction_journal', 'categories.id', '=', 'category_transaction_journal.category_id')
->leftJoin('users', 'categories.user_id', '=', 'users.id')
->distinct()
->whereNull('category_transaction_journal.category_id')
->whereNull('categories.deleted_at')
->get(['categories.id', 'categories.name', 'categories.user_id', 'users.email']);
/** @var stdClass $entry */
foreach ($set as $entry) {
$objName = $entry->name;
try {
$objName = Crypt::decrypt($objName);
} catch (DecryptException $e) {
// it probably was not encrypted.
Log::debug(sprintf('Not a problem: %s', $e->getMessage()));
}
// also count the transactions:
$countTransactions = DB::table('category_transaction')->where('category_id', $entry->id)->count();
if (0 === $countTransactions) {
$line = sprintf(
'User #%d (%s) has category #%d ("%s") which has no transactions.',
$entry->user_id,
$entry->email,
$entry->id,
$objName
);
$this->line($line);
}
}
}
/**
* Report on journals with bad account types linked to them.
*/
@@ -483,12 +572,13 @@ class VerifyDatabase extends Command
$plural = str_plural($name);
$class = sprintf('FireflyIII\Models\%s', ucfirst($name));
$field = 'tag' === $name ? 'tag' : 'name';
$set = $class::leftJoin($name . '_transaction_journal', $plural . '.id', '=', $name . '_transaction_journal.' . $name . '_id')
->leftJoin('users', $plural . '.user_id', '=', 'users.id')
->distinct()
->whereNull($name . '_transaction_journal.' . $name . '_id')
->whereNull($plural . '.deleted_at')
->get([$plural . '.id', $plural . '.' . $field . ' as name', $plural . '.user_id', 'users.email']);
/** @noinspection PhpUndefinedMethodInspection */
$set = $class::leftJoin($name . '_transaction_journal', $plural . '.id', '=', $name . '_transaction_journal.' . $name . '_id')
->leftJoin('users', $plural . '.user_id', '=', 'users.id')
->distinct()
->whereNull($name . '_transaction_journal.' . $name . '_id')
->whereNull($plural . '.deleted_at')
->get([$plural . '.id', $plural . '.' . $field . ' as name', $plural . '.user_id', 'users.email']);
/** @var stdClass $entry */
foreach ($set as $entry) {
@@ -497,6 +587,7 @@ class VerifyDatabase extends Command
$objName = Crypt::decrypt($objName);
} catch (DecryptException $e) {
// it probably was not encrypted.
Log::debug(sprintf('Not a problem: %s', $e->getMessage()));
}
$line = sprintf(
@@ -524,7 +615,8 @@ class VerifyDatabase extends Command
$sum = (string)$user->transactions()->sum('amount');
if (0 !== bccomp($sum, '0')) {
$this->error('Error: Transactions for user #' . $user->id . ' (' . $user->email . ') are off by ' . $sum . '!');
} else {
}
if (0 === bccomp($sum, '0')) {
$this->info(sprintf('Amount integrity OK for user #%d', $user->id));
}
}
@@ -554,7 +646,7 @@ class VerifyDatabase extends Command
/**
* Report on transfers that have budgets.
*/
private function reportTransfersBudgets()
private function reportTransfersBudgets(): void
{
$set = TransactionJournal::distinct()
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')

View File

@@ -24,25 +24,16 @@ declare(strict_types=1);
namespace FireflyIII\Console;
use Carbon\Carbon;
use FireflyIII\Jobs\CreateRecurringTransactions;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Log;
/**
* File to make sure commands work.
* @codeCoverageIgnore
*/
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands
= [
];
/**
* Register the commands for the application.
*/
@@ -50,6 +41,7 @@ class Kernel extends ConsoleKernel
{
$this->load(__DIR__ . '/Commands');
/** @noinspection PhpIncludeInspection */
require base_path('routes/console.php');
}
@@ -60,6 +52,21 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule): void
{
$schedule->job(new CreateRecurringTransactions(new Carbon))->daily();
$schedule->call(
function () {
Log::error('Firefly III no longer users the Laravel scheduler to do cron jobs! Please read the instructions at https://firefly-iii.readthedocs.io/en/latest/');
echo "\n";
echo '------------';
echo "\n";
echo wordwrap('Firefly III no longer users the Laravel scheduler to do cron jobs! Please read the instructions here:');
echo "\n";
echo 'https://firefly-iii.readthedocs.io/en/latest/';
echo "\n\n";
echo 'Disable this cron job!';
echo "\n";
echo '------------';
echo "\n";
}
)->everyMinute();
}
}

View File

@@ -30,18 +30,15 @@ use Log;
/**
* Class AdminRequestedTestMessage.
* @codeCoverageIgnore
*/
class AdminRequestedTestMessage extends Event
{
use SerializesModels;
/**
* @var string
*/
/** @var string The users IP address */
public $ipAddress;
/**
* @var User
*/
/** @var User The user */
public $user;
/**

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Events;
/**
* Class Event.
* @codeCoverageIgnore
*/
abstract class Event
{

View File

@@ -29,18 +29,15 @@ use Illuminate\Queue\SerializesModels;
/**
* Class RegisteredUser.
* @codeCoverageIgnore
*/
class RegisteredUser extends Event
{
use SerializesModels;
/**
* @var string
*/
/** @var string The users IP address */
public $ipAddress;
/**
* @var User
*/
/** @var User The user */
public $user;
/**

View File

@@ -29,22 +29,17 @@ use Illuminate\Queue\SerializesModels;
/**
* Class RequestedNewPassword.
* @codeCoverageIgnore
*/
class RequestedNewPassword extends Event
{
use SerializesModels;
/**
* @var string
*/
/** @var string The users IP address */
public $ipAddress;
/**
* @var string
*/
/** @var string The token */
public $token;
/**
* @var User
*/
/** @var User The user */
public $user;
/**

View File

@@ -1,4 +1,24 @@
<?php
declare(strict_types=1);
/**
* RequestedReportOnJournals.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Events;
@@ -11,14 +31,16 @@ use Log;
/**
* Class RequestedReportOnJournals
*
* @codeCoverageIgnore
*/
class RequestedReportOnJournals
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/** @var Collection */
/** @var Collection The journals to report on. */
public $journals;
/** @var int */
/** @var int The ID of the user. */
public $userId;
/**

View File

@@ -30,14 +30,14 @@ use Illuminate\Queue\SerializesModels;
/**
* Class RequestedVersionCheckStatus
*
* @codeCoverageIgnore
*/
class RequestedVersionCheckStatus extends Event
{
use SerializesModels;
/**
* @var User
*/
/** @var User The user */
public $user;
/**

View File

@@ -28,16 +28,17 @@ use FireflyIII\Models\TransactionJournal;
use Illuminate\Queue\SerializesModels;
/**
* @codeCoverageIgnore
* Class StoredTransactionJournal.
*
* @codeCoverageIgnore
*/
class StoredTransactionJournal extends Event
{
use SerializesModels;
/** @var TransactionJournal */
/** @var TransactionJournal The journal that was stored. */
public $journal;
/** @var int */
/** @var int The piggy bank ID. */
public $piggyBankId;
/**

View File

@@ -37,7 +37,7 @@ class UpdatedTransactionJournal extends Event
{
use SerializesModels;
/** @var TransactionJournal */
/** @var TransactionJournal The journal. */
public $journal;
/**

View File

@@ -29,18 +29,20 @@ use Illuminate\Queue\SerializesModels;
/**
* Class UserChangedEmail.
*
* @codeCoverageIgnore
*/
class UserChangedEmail extends Event
{
use SerializesModels;
/** @var string */
/** @var string The user's IP address */
public $ipAddress;
/** @var string */
/** @var string The user's new email address */
public $newEmail;
/** @var string */
/** @var string The user's old email address */
public $oldEmail;
/** @var User */
/** @var User The user itself */
public $user;
/**

View File

@@ -20,6 +20,8 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
declare(strict_types=1);
namespace FireflyIII\Exceptions;
@@ -29,46 +31,31 @@ use Exception;
use FireflyIII\Jobs\MailError;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Validation\ValidationException;
use Illuminate\Validation\ValidationException as LaravelValidationException;
use League\OAuth2\Server\Exception\OAuthServerException;
use Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class Handler
* @codeCoverageIgnore
*/
class Handler extends ExceptionHandler
{
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var array
*/
protected $dontFlash
= [
'password',
'password_confirmation',
];
/**
* A list of the exception types that are not reported.
*
* @var array
*/
protected $dontReport
= [
];
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @param Request $request
* @param Exception $exception
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
* @return \Illuminate\Http\Response
* @return mixed
*/
public function render($request, Exception $exception)
{
if ($exception instanceof ValidationException && $request->expectsJson()) {
if ($exception instanceof LaravelValidationException && $request->expectsJson()) {
// ignore it: controller will handle it.
return parent::render($request, $exception);
}
@@ -130,18 +117,10 @@ class Handler extends ExceptionHandler
{
$doMailError = env('SEND_ERROR_MESSAGE', true);
if (
// if the user wants us to mail:
$doMailError === true
&& (
// and if is one of these error instances
$exception instanceof FireflyException
|| $exception instanceof ErrorException
|| $exception instanceof OAuthServerException
)
) {
// then, send email
// if the user wants us to mail:
if (true === $doMailError
// and if is one of these error instances
&& ($exception instanceof FireflyException || $exception instanceof ErrorException || $exception instanceof OAuthServerException)) {
$userData = [
'id' => 0,
'email' => 'unknown@example.com',

View File

@@ -1,5 +1,4 @@
<?php
/**
* AttachmentCollector.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -35,18 +34,21 @@ use Storage;
/**
* Class AttachmentCollector.
*
* @deprecated
* @codeCoverageIgnore
*/
class AttachmentCollector extends BasicCollector implements CollectorInterface
{
/** @var Carbon */
/** @var Carbon The end date of the range. */
private $end;
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
/** @var \Illuminate\Contracts\Filesystem\Filesystem File system */
private $exportDisk;
/** @var AttachmentRepositoryInterface */
/** @var AttachmentRepositoryInterface Attachment repository */
private $repository;
/** @var Carbon */
/** @var Carbon Start date of range */
private $start;
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
/** @var \Illuminate\Contracts\Filesystem\Filesystem Disk with uploads on it */
private $uploadDisk;
/**
@@ -64,6 +66,8 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
}
/**
* Run the routine.
*
* @return bool
*/
public function run(): bool
@@ -80,6 +84,8 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
}
/**
* Set the start and end date.
*
* @param Carbon $start
* @param Carbon $end
*/
@@ -89,7 +95,10 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
$this->end = $end;
}
/** @noinspection MultipleReturnStatementsInspection */
/**
* Export attachments.
*
* @param Attachment $attachment
*
* @return bool
@@ -107,7 +116,7 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
return false;
}
}
if ($decrypted === false) {
if (false === $decrypted) {
return false;
}
$exportFile = $this->exportFileName($attachment);
@@ -130,6 +139,8 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
}
/**
* Get the attachments.
*
* @return Collection
*/
private function getAttachments(): Collection

View File

@@ -30,14 +30,17 @@ use Illuminate\Support\Collection;
/**
* Class BasicCollector.
*
* @codeCoverageIgnore
* @deprecated
*/
class BasicCollector
{
/** @var ExportJob */
/** @var ExportJob The job to export. */
protected $job;
/** @var User */
/** @var User The user */
protected $user;
/** @var Collection */
/** @var Collection All the entries. */
private $entries;
/**
@@ -49,6 +52,8 @@ class BasicCollector
}
/**
* Get all entries.
*
* @return Collection
*/
public function getEntries(): Collection
@@ -57,26 +62,32 @@ class BasicCollector
}
/**
* Set entries.
*
* @param Collection $entries
*/
public function setEntries(Collection $entries)
public function setEntries(Collection $entries): void
{
$this->entries = $entries;
}
/**
* Set export job.
*
* @param ExportJob $job
*/
public function setJob(ExportJob $job)
public function setJob(ExportJob $job): void
{
$this->job = $job;
$this->user = $job->user;
}
/**
* Set user.
*
* @param User $user
*/
public function setUser(User $user)
public function setUser(User $user): void
{
$this->user = $user;
}

View File

@@ -29,25 +29,36 @@ use Illuminate\Support\Collection;
/**
* Interface CollectorInterface.
*
* @codeCoverageIgnore
* @deprecated
*/
interface CollectorInterface
{
/**
* Get entries.
*
* @return Collection
*/
public function getEntries(): Collection;
/**
* Run the collector.
*
* @return bool
*/
public function run(): bool;
/**
* Set entries.
*
* @param Collection $entries
*/
public function setEntries(Collection $entries);
/**
* Set export job.
*
* @param ExportJob $job
*
* @return mixed

View File

@@ -1,5 +1,4 @@
<?php
/**
* UploadCollector.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -32,6 +31,9 @@ use Storage;
/**
* Class UploadCollector.
*
* @codeCoverageIgnore
* @deprecated
*/
class UploadCollector extends BasicCollector implements CollectorInterface
{
@@ -84,7 +86,10 @@ class UploadCollector extends BasicCollector implements CollectorInterface
return true;
}
/** @noinspection MultipleReturnStatementsInspection */
/**
* Process new file uploads.
*
* @param string $key
*
* @return bool

View File

@@ -43,140 +43,71 @@ use FireflyIII\Models\Transaction;
*
* @SuppressWarnings(PHPMD.LongVariable)
* @SuppressWarnings(PHPMD.TooManyFields)
*
* @codeCoverageIgnore
* @deprecated
*/
final class Entry
{
// @formatter:off
/**
* @var int
*/
/** @var int ID of the journal */
public $journal_id;
/**
* @var int
*/
/** @var int ID of the transaction */
public $transaction_id = 0;
/**
* @var string
*/
/** @var string The date. */
public $date;
/**
* @var string
*/
/** @var string The description */
public $description;
/**
* @var string
*/
/** @var string The currency code. */
public $currency_code;
/**
* @var string
*/
/** @var string The amount. */
public $amount;
/**
* @var string
*/
/** @var string The foreign currency code */
public $foreign_currency_code = '';
/**
* @var string
*/
/** @var string Foreign amount */
public $foreign_amount = '0';
/**
* @var string
*/
/** @var string Transaction type */
public $transaction_type;
/**
* @var string
*/
/** @var string Asset account ID */
public $asset_account_id;
/**
* @var string
*/
/** @var string Asset account name */
public $asset_account_name;
/**
* @var string
*/
/** @var string Asset account IBAN */
public $asset_account_iban;
/**
* @var string
*/
/** @var string Asset account BIC */
public $asset_account_bic;
/**
* @var string
*/
/** @var string Asset account number */
public $asset_account_number;
/**
* @var string
*/
/** @var string Asset account currency code */
public $asset_currency_code;
/**
* @var string
*/
/** @var string Opposing account ID */
public $opposing_account_id;
/**
* @var string
*/
/** @var string Opposing account name */
public $opposing_account_name;
/**
* @var string
*/
/** @var string Opposing account IBAN */
public $opposing_account_iban;
/**
* @var string
*/
/** @var string Opposing account BIC */
public $opposing_account_bic;
/**
* @var string
*/
/** @var string Opposing account number */
public $opposing_account_number;
/**
* @var string
*/
/** @var string Opposing account code */
public $opposing_currency_code;
/**
* @var string
*/
/** @var string Budget ID */
public $budget_id;
/**
* @var string
*/
/** @var string Budget name */
public $budget_name;
/**
* @var string
*/
/** @var string Category ID */
public $category_id;
/**
* @var string
*/
/** @var string Category name */
public $category_name;
/**
* @var string
*/
/** @var string Bill ID */
public $bill_id;
/**
* @var string
*/
/** @var string Bill name */
public $bill_name;
/**
* @var string
*/
/** @var string Notes */
public $notes;
/**
* @var string
*/
/** @var string Tags */
public $tags;
// @formatter:on
/**
* Entry constructor.
*/

View File

@@ -1,5 +1,4 @@
<?php
/**
* ExpandedProcessor.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -20,6 +19,8 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection PhpDynamicAsStaticMethodCallInspection */
declare(strict_types=1);
namespace FireflyIII\Export;
@@ -30,7 +31,8 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Export\Collector\AttachmentCollector;
use FireflyIII\Export\Collector\UploadCollector;
use FireflyIII\Export\Entry\Entry;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Export\Exporter\ExporterInterface;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\ExportJob;
@@ -47,26 +49,29 @@ use ZipArchive;
* Class ExpandedProcessor.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects) // its doing a lot.
*
* @codeCoverageIgnore
* @deprecated
*/
class ExpandedProcessor implements ProcessorInterface
{
/** @var Collection */
/** @var Collection All accounts */
public $accounts;
/** @var string */
/** @var string The export format */
public $exportFormat;
/** @var bool */
/** @var bool Should include attachments */
public $includeAttachments;
/** @var bool */
/** @var bool Should include old uploads */
public $includeOldUploads;
/** @var ExportJob */
/** @var ExportJob The export job itself */
public $job;
/** @var array */
/** @var array The settings */
public $settings;
/** @var Collection */
/** @var Collection The entries to export. */
private $exportEntries;
/** @var Collection */
/** @var Collection The files to export */
private $files;
/** @var Collection */
/** @var Collection The journals. */
private $journals;
/**
@@ -80,6 +85,8 @@ class ExpandedProcessor implements ProcessorInterface
}
/**
* Collect all attachments
*
* @return bool
*/
public function collectAttachments(): bool
@@ -103,13 +110,13 @@ class ExpandedProcessor implements ProcessorInterface
public function collectJournals(): bool
{
// use journal collector thing.
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
/** @var TransactionCollectorInterface $collector */
$collector = app(TransactionCollectorInterface::class);
$collector->setUser($this->job->user);
$collector->setAccounts($this->accounts)->setRange($this->settings['startDate'], $this->settings['endDate'])
->withOpposingAccount()->withBudgetInformation()->withCategoryInformation()
->removeFilter(InternalTransferFilter::class);
$transactions = $collector->getJournals();
$transactions = $collector->getTransactions();
// get some more meta data for each entry:
$ids = $transactions->pluck('journal_id')->toArray();
$assetIds = $transactions->pluck('account_id')->toArray();
@@ -143,6 +150,8 @@ class ExpandedProcessor implements ProcessorInterface
}
/**
* Get old oploads.
*
* @return bool
*/
public function collectOldUploads(): bool
@@ -158,6 +167,8 @@ class ExpandedProcessor implements ProcessorInterface
}
/**
* Convert journals to export objects.
*
* @return bool
*/
public function convertJournals(): bool
@@ -173,6 +184,8 @@ class ExpandedProcessor implements ProcessorInterface
}
/**
* Create a ZIP file.
*
* @return bool
*
* @throws FireflyException
@@ -204,12 +217,15 @@ class ExpandedProcessor implements ProcessorInterface
}
/**
* Export the journals.
*
* @return bool
*/
public function exportJournals(): bool
{
$exporterClass = config('firefly.export_formats.' . $this->exportFormat);
$exporter = app($exporterClass);
/** @var ExporterInterface $exporter */
$exporter = app($exporterClass);
$exporter->setJob($this->job);
$exporter->setEntries($this->exportEntries);
$exporter->run();
@@ -219,6 +235,8 @@ class ExpandedProcessor implements ProcessorInterface
}
/**
* Get files.
*
* @return Collection
*/
public function getFiles(): Collection
@@ -231,7 +249,7 @@ class ExpandedProcessor implements ProcessorInterface
*
* @param array $settings
*/
public function setSettings(array $settings)
public function setSettings(array $settings): void
{
// save settings
$this->settings = $settings;
@@ -243,9 +261,9 @@ class ExpandedProcessor implements ProcessorInterface
}
/**
*
* Delete files.
*/
private function deleteFiles()
private function deleteFiles(): void
{
$disk = Storage::disk('export');
foreach ($this->getFiles() as $file) {
@@ -254,6 +272,8 @@ class ExpandedProcessor implements ProcessorInterface
}
/**
* Get currencies.
*
* @param array $array
*
* @return array

View File

@@ -29,12 +29,15 @@ use Illuminate\Support\Collection;
/**
* Class BasicExporter.
*
* @codeCoverageIgnore
* @deprecated
*/
class BasicExporter
{
/** @var ExportJob */
/** @var ExportJob The export job */
protected $job;
/** @var Collection */
/** @var Collection The entries */
private $entries;
/**
@@ -46,6 +49,8 @@ class BasicExporter
}
/**
* Get all entries.
*
* @return Collection
*/
public function getEntries(): Collection
@@ -54,17 +59,21 @@ class BasicExporter
}
/**
* Set all entries.
*
* @param Collection $entries
*/
public function setEntries(Collection $entries)
public function setEntries(Collection $entries): void
{
$this->entries = $entries;
}
/**
* Set the job.
*
* @param ExportJob $job
*/
public function setJob(ExportJob $job)
public function setJob(ExportJob $job): void
{
$this->job = $job;
}

View File

@@ -30,13 +30,18 @@ use Storage;
/**
* Class CsvExporter.
*
* @codeCoverageIgnore
* @deprecated
*/
class CsvExporter extends BasicExporter implements ExporterInterface
{
/** @var string */
/** @var string Filename */
private $fileName;
/**
* Get file name.
*
* @return string
*/
public function getFileName(): string
@@ -45,6 +50,8 @@ class CsvExporter extends BasicExporter implements ExporterInterface
}
/**
* Run collector.
*
* @return bool
*
*/
@@ -83,6 +90,9 @@ class CsvExporter extends BasicExporter implements ExporterInterface
return true;
}
/**
* Make a temp file.
*/
private function tempFile()
{
$this->fileName = $this->job->key . '-records.csv';

View File

@@ -29,30 +29,43 @@ use Illuminate\Support\Collection;
/**
* Interface ExporterInterface.
*
* @codeCoverageIgnore
* @deprecated
*/
interface ExporterInterface
{
/**
* Get entries.
*
* @return Collection
*/
public function getEntries(): Collection;
/**
* Get file name.
*
* @return string
*/
public function getFileName(): string;
/**
* Run exporter.
*
* @return bool
*/
public function run(): bool;
/**
* Set entries.
*
* @param Collection $entries
*/
public function setEntries(Collection $entries);
/**
* Set job.
*
* @param ExportJob $job
*/
public function setJob(ExportJob $job);

View File

@@ -28,6 +28,9 @@ use Illuminate\Support\Collection;
/**
* Interface ProcessorInterface.
*
* @codeCoverageIgnore
* @deprecated
*/
interface ProcessorInterface
{
@@ -37,41 +40,57 @@ interface ProcessorInterface
public function __construct();
/**
* Collect all attachments.
*
* @return bool
*/
public function collectAttachments(): bool;
/**
* Collect all journals.
*
* @return bool
*/
public function collectJournals(): bool;
/**
* Collect old uploads.
*
* @return bool
*/
public function collectOldUploads(): bool;
/**
* Convert all journals.
*
* @return bool
*/
public function convertJournals(): bool;
/**
* Create a zip file.
*
* @return bool
*/
public function createZipFile(): bool;
/**
* Export journals.
*
* @return bool
*/
public function exportJournals(): bool;
/**
* Get all files.
*
* @return Collection
*/
public function getFiles(): Collection;
/**
* Set the settings.
*
* @param array $settings
*/
public function setSettings(array $settings);

View File

@@ -20,14 +20,19 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection PhpDynamicAsStaticMethodCallInspection */
/** @noinspection PhpUndefinedMethodInspection */
declare(strict_types=1);
namespace FireflyIII\Factory;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Services\Internal\Support\AccountServiceTrait;
use FireflyIII\User;
use Log;
/**
* Factory to create or return accounts.
@@ -44,56 +49,64 @@ class AccountFactory
* @param array $data
*
* @return Account
* @throws FireflyException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function create(array $data): Account
{
$type = $this->getAccountType($data['account_type_id'], $data['accountType']);
$type = $this->getAccountType($data['account_type_id'], $data['accountType']);
if (null === $type) {
throw new FireflyException(
sprintf('AccountFactory::create() was unable to find account type #%d ("%s").', $data['account_type_id'], $data['accountType'])
);
}
$data['iban'] = $this->filterIban($data['iban']);
// account may exist already:
$existingAccount = $this->find($data['name'], $type->type);
if (null !== $existingAccount) {
return $existingAccount;
$return = $this->find($data['name'], $type->type);
if (null === $return) {
// create it:
$databaseData
= [
'user_id' => $this->user->id,
'account_type_id' => $type->id,
'name' => $data['name'],
'virtual_balance' => $data['virtualBalance'] ?? '0',
'active' => true === $data['active'],
'iban' => $data['iban'],
];
// remove virtual balance when not an asset account or a liability
$canHaveVirtual = [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD];
if (!\in_array($type->type, $canHaveVirtual, true)) {
$databaseData['virtual_balance'] = '0';
}
// fix virtual balance when it's empty
if ('' === $databaseData['virtual_balance']) {
$databaseData['virtual_balance'] = '0';
}
$return = Account::create($databaseData);
$this->updateMetaData($return, $data);
if (\in_array($type->type, $canHaveVirtual, true)) {
if ($this->validIBData($data)) {
$this->updateIB($return, $data);
}
if (!$this->validIBData($data)) {
$this->deleteIB($return);
}
}
$this->updateNote($return, $data['notes'] ?? '');
}
// create it:
$databaseData
= [
'user_id' => $this->user->id,
'account_type_id' => $type->id,
'name' => $data['name'],
'virtual_balance' => $data['virtualBalance'] ?? '0',
'active' => true === $data['active'],
'iban' => $data['iban'],
];
// remove virtual balance when not an asset account:
if ($type->type !== AccountType::ASSET) {
$databaseData['virtual_balance'] = '0';
}
// fix virtual balance when it's empty
if ($databaseData['virtual_balance'] === '') {
$databaseData['virtual_balance'] = '0';
}
$newAccount = Account::create($databaseData);
$this->updateMetaData($newAccount, $data);
if ($this->validIBData($data) && $type->type === AccountType::ASSET) {
$this->updateIB($newAccount, $data);
}
if (!$this->validIBData($data) && $type->type === AccountType::ASSET) {
$this->deleteIB($newAccount);
}
// update note:
if (isset($data['notes'])) {
$this->updateNote($newAccount, $data['notes']);
}
return $newAccount;
return $return;
}
/**
@@ -106,46 +119,53 @@ class AccountFactory
{
$type = AccountType::whereType($accountType)->first();
$accounts = $this->user->accounts()->where('account_type_id', $type->id)->get(['accounts.*']);
$return = null;
/** @var Account $object */
foreach ($accounts as $object) {
if ($object->name === $accountName) {
return $object;
$return = $object;
break;
}
}
return null;
return $return;
}
/**
*
* @param string $accountName
* @param string $accountType
*
* @return Account
* @throws FireflyException
*/
public function findOrCreate(string $accountName, string $accountType): Account
{
$type = AccountType::whereType($accountType)->first();
$accounts = $this->user->accounts()->where('account_type_id', $type->id)->get(['accounts.*']);
$return = null;
/** @var Account $object */
foreach ($accounts as $object) {
if ($object->name === $accountName) {
return $object;
$return = $object;
break;
}
}
if (null === $return) {
$return = $this->create(
[
'user_id' => $this->user->id,
'name' => $accountName,
'account_type_id' => $type->id,
'accountType' => null,
'virtualBalance' => '0',
'iban' => null,
'active' => true,
]
);
}
return $this->create(
[
'user_id' => $this->user->id,
'name' => $accountName,
'account_type_id' => $type->id,
'accountType' => null,
'virtualBalance' => '0',
'iban' => null,
'active' => true,
]
);
return $return;
}
/**
@@ -161,18 +181,27 @@ class AccountFactory
* @param null|string $accountType
*
* @return AccountType|null
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function getAccountType(?int $accountTypeId, ?string $accountType): ?AccountType
{
$accountTypeId = (int)$accountTypeId;
$result = null;
if ($accountTypeId > 0) {
return AccountType::find($accountTypeId);
$result = AccountType::find($accountTypeId);
}
$type = config('firefly.accountTypeByIdentifier.' . (string)$accountType);
$result = AccountType::whereType($type)->first();
if (null === $result && null !== $accountType) {
// try as full name:
$result = AccountType::whereType($accountType)->first();
if (null === $result) {
Log::debug(sprintf('No account type found by ID, continue search for "%s".', $accountType));
/** @var array $types */
$types = config('firefly.accountTypeByIdentifier.' . $accountType) ?? [];
if (\count($types) > 0) {
Log::debug(sprintf('%d accounts in list from config', \count($types)), $types);
$result = AccountType::whereIn('type', $types)->first();
}
if (null === $result && null !== $accountType) {
// try as full name:
$result = AccountType::whereType($accountType)->first();
}
}
return $result;

View File

@@ -24,13 +24,17 @@ declare(strict_types=1);
namespace FireflyIII\Factory;
use Exception;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use Log;
/**
* Class AccountMetaFactory
*/
class AccountMetaFactory
{
/**
* @param array $data
*
@@ -41,4 +45,46 @@ class AccountMetaFactory
return AccountMeta::create($data);
}
/**
* Create update or delete meta data.
*
* @param Account $account
* @param string $field
* @param string $value
*
* @return AccountMeta|null
*/
public function crud(Account $account, string $field, string $value): ?AccountMeta
{
/** @var AccountMeta $entry */
$entry = $account->accountMeta()->where('name', $field)->first();
// must not be an empty string:
if ('' !== $value) {
// if $data has field and $entry is null, create new one:
if (null === $entry) {
Log::debug(sprintf('Created meta-field "%s":"%s" for account #%d ("%s") ', $field, $value, $account->id, $account->name));
return $this->create(['account_id' => $account->id, 'name' => $field, 'data' => $value]);
}
// if $data has field and $entry is not null, update $entry:
if (null !== $entry) {
$entry->data = $value;
$entry->save();
Log::debug(sprintf('Updated meta-field "%s":"%s" for #%d ("%s") ', $field, $value, $account->id, $account->name));
}
}
if ('' === $value && null !== $entry) {
try {
$entry->delete();
} catch (Exception $e) { // @codeCoverageIgnore
Log::debug(sprintf('Could not delete entry: %s', $e->getMessage())); // @codeCoverageIgnore
}
return null;
}
return $entry;
}
}

View File

@@ -76,4 +76,4 @@ class AttachmentFactory
$this->user = $user;
}
}
}

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Factory;
use FireflyIII\Models\Bill;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Services\Internal\Support\BillServiceTrait;
use FireflyIII\User;
use Illuminate\Support\Collection;
@@ -46,6 +47,10 @@ class BillFactory
*/
public function create(array $data): ?Bill
{
/** @var TransactionCurrencyFactory $factory */
$factory = app(TransactionCurrencyFactory::class);
/** @var TransactionCurrency $currency */
$currency = $factory->find((int)$data['currency_id'], (string)$data['currency_code']);
/** @var Bill $bill */
$bill = Bill::create(
[
@@ -53,7 +58,7 @@ class BillFactory
'match' => 'MIGRATED_TO_RULES',
'amount_min' => $data['amount_min'],
'user_id' => $this->user->id,
'transaction_currency_id' => $data['transaction_currency_id'],
'transaction_currency_id' => $currency->id,
'amount_max' => $data['amount_max'],
'date' => $data['date'],
'repeat_freq' => $data['repeat_freq'],
@@ -81,25 +86,19 @@ class BillFactory
{
$billId = (int)$billId;
$billName = (string)$billName;
$bill = null;
// first find by ID:
if ($billId > 0) {
/** @var Bill $bill */
$bill = $this->user->bills()->find($billId);
if (null !== $bill) {
return $bill;
}
}
// then find by name:
if (\strlen($billName) > 0) {
if (null === $bill && \strlen($billName) > 0) {
$bill = $this->findByName($billName);
if (null !== $bill) {
return $bill;
}
}
return null;
return $bill;
}
@@ -112,22 +111,24 @@ class BillFactory
{
/** @var Collection $collection */
$collection = $this->user->bills()->get();
$return = null;
/** @var Bill $bill */
foreach ($collection as $bill) {
Log::debug(sprintf('"%s" vs. "%s"', $bill->name, $name));
if ($bill->name === $name) {
return $bill;
$return = $bill;
break;
}
}
Log::debug(sprintf('Bill::Find by name returns NULL based on "%s"', $name));
Log::debug(sprintf('Bill::find("%s") by name returns null? %s', $name, var_export($return, true)));
return null;
return $return;
}
/**
* @param User $user
*/
public function setUser(User $user)
public function setUser(User $user): void
{
$this->user = $user;
}

View File

@@ -1,5 +1,4 @@
<?php
/**
* BudgetFactory.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -19,7 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
declare(strict_types=1);
@@ -30,7 +29,7 @@ use FireflyIII\User;
use Illuminate\Support\Collection;
/**
* Class BudgetFactory
* Class BudgetFactory.
*/
class BudgetFactory
{
@@ -43,13 +42,14 @@ class BudgetFactory
* @param null|string $budgetName
*
* @return Budget|null
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function find(?int $budgetId, ?string $budgetName): ?Budget
{
$budgetId = (int)$budgetId;
$budgetName = (string)$budgetName;
if (\strlen($budgetName) === 0 && $budgetId === 0) {
if (0 === $budgetId && '' === $budgetName) {
return null;
}
@@ -62,7 +62,7 @@ class BudgetFactory
}
}
if (\strlen($budgetName) > 0) {
if ('' !== $budgetName) {
$budget = $this->findByName($budgetName);
if (null !== $budget) {
return $budget;
@@ -94,7 +94,7 @@ class BudgetFactory
/**
* @param User $user
*/
public function setUser(User $user)
public function setUser(User $user): void
{
$this->user = $user;
}

View File

@@ -1,5 +1,4 @@
<?php
/**
* CategoryFactory.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -19,7 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
declare(strict_types=1);
namespace FireflyIII\Factory;
@@ -64,6 +63,7 @@ class CategoryFactory
* @param null|string $categoryName
*
* @return Category|null
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function findOrCreate(?int $categoryId, ?string $categoryName): ?Category
{
@@ -72,7 +72,7 @@ class CategoryFactory
Log::debug(sprintf('Going to find category with ID %d and name "%s"', $categoryId, $categoryName));
if ('' === $categoryName && $categoryId === 0) {
if ('' === $categoryName && 0 === $categoryId) {
return null;
}
// first by ID:
@@ -104,7 +104,7 @@ class CategoryFactory
/**
* @param User $user
*/
public function setUser(User $user)
public function setUser(User $user): void
{
$this->user = $user;
}

View File

@@ -1,5 +1,4 @@
<?php
/**
* PiggyBankEventFactory.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -19,7 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
declare(strict_types=1);
namespace FireflyIII\Factory;
@@ -43,6 +42,7 @@ class PiggyBankEventFactory
* @param PiggyBank|null $piggyBank
*
* @return PiggyBankEvent|null
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function create(TransactionJournal $journal, ?PiggyBank $piggyBank): ?PiggyBankEvent
{
@@ -51,7 +51,6 @@ class PiggyBankEventFactory
return null;
}
// is a transfer?
if (!(TransactionType::TRANSFER === $journal->transactionType->type)) {
Log::info(sprintf('Will not connect %s #%d to a piggy bank.', $journal->transactionType->type, $journal->id));
@@ -62,7 +61,6 @@ class PiggyBankEventFactory
$piggyRepos = app(PiggyBankRepositoryInterface::class);
$piggyRepos->setUser($journal->user);
// repetition exists?
$repetition = $piggyRepos->getRepetition($piggyBank);
if (null === $repetition) {
Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d')));
@@ -70,7 +68,6 @@ class PiggyBankEventFactory
return null;
}
// get the amount
$amount = $piggyRepos->getExactAmount($piggyBank, $repetition, $journal);
if (0 === bccomp($amount, '0')) {
Log::debug('Amount is zero, will not create event.');
@@ -78,10 +75,8 @@ class PiggyBankEventFactory
return null;
}
// update amount
$piggyRepos->addAmountToRepetition($repetition, $amount);
$event = $piggyRepos->createEventWithJournal($piggyBank, $amount, $journal);
Log::debug(sprintf('Created piggy bank event #%d', $event->id));
return $event;

View File

@@ -1,5 +1,4 @@
<?php
/**
* PiggyBankFactory.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -19,7 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
declare(strict_types=1);
namespace FireflyIII\Factory;
@@ -41,12 +40,13 @@ class PiggyBankFactory
* @param null|string $piggyBankName
*
* @return PiggyBank|null
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function find(?int $piggyBankId, ?string $piggyBankName): ?PiggyBank
{
$piggyBankId = (int)$piggyBankId;
$piggyBankName = (string)$piggyBankName;
if (\strlen($piggyBankName) === 0 && $piggyBankId === 0) {
if ('' === $piggyBankName && 0 === $piggyBankId) {
return null;
}
// first find by ID:
@@ -92,7 +92,7 @@ class PiggyBankFactory
/**
* @param User $user
*/
public function setUser(User $user)
public function setUser(User $user): void
{
$this->user = $user;

View File

@@ -18,12 +18,14 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
declare(strict_types=1);
namespace FireflyIII\Factory;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Recurrence;
use FireflyIII\Services\Internal\Support\RecurringTransactionTrait;
@@ -56,6 +58,9 @@ class RecurrenceFactory
return null;
}
/** @var Carbon $firstDate */
$firstDate = $data['recurrence']['first_date'];
$repetitions = (int)$data['recurrence']['repetitions'];
$recurrence = new Recurrence(
[
@@ -63,7 +68,7 @@ class RecurrenceFactory
'transaction_type_id' => $type->id,
'title' => $data['recurrence']['title'],
'description' => $data['recurrence']['description'],
'first_date' => $data['recurrence']['first_date']->format('Y-m-d'),
'first_date' => $firstDate->format('Y-m-d'),
'repeat_until' => $repetitions > 0 ? null : $data['recurrence']['repeat_until'],
'latest_date' => null,
'repetitions' => $data['recurrence']['repetitions'],
@@ -88,4 +93,4 @@ class RecurrenceFactory
$this->user = $user;
}
}
}

View File

@@ -1,5 +1,4 @@
<?php
/**
* TagFactory.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
@@ -19,6 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
declare(strict_types=1);

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